Author Topic: Calling PInvoke method in a form override.  (Read 4077 times)

0 Members and 1 Guest are viewing this topic.

BillZndl

  • Guest
Calling PInvoke method in a form override.
« on: August 22, 2012, 10:58:45 AM »
VS2010exp, AutoCAD 2012, Win7

Im my quest to come up with a fix for my openfile dialog,
I am trying to use a pinvoke method that accesses/sets the list view of the win OpenFileDialog control that I have in my form.
So what I accomplish is to set the selected file name in the list so it is the "selected item".
The code at the bottom is supposed to set the view to "Thumbnails" but so far, no joy.

The comment in the method code instructs to:
Quote
/// Hash to be called from the overriden WndProc in the parent window of the dialog

This is where I could use some help.
My attempt is not working, everything compiles fine but the open file dialog is not affected upon displaying it.
I am compiling to an AutoCAD net loaded .dll.

Code: [Select]
public partial class OpenDWGdialog : Form
    {
        public OpenDWGdialog()
        {
            InitializeComponent();
        }
        [STAThread]
        static void Main(string[] args)
        {
            Application.Run(new OpenDWGdialog());
        }

        protected override void WndProc(ref Message m)  //<< this is what I think I am supposed to do.
        {
            // Letting the Form take care off all messages.
            base.WndProc(ref m);
            FileDialogExtender.FileDialogExtender flde = new FileDialogExtender.FileDialogExtender(FileDialogExtender.FileDialogExtender.DialogViewTypes.Thumbnails, true);
            flde.WndProc(ref m);
           
        }

This is the dialog extension I'm using.


Code: [Select]
//
// This source file was provided by Robert Rohde via http://www.thecodeproject.com/cs/miscctrl/FileDialogExtender.asp
//

    using System;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
   
    namespace FileDialogExtender
    {
        public class FileDialogExtender
        {
            #region Enum DialogViewTypes
   
           /// <summary>
           /// Ansichtentypen der Listenanzeige von Dateidialogen
           /// </summary>
           public enum DialogViewTypes
           {
               /// <summary>
               /// Symbole
               /// </summary>
               Icons = 0x7029,
               /// <summary>
               /// Liste
               /// </summary>
               List  = 0x702b,
               /// <summary>
               /// Details
               /// </summary>
               Details= 0x702c,
               /// <summary>
               /// Minitauransicht
               /// </summary>
               Thumbnails= 0x702d,
               /// <summary>
               /// Kacheln
               /// </summary>
               Tiles = 0x702e,
           }
   
           #endregion
   
           #region Fields
   
           private const uint WM_COMMAND = 0x0111;
           private uint _lastDialogHandle = 0;
           private DialogViewTypes _viewType;
           private bool _enabled;
   
           #endregion
   
           #region DllImports
   
           [DllImport("user32.dll", EntryPoint="SendMessageA", CallingConvention=CallingConvention.StdCall,CharSet=CharSet.Ansi)]
           private static extern uint SendMessage(uint Hdc, uint Msg_Const, uint wParam, uint lParam);
   
           [DllImport("user32.dll", EntryPoint="FindWindowExA", CallingConvention=CallingConvention.StdCall,CharSet=CharSet.Ansi)]
           private static extern uint FindWindowEx(uint hwndParent, uint hwndChildAfter, string lpszClass, string lpszWindow);
   
           #endregion
   
           #region Constructors & Destructors
   
           public FileDialogExtender() : this(DialogViewTypes.List, false) {}
   
           public FileDialogExtender(DialogViewTypes viewType) : this(viewType, false) {}
   
           public FileDialogExtender(DialogViewTypes viewType, bool enabled)
           {
               _viewType = viewType;
               Enabled = enabled;
           }
   
           #endregion
   
           #region Properties
   
           public DialogViewTypes DialogViewType
           {
               get { return _viewType; }
               set { _viewType = value; }
           }
   
           public bool Enabled
           {
               get { return _enabled; }
               set { _enabled = value; }
           }
   
           #endregion
   
           #region Methods
   
           /// <summary>
           /// Hash to be called from the overriden WndProc in the parent window of the dialog
           /// </summary>
           /// <param name="m"></param>
           public void WndProc(ref Message m)
           {
               if (!_enabled)
                   return;
   
              if (m.Msg == 289) //Notify of message loop
              {
                  uint dialogHandle = (uint)m.LParam; //handle of the file dialog
 
                  if (dialogHandle != _lastDialogHandle) //only when not already changed
                  {           
                      //get handle of the listview
                      uint listviewHandle = FindWindowEx(dialogHandle, 0, "SHELLDLL_DefView", "");
 
                      //send message to listview
                      SendMessage(listviewHandle, WM_COMMAND, (uint)_viewType, 0);

                      // Sending message to the ListBox to select all items.
                      //SendMessage(listviewHandle, WM_COMMAND, (uint)0x00017021, (uint)0);
 
                      //remember last handle
                      _lastDialogHandle = dialogHandle;
                  }
              }
          }
 
          #endregion
      }
  }



TheMaster

  • Guest
Re: Calling PInvoke method in a form override.
« Reply #1 on: August 23, 2012, 06:00:54 AM »
VS2010exp, AutoCAD 2012, Win7

Im my quest to come up with a fix for my openfile dialog,
I am trying to use a pinvoke method that accesses/sets the list view of the win OpenFileDialog control that I have in my form.
So what I accomplish is to set the selected file name in the list so it is the "selected item".
The code at the bottom is supposed to set the view to "Thumbnails" but so far, no joy.

The comment in the method code instructs to:
Quote
/// Hash to be called from the overriden WndProc in the parent window of the dialog

This is where I could use some help.
My attempt is not working, everything compiles fine but the open file dialog is not affected upon displaying it.
I am compiling to an AutoCAD net loaded .dll.

Code: [Select]
public partial class OpenDWGdialog : Form
    {
        public OpenDWGdialog()
        {
            InitializeComponent();
        }
        [STAThread]
        static void Main(string[] args)
        {
            Application.Run(new OpenDWGdialog());
        }

        protected override void WndProc(ref Message m)  //<< this is what I think I am supposed to do.
        {
            // Letting the Form take care off all messages.
            base.WndProc(ref m);
            FileDialogExtender.FileDialogExtender flde = new FileDialogExtender.FileDialogExtender(FileDialogExtender.FileDialogExtender.DialogViewTypes.Thumbnails, true);
            flde.WndProc(ref m);
           
        }

This is the dialog extension I'm using.


Code: [Select]
//
// This source file was provided by Robert Rohde via http://www.thecodeproject.com/cs/miscctrl/FileDialogExtender.asp
//

    using System;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
   
    namespace FileDialogExtender
    {
        public class FileDialogExtender
        {
            #region Enum DialogViewTypes
   
           /// <summary>
           /// Ansichtentypen der Listenanzeige von Dateidialogen
           /// </summary>
           public enum DialogViewTypes
           {
               /// <summary>
               /// Symbole
               /// </summary>
               Icons = 0x7029,
               /// <summary>
               /// Liste
               /// </summary>
               List  = 0x702b,
               /// <summary>
               /// Details
               /// </summary>
               Details= 0x702c,
               /// <summary>
               /// Minitauransicht
               /// </summary>
               Thumbnails= 0x702d,
               /// <summary>
               /// Kacheln
               /// </summary>
               Tiles = 0x702e,
           }
   
           #endregion
   
           #region Fields
   
           private const uint WM_COMMAND = 0x0111;
           private uint _lastDialogHandle = 0;
           private DialogViewTypes _viewType;
           private bool _enabled;
   
           #endregion
   
           #region DllImports
   
           [DllImport("user32.dll", EntryPoint="SendMessageA", CallingConvention=CallingConvention.StdCall,CharSet=CharSet.Ansi)]
           private static extern uint SendMessage(uint Hdc, uint Msg_Const, uint wParam, uint lParam);
   
           [DllImport("user32.dll", EntryPoint="FindWindowExA", CallingConvention=CallingConvention.StdCall,CharSet=CharSet.Ansi)]
           private static extern uint FindWindowEx(uint hwndParent, uint hwndChildAfter, string lpszClass, string lpszWindow);
   
           #endregion
   
           #region Constructors & Destructors
   
           public FileDialogExtender() : this(DialogViewTypes.List, false) {}
   
           public FileDialogExtender(DialogViewTypes viewType) : this(viewType, false) {}
   
           public FileDialogExtender(DialogViewTypes viewType, bool enabled)
           {
               _viewType = viewType;
               Enabled = enabled;
           }
   
           #endregion
   
           #region Properties
   
           public DialogViewTypes DialogViewType
           {
               get { return _viewType; }
               set { _viewType = value; }
           }
   
           public bool Enabled
           {
               get { return _enabled; }
               set { _enabled = value; }
           }
   
           #endregion
   
           #region Methods
   
           /// <summary>
           /// Hash to be called from the overriden WndProc in the parent window of the dialog
           /// </summary>
           /// <param name="m"></param>
           public void WndProc(ref Message m)
           {
               if (!_enabled)
                   return;
   
              if (m.Msg == 289) //Notify of message loop
              {
                  uint dialogHandle = (uint)m.LParam; //handle of the file dialog
 
                  if (dialogHandle != _lastDialogHandle) //only when not already changed
                  {           
                      //get handle of the listview
                      uint listviewHandle = FindWindowEx(dialogHandle, 0, "SHELLDLL_DefView", "");
 
                      //send message to listview
                      SendMessage(listviewHandle, WM_COMMAND, (uint)_viewType, 0);

                      // Sending message to the ListBox to select all items.
                      //SendMessage(listviewHandle, WM_COMMAND, (uint)0x00017021, (uint)0);
 
                      //remember last handle
                      _lastDialogHandle = dialogHandle;
                  }
              }
          }
 
          #endregion
      }
  }



Your code is creating a new instance of the FileDialogExtender class in your form's WndProc() override.

You should create the instance in your form's constructor and assign it to a member variable, and from the form's WndProc override, call the FileDialogExtender's WndProc() method.

I can't imagine why you would create a new instance of that class every time the WndProc() is called, which can be hundreds of times per second.  :-o

BillZndl

  • Guest
Re: Calling PInvoke method in a form override.
« Reply #2 on: August 23, 2012, 07:06:32 AM »
Thanks Tony.

I found a better example of the filedialogextender on the web so did as you recommend.
But I still see no change in the style of the dialog when it is displayed.

This is a farily simple project with a simple windows form and one control (openFileDialog).
Where it is lacking is the dialog filename does not get "selected" or "highlighted" in the file list on shown,
so I was trying to tweek it with the extender to fix that (single file selection only btw).

My thoughts are, I'm not getting any messages as I would think that the messagebox would fire inside the WndProc.
A different article infers that the control is created earlier and that may be why the message is not processed.
Code: [Select]
using System;
using System.Windows.Forms;

namespace OpenFilesInAcad
{
    public partial class OpenDWGdialog : Form
    {
        public OpenDWGdialog()
        {
            InitializeComponent();
        }
        [STAThread]
        static void Main(string[] args)
        {
            Application.Run(new OpenDWGdialog());
        }

        private FileDialogExtender.FileDialogExtender flde = new FileDialogExtender.FileDialogExtender();

       
        protected override void WndProc(ref Message m)
        {
            // Letting the Form take care off all messages.
            MessageBox.Show("Hello");             
            flde.WndProc(ref m);
            base.WndProc(ref m);
                       
        }

       
        public string OpenDWGdialog1(string title, string defaultDir, string defaultFilename, string defaultExtension)
        {                           
                openFileDialog1.Multiselect = true;
                openFileDialog1.Filter = "AutoCAD files|*" + defaultExtension;               
                openFileDialog1.Title = title;
                openFileDialog1.InitialDirectory = defaultDir;
                openFileDialog1.FileName = defaultFilename;               

                flde.Enabled = true;
                flde.DialogViewType = FileDialogExtender.FileDialogExtender.DialogViewTypes.Thumbnails;

                DialogResult result = openFileDialog1.ShowDialog();

                if (result == DialogResult.OK)
                {
                    return openFileDialog1.FileName;
                }
                else
                {
                    return null;
                }               
        }
       
    }
}


This is the only other class (other than the form designer) in my project, it's a modified class of C Gabriel that was posted here.

Code: [Select]
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.DatabaseServices;

namespace OpenFilesInAcad
{
    public class OpenDWGfileDialog
    {       
        public static string title;
        public static string defaultDir;
        public static string defaultFileName;
        public static string defaultExtension;       

        [LispFunction("GetOpenDWGdialog")]
        public static ResultBuffer GetOpenDWGdialog(ResultBuffer args)
        {
            if (!parseArguments(args)) return null;           

            OpenFilesInAcad.OpenDWGdialog dlg = new OpenDWGdialog();

            string file = dlg.OpenDWGdialog1(title, defaultDir, defaultFileName, defaultExtension);

            ResultBuffer result = new ResultBuffer();
           
            result.Add(new TypedValue((int)LispDataType.Text, file));
           
            return result;
           
        }

        public static bool parseArguments(ResultBuffer args)
        {
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            if (args == null)
                return notEnoughArguments(ed);

            ResultBufferEnumerator iter = args.GetEnumerator();

            iter.MoveNext();
            if (iter.Current.TypeCode != (short)LispDataType.Text)
                return wrongArguments(ed);
            title = (string)iter.Current.Value;

            if (iter.MoveNext() == false)
                return notEnoughArguments(ed);
            if (iter.Current.TypeCode != (short)LispDataType.Text)
                return wrongArguments(ed);
            defaultDir = (string)iter.Current.Value;

            if (iter.MoveNext() == false)
                return notEnoughArguments(ed);
            if (iter.Current.TypeCode != (short)LispDataType.Text)
                return wrongArguments(ed);
            defaultFileName = (string)iter.Current.Value;

            if (iter.MoveNext() == false)
                return notEnoughArguments(ed);
            if (iter.Current.TypeCode != (short)LispDataType.Text)
                return wrongArguments(ed);
            defaultExtension = (string)iter.Current.Value;           

            return true;           
           
        }

        public static bool notEnoughArguments(Editor ed)
        {
            ed.WriteMessage("\nToo few arguments.");
            return false;
        }

        public static bool wrongArguments(Editor ed)
        {
            ed.WriteMessage("\nExpected string string string string.");
            return false;
        }
    }
}


TheMaster

  • Guest
Re: Calling PInvoke method in a form override.
« Reply #3 on: August 23, 2012, 10:27:43 PM »
Thanks Tony.

I found a better example of the filedialogextender on the web so did as you recommend.
But I still see no change in the style of the dialog when it is displayed.

This is a farily simple project with a simple windows form and one control (openFileDialog).
Where it is lacking is the dialog filename does not get "selected" or "highlighted" in the file list on shown,
so I was trying to tweek it with the extender to fix that (single file selection only btw).

My thoughts are, I'm not getting any messages as I would think that the messagebox would fire inside the WndProc.
A different article infers that the control is created earlier and that may be why the message is not processed.
Code: [Select]
using System;
using System.Windows.Forms;

namespace OpenFilesInAcad
{
    public partial class OpenDWGdialog : Form
    {
        public OpenDWGdialog()
        {
            InitializeComponent();
        }
        [STAThread]
        static void Main(string[] args)
        {
            Application.Run(new OpenDWGdialog());
        }

        private FileDialogExtender.FileDialogExtender flde = new FileDialogExtender.FileDialogExtender();

       
        protected override void WndProc(ref Message m)
        {
            // Letting the Form take care off all messages.
            MessageBox.Show("Hello");             
            flde.WndProc(ref m);
            base.WndProc(ref m);
                       
        }

       
        public string OpenDWGdialog1(string title, string defaultDir, string defaultFilename, string defaultExtension)
        {                           
                openFileDialog1.Multiselect = true;
                openFileDialog1.Filter = "AutoCAD files|*" + defaultExtension;               
                openFileDialog1.Title = title;
                openFileDialog1.InitialDirectory = defaultDir;
                openFileDialog1.FileName = defaultFilename;               

                flde.Enabled = true;
                flde.DialogViewType = FileDialogExtender.FileDialogExtender.DialogViewTypes.Thumbnails;

                DialogResult result = openFileDialog1.ShowDialog();

                if (result == DialogResult.OK)
                {
                    return openFileDialog1.FileName;
                }
                else
                {
                    return null;
                }               
        }
       
    }
}


This is the only other class (other than the form designer) in my project, it's a modified class of C Gabriel that was posted here.

Code: [Select]
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.DatabaseServices;

namespace OpenFilesInAcad
{
    public class OpenDWGfileDialog
    {       
        public static string title;
        public static string defaultDir;
        public static string defaultFileName;
        public static string defaultExtension;       

        [LispFunction("GetOpenDWGdialog")]
        public static ResultBuffer GetOpenDWGdialog(ResultBuffer args)
        {
            if (!parseArguments(args)) return null;           

            OpenFilesInAcad.OpenDWGdialog dlg = new OpenDWGdialog();

            string file = dlg.OpenDWGdialog1(title, defaultDir, defaultFileName, defaultExtension);

            ResultBuffer result = new ResultBuffer();
           
            result.Add(new TypedValue((int)LispDataType.Text, file));
           
            return result;
           
        }

        public static bool parseArguments(ResultBuffer args)
        {
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            if (args == null)
                return notEnoughArguments(ed);

            ResultBufferEnumerator iter = args.GetEnumerator();

            iter.MoveNext();
            if (iter.Current.TypeCode != (short)LispDataType.Text)
                return wrongArguments(ed);
            title = (string)iter.Current.Value;

            if (iter.MoveNext() == false)
                return notEnoughArguments(ed);
            if (iter.Current.TypeCode != (short)LispDataType.Text)
                return wrongArguments(ed);
            defaultDir = (string)iter.Current.Value;

            if (iter.MoveNext() == false)
                return notEnoughArguments(ed);
            if (iter.Current.TypeCode != (short)LispDataType.Text)
                return wrongArguments(ed);
            defaultFileName = (string)iter.Current.Value;

            if (iter.MoveNext() == false)
                return notEnoughArguments(ed);
            if (iter.Current.TypeCode != (short)LispDataType.Text)
                return wrongArguments(ed);
            defaultExtension = (string)iter.Current.Value;           

            return true;           
           
        }

        public static bool notEnoughArguments(Editor ed)
        {
            ed.WriteMessage("\nToo few arguments.");
            return false;
        }

        public static bool wrongArguments(Editor ed)
        {
            ed.WriteMessage("\nExpected string string string string.");
            return false;
        }
    }
}


Are you using this code in an AutoCAD DLL or a windows executable ?

BillZndl

  • Guest
Re: Calling PInvoke method in a form override.
« Reply #4 on: August 27, 2012, 06:35:55 AM »
Are you using this code in an AutoCAD DLL or a windows executable ?

I am compiling to an AutoCAD net loaded .dll.


TheMaster

  • Guest
Re: Calling PInvoke method in a form override.
« Reply #5 on: August 27, 2012, 07:55:35 AM »
Are you using this code in an AutoCAD DLL or a windows executable ?

I am compiling to an AutoCAD net loaded .dll.

The main application window is the target for many dialog messages, and I think that's the assumption that component makes. In a standalone windows executable with a Form, the form may be the main application window, but not in AutoCAD (The AutoCAD main window is). To verify that, you can test the code in a standalone executable to see if it works in that case.  If it does, then you can try passing the handle of the main AutoCAD window to the control rather than your form's handle.

Also, I assume you're using a standard Windows Forms OpenFileDialog, rather than the AutoCAD file dialog.

BillZndl

  • Guest
Re: Calling PInvoke method in a form override.
« Reply #6 on: August 27, 2012, 11:43:06 AM »
The main application window is the target for many dialog messages, and I think that's the assumption that component makes. In a standalone windows executable with a Form, the form may be the main application window, but not in AutoCAD (The AutoCAD main window is). To verify that, you can test the code in a standalone executable to see if it works in that case.  If it does, then you can try passing the handle of the main AutoCAD window to the control rather than your form's handle.

Also, I assume you're using a standard Windows Forms OpenFileDialog, rather than the AutoCAD file dialog.

Yes, the windows OpenFileDialog.
Tried an exe version with the no joy.

I'm in over my head and spent too much time already.
Attached the zip file for the .exe project if someone else wants to look at it.




Jeff H

  • Needs a day job
  • Posts: 6151
Re: Calling PInvoke method in a form override.
« Reply #7 on: August 27, 2012, 01:39:34 PM »
Are you using Windows 7?
I think things have changed like the views types.
 
Maybe check out
http://archive.msdn.microsoft.com/WindowsAPICodePack
 
Look at explorer sample

 

BillZndl

  • Guest
Re: Calling PInvoke method in a form override.
« Reply #8 on: August 27, 2012, 02:02:51 PM »
Yes Win7,  noticed there were more choices for the view in Win7 but figured that the "details" and "list" should've worked, well apparently not! :blank:
I'll dig into the API pack and see what's up. Sure would be nice to solve the glitch of the file not highlighting (same problem as VisualLisp Getfiled function has since win7).
I'll post back when I know something more.

Thanks!

BillZndl

  • Guest
Re: Calling PInvoke method in a form override.
« Reply #9 on: August 30, 2012, 02:12:13 PM »
Are you using Windows 7?
I think things have changed like the views types.
 
Maybe check out
http://archive.msdn.microsoft.com/WindowsAPICodePack
 
Look at explorer sample
 

Just a follow up:

The Custom openFileDialog was awsome and I had a bit of success modifying it to my liking.
I couldn't find a way to access the list of files to set the selected item, it just didn't seem to be exposed, even at the native dialog box level,
not that it wasn't or couldn't be made to, It was just that I couldn't find or figure out anything.

The explore sample looked fantastic but, well let's just say I might look at another time.

For now, I'll have to settle for the glitch in the dialogs we have.

Thanks again for all that helped.  :-)