Winform开发小例

1.  理解“Windows 窗体应用程序”项目中Program.cs文件中的main方法与传统C++Console控制台程序中的main方法的区别。从程序运行层次上讲,两者无区别,都是程序的入口点,属于进程中的第一个线程。前者隐藏了UI应用程序必需的消息循环,后者没有。

2.  每个Windows桌面应用程序都必须包含至少一个UI线程,所谓UI线程,就是可以响应Windows消息的线程。通常情况下,除非特别需要,一个Windows桌面应用程序只包含一个UI线程。

3.  UI线程本质上跟普通线程一样,一般为程序的入口线程,比如Program.cs文件中的main方法,就是UI线程,而Application.Run()方法中封装了消息循环。如果没有Application.Run()方法,那么它跟其他线程一模一样。之所以叫做UI线程,是因为它之中包含一个类似

1 While(GetMessage(…))//取Windows消息

2 {
3     //处理windows消息,调用开发者编写的回调方法,如事件处理程序 等。
4 }   

的循环。

4. 有关Windows消息机制等内容,请上网Google或者百度。

5.  UI线程主要负责界面的实时更新,所以开发人员编写代码时,请遵守以下规律:

     1) 不要在控件的事件处理程序中编写(或者调用)耗时的代码块;

     2) 不要在控件的事件处理程序中调用阻塞方法;阻塞与非阻塞应参见13.

6.  明白程序设计中的 委托、事件、事件处理程序的区别

      1) Publicdelegate void KeyPressEventHandler(KeyPressEventArgse);

      2) Public eventKeyPressEventHandler KeyPress;

      3)  Public void Textbox1_KeyPress(objectsender,KeyPressEventArgs e)

           {

                   //….

           }

      其中:

      1为委托 2为事件 3为事件处理程序

7.  所有的事件处理程序都是在UI线程中调用,又因为UI线程负责更新界面,所以UI线程始终必须保持顺畅(表现为3中的while循环体不能耗时太长),即不能出现长时间执 行一个方法不返回的情况。所以,请遵守5中的规律。

8.  同一个方法,可以运行在多个线程之中,方法跟线程没有一对一的原则

      Private void  thread_pro()  //

      { 

      }

     1) privatebutton1_click(object sender,EventArgs e)

     {

           thread_pro();  //thread_pro运行在UI线程中

     }

   2)private button1_click(object sender,EventArgs e)

     {

           Thread t = new Thread(newThreadStart(thread_pro));

           Thread t1 = new Thread(new ThreadStart(thread_pro));

           Thread t2 = newThread(new ThreadStart(thread_pro));

          t.start();  //thread_pro运行在t线程中

         t1.start();  //thread_pro运行在t1线程中

          t.2.start();  //thread_pro运行在t2线程中

     }

     3) 还可以通过Control.Invoke() 或者BenginInvoke方法将方法投递到创建该控件的线程中执行。

      以上所有情况,请注意线程共享数据。

9.   多线程编程中,请注意“线程安全”问题,对于一些具备“非原子”操作的对象,必须采取措施避免发生错误。

UI控件(Button、datagridview等等)、集合(List、ArrayList)等属于此类对象,控件任何时间都不能多线程访问。

10. 坚决杜绝跨线程访问UI控件,原因见9。跨线程访问控件的方法见8中的3)。

11. 除了.Net Winform中的事件处理程序是在UI线程中调用以外,其它的回调方法几乎所有都不会在UI线程中执行,所以,开发人员在编写回调方法时,请遵守第9,10两大规律。

12.  明白什么叫回调方法。回调方法一般由开发者编写,但不由开发者调用,由系统(或者说框架)调用。在Windows桌面应用程序开发过程中,控件的事件处理程序都属于回调方法,回调方法一般用在“观察者”设计模式中,当事件的激发者激发一个事件时,它就会调用回调方法。控件的所有事件都属于此类。

另外一种常见为,异步执行某个操作,譬如,socket.BeginAccept()中的AsyncCallBack类型参数。

      在框架横行的时代,一般开发者编写的代码都属于回调代码。因为程序的主要结构都由先辈们在框架中集成好了。开发者们只需要像填空一样完善空缺的部分。

13.  阻塞方法指,由于方法体内包含耗时较长的操作,所以方法不能及时返回。

所谓“及时”与“非及时”没有绝对界限,示例如下:

复制代码

      int func1()     //及时返回
      {
          Int index = 0;
          For(int i=0;i<100;i++)
          {
               Index ++;
           }
           Return index;
      }
     Int func2()   //非及时返回
     {
          Int index = 0;
          For(int i=0;i<1000;i++)
          {
                For(int j=0;j<1000;++j)
               {
                      Index ++;
                }
          }
          Return index;
      }

复制代码

上述func1相对而言,属于非阻塞方法,func2属于阻塞方法。

14.  Windows窗体应用程序不会直接跟键盘、鼠标等硬件设备交互,它只与Windows消息有直接交互。虽然表面上鼠标键盘等硬件设备是操作在窗体之上的,但实质上,你        编写的桌面应用程序是不会理解这些硬件设备的一举一动。他们是通过操作系统(驱动程序)进行桥接的,操作系统先将硬件设备的一举一动翻译成windows消息(一种数据结构,程序可以理解),然后供程序理解,作出相应的反应。

15.  所谓“阻塞调用线程”,是指在某一个线程中调用了阻塞方法,从而使该线程不能及时执行以后的代码。

复制代码

1      Void func()
2      {
3          Int index=0;
4          For(int i=0;i<10000;++i)
5          {
6               For(int j=0;j<10000;++j)
7              {
8                    I ndex++;
9               }
10           }
11      }
12      Thread t = newThread(new ThreadStart(func));
13       t.Start();       //线程t中调用了阻塞方法func,因此线程t会被阻塞
14

复制代码

在介绍func方法时,可以这样描述:该方法会阻塞调用线程。

16. 同一个方法可以被多个线程调用,既可被UI线程调用,也可被非UI线程调用,那么在方法体内怎么编写访问UI控件(UI元素)的代码呢?(跨线程访问UI控件会引发异常

      Void func()

      {

          Textbox1.Text=”测试”;

          PictureBox1.Image = Image.FromFile(“a.jpg”);

      }

     1)以上func方法可能运行在UI线程中,如下:

     Private voidbutton1_Click(object sender,EventArgs e)

     {

          func();  //调用func方法

     }

2)有如下,func方法可能运行在其他非UI线程中

     Private void button1_Click(object sender,EventArgs e)

     {

         Thread t = new Thread(newThreadStart(func));

         t.Start();  //func访问运行在t线程中

     }

    在2)中,可能引发异常。

    以上问题的解决方案为:

    修改func代码为:

    Func()

    {

          If(this.InvokeRequired)

          {

                  This.BeginInvoke((Action)delegate(){func()});

          }

         Else

         {

              Textbox1.Text=”测试”;

               PictureBox1.Image = Image.FromFile(“a.jpg”);

         }

   }

有关BeginInvoke或者Invoke方法的使用,请上网Google或者百度。

17. 有关“跨线程访问UI控件可能引发异常”的原因,跟多线程访问集合可能出现错误的原因基本相似。下面列举一段代码说明情况

复制代码

1    ClassMyControl
2    {
3        Object root;
4        Public Draw()
5        {
6            GetRoot(root);
7            // 一系列操作…
8            ReleaseRoot(root);
9         }
10        Public OtherDraw()
11       {
12           GetRoot(root);
13           // 一系列操作 …
14            ReleaseRoot(root);
15        }
16    }

复制代码

其中root变量同时只能被占用一次,GetRoot()获取root的访问权,如果root已经被占用,则抛出异常。ReleaseRoot()释放root占用。

当在一个线程中(比如UI线程中)访问MyControl类对象A,调用A.Draw()方法,执行到GetRoot(root)方法后,该线程失去控制权,暂停运行一下的代码,即此时root已被占用。而另一线程中如果也要访问同一对象A的Draw()方法,那么就会引发异常。

18.在.Net Winform应用程序中,程序与用户的交互主要包含两个方面,一是用户用鼠标、键盘灯硬件设备进行操作,程序响应操作,然后进行反馈(比如更新界面、刷新数据等),二是不需要用户用鼠标等硬件设备进行操作,程序自己自动进行反馈(比如QQ弹出新闻窗体、360弹窗等)。

第一种情况是我们所熟知的,比如用户用鼠标点击按钮(button1),程序则弹出一个MessageBox,我们在程序中是这样子写的:事件处理程序如下

1    Private voidbutton1_Click(object sender,EventArgs e)
2    {
3           MessageBox.Show(“弹出对话框,或者其他操作”);
4    }

再来理一下这个过程,首先用户拿起鼠标点击button1,操作系统(鼠标驱动)会捕获这个事件,经过分析,操作系统得知用户点击的是哪个窗体(按钮)、点击的位置(坐标),点击类型(左键还是右键或者其他),以及其他信息,之后,将这些信息封装成一个类型(即windows消息)发送给创建该窗体(控件)的线程中的消息队列,之后,操作系统(鼠标驱动)就不在负责了。接着,UI线程从线程消息队列中获取该消息(注意:这个过程是一直存在的),分析消息,调用开发人员编写的一些回调方法,如button1_Click()方法,从而到达相应鼠标键盘操作的目的。从上面分析过程来看,再一次说明,程序是不会直接跟鼠标等硬件设备交互的,与它直接交互的只有Windows消息,而这个过程需要Windows操作系统起着重要作用。

第二种情况一般用在多线程编程中,当程序有耗时操作、或者需要一直监听等情况的时候,是不能放在UI线程之中的,这时候就需要另外开辟线程,在另外的线程中处理。这种情况中,另外开辟的线程有时候需要反馈跟用户一些信息,即更新UI界面或者弹出一个窗体等,这就涉及到跨线程访问UI元素的问题了,详见5和16.

(1)Winform应用程序运行结构图

(2)TCP通讯协议在Winform程序中的应用示意图

熟悉整个程序的来龙去脉,编程的时候就会很轻松,不会云里雾里。

另附公司招聘面试题一份,用了几次,发现效果不好,不知啥原因

1.简述接口、抽象类的区别。

2.简述重载(overload)与重写(override)的区别。

3.对OO思想的理解。

4.简述对象“线程安全”是什么意思。

5.跨线程访问控件的方法?简述该方法的原理。

6.简述Socket通讯原理,简述怎样处理数据包不完整问题。

7..Net Winform编程中最常用的设计模式有哪些?

8.能否自己写一个类似ListBox功能的控件?简述其原理。

9.简述在windows操作系统中,窗体与按钮的区别。

10.简述用C#(或者VB)将Excel中的数据导入数据库的方法。简述用C#(或者VB)将数据库中的数据导入到一个新的Excel文件打方法。

11.两个Winform桌面应用程序A与B,各有一个主窗体,列举A程序关闭B程序的方法。

12情景:.Net Winform程序设计中,用鼠标点击按钮“Button1”,弹出一个MessageBox消息提示框。

末日这天写篇博客吧,既然没来,那就纪念一下。

这次谈谈自制控件,也就是自定义控件,先上图,再说

1.扩展OpenFileDialog,在OpenFileDialog中添加各种文件(.txt,.jpg,.excel等等)的预览功能

2.重写ListBox,增加折叠、鼠标背影、分类等功能

-----------------------------分割线--------------------------------------------------------------

一、扩展OpenFileDialog

许多软件的打开对话框都有预览功能,最常见的就是图片预览,用鼠标选择一个图片文件后,右侧或者下侧就会有该图片的缩略图(photoshop中属于后者)。在winform编程中,有专门的打开文件对话框的类OpenFileDialog,但是他不提供文件预览功能,封装得实在太好。看看它公开那些接口

提到扩展,很多人可能想到继承它就可以扩展它,可惜OpenFileDialog声明为sealed,不允许从他继承。稍微底层一点的,想到可以通过Win32 API来修改它的显示方式,只可惜,如你所见,它根本没提供Handle属性,更别说HandleCreated、HandleDestroyed等事件了。那么怎么样子搞呢?其实答案还是通过Win32 API,只是我们取得它的句柄的方式要复杂一点而且调用API的时机隐晦了一点。

提示:

1.Win32 API操作窗体需要知道窗体的句柄;

2.不熟悉Win32编程的同学可以先上网查查资料,特别是不知道SetParent、SetWindowPos等API是干嘛的,我觉得以下的看不懂。

为什么说取得它的句柄复杂了一点?难道不是用“FindWindow”、“FindWindowEx”、“ EnumChildWindows”等获取OpenFileDialog的句柄,再用“SetParent”、“SetWindowPos”等API将.net控件(本例中是DataGridView控件,当然可以使其他任何一种)添加到OpenFileDialog中去?没错,以上列举出来的API都是基本要用到的,“只是用在什么地方、什么时候用”是个比较麻烦的问题,原因如下:

1)我们知道OpenfileDialog显示的是模式对话框,也就是说,一旦它ShowDialog(),它以下的代码是不会再执行的,具体原因是什么(我以后的博客会专门讲为什么),你现在可以理解为OpenFileDialog()方法会阻塞调用线程,既然阻塞了调用线程,那么我们再无法控制程序了(直到它返回),根本谈不上再调用API获取OpenFileDialog的句柄然后去操作它。如果有人会说,“我可以另开辟线程去取OpenFileDialog得句柄再操作它”,恩,我不否定这个方法,只是我想说,如果你真的按照这个方法去试,那么肯定会陷入泥潭。因为你不仅要取它的句柄,你还要监视OpenFIleDialog的一举一动,移动、缩放、用户鼠标点击选择文件、更改目录等,然后再操作.net控件(本例中是DataGridView控件,下同),让.net控件去适应OpenFileDialog的大小等等,你会发现你忙死了,甚至有的你根本监视不了,比如用户点击选择文件、更改目录。

2)就算我们能够在OpenFIleDialog显示之后,取得它的句柄,那么什么时候再调用其他API呢?比如什么时候调用SetWindowPos,让.net控件适应OpenFileDialog的大小变化?什么时候知道用户选择文件发生了变化?

所以,API方法什么时候用?用在什么地方?就是接下来要讨论的东西。

我不知道各位在使用各种框架的时候,对“框架”的理解到什么程度,我觉得可以总结成一句话“跟个2b似地注册一些事件,然后苦逼地去写好每一个回调方法,我们却不知道为啥要这样写”,不是么?既然这样,那么我们的API方法只要写在了正确的回调方法中,我们就能到达想要的目的了。考虑几个问题:

1)OpenFileDialog显示,我们向其中添加.net控件。我们什么时候知道它显示?

2)OpenFileDialog大小发生变化时,我们要更新.net控件以适应新的大小。我们什么时候知道OpenFileDialog的大小发生了变化?

3)OpenFileDialog中用户选择的文件发生了变化,我们需要知道新选择的文件路径,用来显示在.net控件中。我们怎么知道选择了什么文件?(这里选择文件指用户用鼠标在OpenFileDialog中单击选取,不是点击“确定”后。)

以上所有的问题,其实在一个地方都可以知道,那就是监听OpenFileDialog窗体的Windows消息,因为一个窗体的任何一个动作都伴随着一系列的Windows消息(这个可以用Spy++查看)。既然这样,那么我们可以在窗体处理Windows消息的回调方法中调用API方法了,也就是窗体的Control.WndProc方法中。之前已经说过了,OpenFileDialog声明为Sealed,提供的接口少之又少,我们几乎根本不可能接触到OpenFileDialog的WndProc,更谈不上监听Windows消息,然后调用API去操作它。这时候,NativeWindow该出场了,先来引用一下MSDN上对NativeWindow的解释:

“提供窗口句柄和窗口过程的低级封装。”

说了像没说一样,其实就是说,将一个窗口句柄与NativeWindow对象绑定后,该NativeWindow对象就能接收到这个窗体的所有消息。说到Windows消息,我想说一下Windows桌面应用程序的运行流程,其实如果看了我前一篇博客的同学应该有些了解,.Net Winform开发笔记(二)中基本提到了一些。为了配合本次讲解,我再次画了一张图

上图中,虚线框可以看做是一个.net中的Control类对象(或者其派生类,下同,控件即窗体、窗体即控件),正常情况下,Winform程序会按照1->2->3的步骤运行,当我们将Control类对象的Handle(就是我们常说的窗口句柄,做了一下封装)与一个NativeWIndow对象绑定后,程序不再按照1->2->3这样的顺序运行了,他会按照1->2-1->2-2->3这样运行,也就是说,NativeWindow对象可以拦截Control类对象的WIndows消息,我们完全可以在NativeWIndow中重写他的WndProc方法,像处理自己的Windows消息一样去处理Control类对象的消息。所以,我们就可以在NativeWindow对象的WndProc中调用我们的API方法。

接下来,上代码(代码只提供大概思路)

1.扩展对话框

View Code

复制代码

 1     public class MultiOpenFileDialog
 2     {
 3         #region fields
 4         private const SetWindowPosFlags UFLAGSHIDE =
 5         SetWindowPosFlags.SWP_NOACTIVATE |
 6         SetWindowPosFlags.SWP_NOOWNERZORDER |
 7         SetWindowPosFlags.SWP_NOMOVE |
 8         SetWindowPosFlags.SWP_NOSIZE |
 9         SetWindowPosFlags.SWP_HIDEWINDOW;
10         #endregion
11         public string FileName;
12         #region public methods
13         public DialogResult ShowDialog()
14         {
15             return ShowDialog(null);
16         }
17         public DialogResult ShowDialog(IWin32Window owner)
18         {
19             using (OpenFileDialog open = new OpenFileDialog())
20             {
21                 MedianForm median = new MedianForm(open);
22                 median.Show(owner);
23                 Win32.SetWindowPos(median.Handle, IntPtr.Zero, 0, 0, 0, 0, UFLAGSHIDE); //隐藏中间窗体
24                 DialogResult dialogresult = open.ShowDialog(median); //将median作为openfileDialog的owner
25                 median.Close();
26                 if (dialogresult == DialogResult.OK)
27                 {
28                     FileName = open.FileName;
29                 }
30                 return dialogresult;
31             }
32         }
33         #endregion
34     }

复制代码

2.监听Dialog的NativeWindow

View Code

复制代码

  1     class DialogNativeWindow : NativeWindow,IDisposable
  2     {
  3         IntPtr handle; //待扩展OpenFileDialog的句柄
  4         OpenFileDialog openfiledialog; //待扩展OpenFileDialog
  5         DataGridView addControl; //向窗体中添加新的控件
  6         ChildControlNativeWindow childNative;
  7         bool init = false;
  8 
  9         public DialogNativeWindow(IntPtr handle, OpenFileDialog openfiledialog)
 10         {
 11             this.handle = handle;
 12             this.openfiledialog = openfiledialog;
 13             AssignHandle(handle);
 14 
 15             //设置控件信息
 16             addControl = new DataGridView();
 17             addControl.Width = 600;
 18             addControl.Height = 200;
 19             addControl.DataSource = null;
 20         }
 21 
 22         #region override methods
 23         protected override void WndProc(ref Message m)
 24         {
 25             switch (m.Msg)
 26             {
 27                 case (int)Msg.WM_SHOWWINDOW: //窗体显示
 28                     {
 29                         NativeChild(); 
 30                         AddControl();
 31                         break;
 32                     }
 33                 case (int)Msg.WM_SIZING: //窗体大小改变
 34                     {
 35                         UpdateSize();
 36                         break;
 37                     }
 38                 case (int)Msg.WM_WINDOWPOSCHANGING: //窗体位置变化
 39                     {
 40                         UpdateLocation(m);
 41                         break;
 42                     }
 43             }
 44             base.WndProc(ref m);
 45         }
 46         #endregion
 47 
 48         #region event handlers
 49         void childNative_SelectPathChanged(StringBuilder path)
 50         {
 51             //处理选择目录变化事件
 52             //...
 53         }
 54 
 55         void childNative_SelectFileChanged(StringBuilder file)
 56         {
 57             //处理选择文件变化事件
 58             //如果是xls文件,将其显示在datagridview控件中
 59             string str = file.ToString();
 60             if (str.ToLower().EndsWith(".xls"))
 61             {
 62                 OledbManager manager = new OledbManager();
 63                 if (manager.Connect("Provider=Microsoft.Jet.OLEDB.4.0; Data Source=\'" + str + "\'; Extended Properties='Excel 8.0;'"))
 64                 {
 65                     DataTable tb = manager.SearchTable();
 66                     if (tb != null)
 67                     {
 68                         addControl.Rows.Clear();
 69                         addControl.Columns.Clear();
 70                         foreach (DataColumn col in tb.Columns)
 71                         {
 72                             addControl.Columns.Add(col.ColumnName, col.Caption);
 73                         }
 74                         foreach (DataRow row in tb.Rows)
 75                         {
 76                             object[] objs = new object[tb.Columns.Count];
 77                             for (int i = 0; i < tb.Columns.Count; ++i)
 78                             {
 79                                 objs[i] = row[i];
 80                             }
 81                             addControl.Rows.Add(objs);
 82                         }
 83                     }
 84                 }
 85             }
 86             else
 87             {
 88                 addControl.Rows.Clear();
 89                 addControl.Columns.Clear();
 90             }
 91         }
 92         #endregion
 93 
 94         #region private methods
 95         private void NativeChild()
 96         {
 97             //查找openfileDialog中的子控件
 98             Win32.EnumChildWindows(handle, new Win32.EnumWindowsCallBack(WindowCallBack), 0);
 99         }
100         private void AddControl()
101         {
102             //添加控件到OpenFileDialog界面
103             Win32.SetParent(addControl.Handle, handle);
104             RECT currentSize = new RECT();
105             Win32.GetClientRect(handle, ref currentSize);
106             addControl.Height = (int)currentSize.Height;
107             addControl.Location = new Point((int)(currentSize.Width - addControl.Width), 0);
108 
109             init = true;
110         }
111         private void UpdateLocation(Message m)
112         {
113             if (!init) //只初始化openfileDialog的大小一次
114             {
115                 WINDOWPOS pos = (WINDOWPOS)Marshal.PtrToStructure(m.LParam, typeof(WINDOWPOS));
116                 if (pos.flags != 0 && ((pos.flags & (int)SWP_Flags.SWP_NOSIZE) != (int)SWP_Flags.SWP_NOSIZE))
117                 {
118                     pos.cx += addControl.Width; //修改OpenfileDialog的宽度
119                     Marshal.StructureToPtr(pos, m.LParam, true);
120 
121                     RECT currentSize = new RECT();
122                     Win32.GetClientRect(handle, ref currentSize);
123                     addControl.Height = (int)currentSize.Height;
124                 }
125             }
126         }
127         private void UpdateSize()
128         {
129             RECT currentSize = new RECT();
130             Win32.GetClientRect(handle, ref currentSize);       
131             Win32.SetWindowPos(addControl.Handle, (IntPtr)ZOrderPos.HWND_BOTTOM, 0, 0, (int)addControl.Width, (int)currentSize.Height, UFLAGSSIZEEX); //新添加的控件与openfileDialog大小一致
132         }
133         private bool WindowCallBack(IntPtr handle, int lparam)
134         {
135             StringBuilder wndClass = new StringBuilder(256);
136             Win32.GetClassName(handle, wndClass, wndClass.Capacity);//获取控件类名
137 
138             if (wndClass.ToString().StartsWith("#32770")) //找到目标控件
139             {
140                 childNative = new ChildControlNativeWindow(handle);
141                 childNative.SelectFileChanged += new ChildControlNativeWindow.SelectFileChangedEventHandler(childNative_SelectFileChanged);
142                 childNative.SelectPathChanged += new ChildControlNativeWindow.SelectPathChangedEventHandler(childNative_SelectPathChanged);
143                 return true;
144             }
145             return true;
146         }
147         #endregion
148 
149         #region enums
150         private const SetWindowPosFlags UFLAGSSIZEEX =
151             SetWindowPosFlags.SWP_NOACTIVATE |
152             SetWindowPosFlags.SWP_NOOWNERZORDER |
153             SetWindowPosFlags.SWP_NOMOVE |
154             SetWindowPosFlags.SWP_ASYNCWINDOWPOS |
155             SetWindowPosFlags.SWP_DEFERERASE;
156         private const SetWindowPosFlags UFLAGSSIZE =
157             SetWindowPosFlags.SWP_NOACTIVATE |
158             SetWindowPosFlags.SWP_NOOWNERZORDER |
159             SetWindowPosFlags.SWP_NOMOVE;
160         private const SetWindowPosFlags UFLAGSHIDE =
161             SetWindowPosFlags.SWP_NOACTIVATE |
162             SetWindowPosFlags.SWP_NOOWNERZORDER |
163             SetWindowPosFlags.SWP_NOMOVE |
164             SetWindowPosFlags.SWP_NOSIZE |
165             SetWindowPosFlags.SWP_HIDEWINDOW;
166         #endregion
167 
168         #region IDisposable 成员
169 
170         public void Dispose()
171         {
172             ReleaseHandle(); //释放与openfileDialog的句柄关联
173             if (childNative != null)
174             {
175                 childNative.SelectFileChanged -= new ChildControlNativeWindow.SelectFileChangedEventHandler(childNative_SelectFileChanged);
176                 childNative.SelectPathChanged -= new ChildControlNativeWindow.SelectPathChangedEventHandler(childNative_SelectPathChanged);
177                 childNative.Dispose(); 
178             }
179 
180         }
181 
182         #endregion
183     }

复制代码

3.监听子控件的NativeWindow

View Code

复制代码

 1     class ChildControlNativeWindow : NativeWindow,IDisposable
 2     {
 3         IntPtr handle; //需要被监听消息的子控件句柄
 4         public ChildControlNativeWindow(IntPtr handle)
 5         {
 6             this.handle = handle;
 7             AssignHandle(handle);
 8         }
 9 
10         #region override methods
11         protected override void WndProc(ref Message m)
12         {
13             switch (m.Msg)
14             {
15                 case (int)Msg.WM_NOTIFY:
16                     OFNOTIFY ofNotify = (OFNOTIFY)Marshal.PtrToStructure(m.LParam, typeof(OFNOTIFY));
17                     if (ofNotify.hdr.code == (uint)DialogChangeStatus.CDN_SELCHANGE) //openfileDialog选择文件发生变化
18                     {
19                         StringBuilder file = new StringBuilder(256);
20                         Win32.SendMessage(Win32.GetParent(handle), (int)DialogChangeProperties.CDM_GETFILEPATH, (int)256, file);
21                         if (SelectFileChanged != null)
22                             SelectFileChanged(file); //通知注册者
23                     }
24                     else if (ofNotify.hdr.code == (uint)DialogChangeStatus.CDN_FOLDERCHANGE) //openfileDialog选择目录发生变化
25                     {
26                         StringBuilder path = new StringBuilder(256);
27                         Win32.SendMessage(Win32.GetParent(handle), (int)DialogChangeProperties.CDM_GETFOLDERPATH, (int)256, path);
28                         if (SelectPathChanged != null)
29                             SelectPathChanged(path); //通知注册者
30                     }
31                     break;
32             }
33             base.WndProc(ref m);
34         }
35         #endregion
36 
37         #region delegate
38         public delegate void SelectFileChangedEventHandler(StringBuilder file); 
39         public delegate void SelectPathChangedEventHandler(StringBuilder path);
40         #endregion
41 
42         #region events
43         public event SelectFileChangedEventHandler SelectFileChanged; //当openfileDialog的选择文件发生变化时发生
44         public event SelectPathChangedEventHandler SelectPathChanged; //当openfileDialog的选择目录发生变化时发生
45         #endregion
46 
47         #region IDisposable 成员
48 
49         public void Dispose()
50         {
51             ReleaseHandle(); //终止与子控件句柄的关联
52         }
53 
54         #endregion
55     }

复制代码

4.中间过渡窗体,用来获取OpenFileDialog的句柄

View Code

复制代码

 1     class MedianForm : Form
 2     {
 3         OpenFileDialog open = null; 
 4         DialogNativeWindow dialognative;
 5 
 6         public MedianForm(OpenFileDialog open)
 7         {
 8             this.open = open;
 9             StartPosition = FormStartPosition.Manual;
10             Location = new System.Drawing.Point(-1000, -1000); //避免界面闪烁
11         }
12         protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
13         {
14             if (dialognative != null)
15             {
16                 dialognative.Dispose(); //释放资源
17             }
18             base.OnClosing(e);
19         }
20         protected override void WndProc(ref Message m)
21         {
22             if (m.Msg == (int) Msg.WM_ACTIVATE)
23             {
24                 dialognative = new DialogNativeWindow(m.LParam, open); //m.LParam为要打开的窗口句柄,开始监听OpenFileDialog的Windows消息
25             }
26             base.WndProc(ref m);
27         }
28     }

复制代码

5.访问Excel文件的类

View Code

复制代码

 1     class OledbManager
 2     {
 3         OleDbConnection conn;
 4         /// <summary>
 5         /// 连接excel文件
 6         /// </summary>
 7         /// <param name="connstr"></param>
 8         /// <returns></returns>
 9         public bool Connect(string connstr)
10         {
11             try
12             {
13                 conn = new OleDbConnection(connstr);
14                 conn.Open();
15                 return true;
16             }
17             catch
18             {
19                 return false;
20             }
21         }
22         /// <summary>
23         /// 查找第一张表中的数据
24         /// </summary>
25         /// <returns></returns>
26         public DataTable SearchTable()
27         {
28             try
29             {
30                 DataTable tb = new DataTable();
31                 string sql = "select * from [Sheet1$]";
32                 OleDbCommand com = new OleDbCommand(sql, conn);
33                 OleDbDataAdapter adp = new OleDbDataAdapter(com);
34                 adp.Fill(tb);
35                 return tb;
36             }
37             catch
38             {
39                 return null;
40             }
41         }
42     }

复制代码

6.几个Win32结构体、枚举类型以及API声明(本代码参考CodeProject上的一篇文章)

View Code

复制代码

  1     public static class Win32
  2     {
  3         #region Delegates
  4         public delegate bool EnumWindowsCallBack(IntPtr hWnd, int lParam);
  5         #endregion
  6 
  7         #region USER32
  8         [DllImport("user32.dll", CharSet = CharSet.Auto)]
  9         public static extern IntPtr GetParent(IntPtr hWnd);
 10         [DllImport("User32.Dll")]
 11         public static extern int GetDlgCtrlID(IntPtr hWndCtl);
 12         [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
 13         public static extern int MapWindowPoints(IntPtr hWnd, IntPtr hWndTo, ref POINT pt, int cPoints);
 14         [DllImport("user32.dll", SetLastError = true)]
 15         public static extern bool GetWindowInfo(IntPtr hwnd, out WINDOWINFO pwi);
 16         [DllImport("User32.Dll")]
 17         public static extern void GetWindowText(IntPtr hWnd, StringBuilder param, int length);
 18         [DllImport("User32.Dll")]
 19         public static extern void GetClassName(IntPtr hWnd, StringBuilder param, int length);
 20         [DllImport("user32.Dll")]
 21         public static extern bool EnumChildWindows(IntPtr hWndParent, EnumWindowsCallBack lpEnumFunc, int lParam);
 22         [DllImport("user32.Dll")]
 23         public static extern bool EnumWindows(EnumWindowsCallBack lpEnumFunc, int lParam);
 24         [DllImport("User32.dll", CharSet = CharSet.Auto)]
 25         public static extern bool ReleaseCapture();
 26         [DllImport("user32.dll", CharSet = CharSet.Auto)]
 27         public static extern IntPtr SetCapture(IntPtr hWnd);
 28         [DllImport("user32.dll", CharSet = CharSet.Auto)]
 29         public static extern IntPtr ChildWindowFromPointEx(IntPtr hParent, POINT pt, ChildFromPointFlags flags);
 30         [DllImport("user32.dll", EntryPoint = "FindWindowExA", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
 31         public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
 32         [DllImport("user32.dll")]
 33         public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
 34         [DllImport("user32.dll", CharSet = CharSet.Auto)]
 35         public static extern int PostMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
 36         [DllImport("user32.dll", CharSet = CharSet.Auto)]
 37         public static extern int PostMessage(IntPtr hWnd, int msg, int wParam, int lParam);
 38         [DllImport("user32.dll", CharSet = CharSet.Auto)]
 39         public static extern int SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
 40         [DllImport("user32.dll", CharSet = CharSet.Auto)]
 41         public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
 42         [DllImport("user32.dll", CharSet = CharSet.Auto)]
 43         public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, StringBuilder param);
 44         [DllImport("user32.dll", CharSet = CharSet.Auto)]
 45         public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, char[] chars);
 46         [DllImport("user32.dll", CharSet = CharSet.Auto)]
 47         public static extern IntPtr BeginDeferWindowPos(int nNumWindows);
 48         [DllImport("user32.dll", CharSet = CharSet.Auto)]
 49         public static extern IntPtr DeferWindowPos(IntPtr hWinPosInfo, IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int Width, int Height, SetWindowPosFlags flags);
 50         [DllImport("user32.dll", CharSet = CharSet.Auto)]
 51         public static extern bool EndDeferWindowPos(IntPtr hWinPosInfo);
 52         [DllImport("user32.dll", CharSet = CharSet.Auto)]
 53         public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int Width, int Height, SetWindowPosFlags flags);
 54         [DllImport("user32.dll")]
 55         public static extern bool GetWindowRect(IntPtr hwnd, ref RECT rect);
 56         [DllImport("user32.dll")]
 57         public static extern bool GetClientRect(IntPtr hwnd, ref RECT rect);
 58         #endregion
 59     }
 60 
 61     #region SWP_Flags
 62     [Flags]
 63     public enum SWP_Flags
 64     {
 65         SWP_NOSIZE = 0x0001,
 66         SWP_NOMOVE = 0x0002,
 67         SWP_NOZORDER = 0x0004,
 68         SWP_NOACTIVATE = 0x0010,
 69         SWP_FRAMECHANGED = 0x0020, /* The frame changed: send WM_NCCALCSIZE */
 70         SWP_SHOWWINDOW = 0x0040,
 71         SWP_HIDEWINDOW = 0x0080,
 72         SWP_NOOWNERZORDER = 0x0200, /* Don't do owner Z ordering */
 73 
 74         SWP_DRAWFRAME = SWP_FRAMECHANGED,
 75         SWP_NOREPOSITION = SWP_NOOWNERZORDER
 76     }
 77     #endregion
 78 
 79     #region DialogChangeStatus
 80     public enum DialogChangeStatus : long
 81     {
 82         CDN_FIRST = 0xFFFFFDA7,
 83         CDN_INITDONE = (CDN_FIRST - 0x0000),
 84         CDN_SELCHANGE = (CDN_FIRST - 0x0001),
 85         CDN_FOLDERCHANGE = (CDN_FIRST - 0x0002),
 86         CDN_SHAREVIOLATION = (CDN_FIRST - 0x0003),
 87         CDN_HELP = (CDN_FIRST - 0x0004),
 88         CDN_FILEOK = (CDN_FIRST - 0x0005),
 89         CDN_TYPECHANGE = (CDN_FIRST - 0x0006),
 90     }
 91     #endregion
 92 
 93     #region DialogChangeProperties
 94     public enum DialogChangeProperties
 95     {
 96         CDM_FIRST = (0x400 + 100),
 97         CDM_GETSPEC = (CDM_FIRST + 0x0000),
 98         CDM_GETFILEPATH = (CDM_FIRST + 0x0001),
 99         CDM_GETFOLDERPATH = (CDM_FIRST + 0x0002),
100         CDM_GETFOLDERIDLIST = (CDM_FIRST + 0x0003),
101         CDM_SETCONTROLTEXT = (CDM_FIRST + 0x0004),
102         CDM_HIDECONTROL = (CDM_FIRST + 0x0005),
103         CDM_SETDEFEXT = (CDM_FIRST + 0x0006)
104     }
105     #endregion
106 
107     #region ImeNotify
108     public enum ImeNotify
109     {
110         IMN_CLOSESTATUSWINDOW = 0x0001,
111         IMN_OPENSTATUSWINDOW = 0x0002,
112         IMN_CHANGECANDIDATE = 0x0003,
113         IMN_CLOSECANDIDATE = 0x0004,
114         IMN_OPENCANDIDATE = 0x0005,
115         IMN_SETCONVERSIONMODE = 0x0006,
116         IMN_SETSENTENCEMODE = 0x0007,
117         IMN_SETOPENSTATUS = 0x0008,
118         IMN_SETCANDIDATEPOS = 0x0009,
119         IMN_SETCOMPOSITIONFONT = 0x000A,
120         IMN_SETCOMPOSITIONWINDOW = 0x000B,
121         IMN_SETSTATUSWINDOWPOS = 0x000C,
122         IMN_GUIDELINE = 0x000D,
123         IMN_PRIVATE = 0x000E
124     }
125     #endregion
126 
127     #region FolderViewMode
128     public enum FolderViewMode
129     {
130         Default = 0x7028,
131         Icon = Default + 1,
132         SmallIcon = Default + 2,
133         List = Default + 3,
134         Details = Default + 4,
135         Thumbnails = Default + 5,
136         Title = Default + 6,
137         Thumbstrip = Default + 7,
138     }
139     #endregion
140 
141     #region Enum DialogViewProperty
142     public enum DefaultViewType
143     {
144         Icons = 0x7029,
145         List = 0x702b,
146         Details = 0x702c,
147         Thumbnails = 0x702d,
148         Tiles = 0x702e,
149     }
150     #endregion
151 
152     #region ButtonStyle
153     public enum ButtonStyle : long
154     {
155         BS_PUSHBUTTON = 0x00000000,
156         BS_DEFPUSHBUTTON = 0x00000001,
157         BS_CHECKBOX = 0x00000002,
158         BS_AUTOCHECKBOX = 0x00000003,
159         BS_RADIOBUTTON = 0x00000004,
160         BS_3STATE = 0x00000005,
161         BS_AUTO3STATE = 0x00000006,
162         BS_GROUPBOX = 0x00000007,
163         BS_USERBUTTON = 0x00000008,
164         BS_AUTORADIOBUTTON = 0x00000009,
165         BS_PUSHBOX = 0x0000000A,
166         BS_OWNERDRAW = 0x0000000B,
167         BS_TYPEMASK = 0x0000000F,
168         BS_LEFTTEXT = 0x00000020,
169         BS_TEXT = 0x00000000,
170         BS_ICON = 0x00000040,
171         BS_BITMAP = 0x00000080,
172         BS_LEFT = 0x00000100,
173         BS_RIGHT = 0x00000200,
174         BS_CENTER = 0x00000300,
175         BS_TOP = 0x00000400,
176         BS_BOTTOM = 0x00000800,
177         BS_VCENTER = 0x00000C00,
178         BS_PUSHLIKE = 0x00001000,
179         BS_MULTILINE = 0x00002000,
180         BS_NOTIFY = 0x00004000,
181         BS_FLAT = 0x00008000,
182         BS_RIGHTBUTTON = BS_LEFTTEXT
183     }
184     #endregion
185 
186     #region ZOrderPos
187     public enum ZOrderPos
188     {
189         HWND_TOP = 0,
190         HWND_BOTTOM = 1,
191         HWND_TOPMOST = -1,
192         HWND_NOTOPMOST = -2
193     }
194     #endregion
195 
196     #region Static Control Styles
197     public enum StaticControlStyles : long
198     {
199         SS_LEFT = 0x00000000,
200         SS_CENTER = 0x00000001,
201         SS_RIGHT = 0x00000002,
202         SS_ICON = 0x00000003,
203         SS_BLACKRECT = 0x00000004,
204         SS_GRAYRECT = 0x00000005,
205         SS_WHITERECT = 0x00000006,
206         SS_BLACKFRAME = 0x00000007,
207         SS_GRAYFRAME = 0x00000008,
208         SS_WHITEFRAME = 0x00000009,
209         SS_USERITEM = 0x0000000A,
210         SS_SIMPLE = 0x0000000B,
211         SS_LEFTNOWORDWRAP = 0x0000000C,
212         SS_OWNERDRAW = 0x0000000D,
213         SS_BITMAP = 0x0000000E,
214         SS_ENHMETAFILE = 0x0000000F,
215         SS_ETCHEDHORZ = 0x00000010,
216         SS_ETCHEDVERT = 0x00000011,
217         SS_ETCHEDFRAME = 0x00000012,
218         SS_TYPEMASK = 0x0000001F,
219         SS_REALSIZECONTROL = 0x00000040,
220         SS_NOPREFIX = 0x00000080, /* Don't do "&" character translation */
221         SS_NOTIFY = 0x00000100,
222         SS_CENTERIMAGE = 0x00000200,
223         SS_RIGHTJUST = 0x00000400,
224         SS_REALSIZEIMAGE = 0x00000800,
225         SS_SUNKEN = 0x00001000,
226         SS_EDITCONTROL = 0x00002000,
227         SS_ENDELLIPSIS = 0x00004000,
228         SS_PATHELLIPSIS = 0x00008000,
229         SS_WORDELLIPSIS = 0x0000C000,
230         SS_ELLIPSISMASK = 0x0000C000
231     }
232     #endregion
233 
234     #region Combo Box styles
235     public enum ComboBoxStyles : long
236     {
237         CBS_SIMPLE = 0x0001,
238         CBS_DROPDOWN = 0x0002,
239         CBS_DROPDOWNLIST = 0x0003,
240         CBS_OWNERDRAWFIXED = 0x0010,
241         CBS_OWNERDRAWVARIABLE = 0x0020,
242         CBS_AUTOHSCROLL = 0x0040,
243         CBS_OEMCONVERT = 0x0080,
244         CBS_SORT = 0x0100,
245         CBS_HASSTRINGS = 0x0200,
246         CBS_NOINTEGRALHEIGHT = 0x0400,
247         CBS_DISABLENOSCROLL = 0x0800,
248         CBS_UPPERCASE = 0x2000,
249         CBS_LOWERCASE = 0x4000
250     }
251     #endregion
252 
253     #region Window Styles
254     public enum WindowStyles : long
255     {
256         WS_OVERLAPPED = 0x00000000,
257         WS_POPUP = 0x80000000,
258         WS_CHILD = 0x40000000,
259         WS_MINIMIZE = 0x20000000,
260         WS_VISIBLE = 0x10000000,
261         WS_DISABLED = 0x08000000,
262         WS_CLIPSIBLINGS = 0x04000000,
263         WS_CLIPCHILDREN = 0x02000000,
264         WS_MAXIMIZE = 0x01000000,
265         WS_CAPTION = 0x00C00000,
266         WS_BORDER = 0x00800000,
267         WS_DLGFRAME = 0x00400000,
268         WS_VSCROLL = 0x00200000,
269         WS_HSCROLL = 0x00100000,
270         WS_SYSMENU = 0x00080000,
271         WS_THICKFRAME = 0x00040000,
272         WS_GROUP = 0x00020000,
273         WS_TABSTOP = 0x00010000,
274         WS_MINIMIZEBOX = 0x00020000,
275         WS_MAXIMIZEBOX = 0x00010000,
276         WS_TILED = 0x00000000,
277         WS_ICONIC = 0x20000000,
278         WS_SIZEBOX = 0x00040000,
279         WS_POPUPWINDOW = 0x80880000,
280         WS_OVERLAPPEDWINDOW = 0x00CF0000,
281         WS_TILEDWINDOW = 0x00CF0000,
282         WS_CHILDWINDOW = 0x40000000
283     }
284     #endregion
285 
286     #region Window Extended Styles
287     public enum WindowExStyles
288     {
289         WS_EX_DLGMODALFRAME = 0x00000001,
290         WS_EX_NOPARENTNOTIFY = 0x00000004,
291         WS_EX_TOPMOST = 0x00000008,
292         WS_EX_ACCEPTFILES = 0x00000010,
293         WS_EX_TRANSPARENT = 0x00000020,
294         WS_EX_MDICHILD = 0x00000040,
295         WS_EX_TOOLWINDOW = 0x00000080,
296         WS_EX_WINDOWEDGE = 0x00000100,
297         WS_EX_CLIENTEDGE = 0x00000200,
298         WS_EX_CONTEXTHELP = 0x00000400,
299         WS_EX_RIGHT = 0x00001000,
300         WS_EX_LEFT = 0x00000000,
301         WS_EX_RTLREADING = 0x00002000,
302         WS_EX_LTRREADING = 0x00000000,
303         WS_EX_LEFTSCROLLBAR = 0x00004000,
304         WS_EX_RIGHTSCROLLBAR = 0x00000000,
305         WS_EX_CONTROLPARENT = 0x00010000,
306         WS_EX_STATICEDGE = 0x00020000,
307         WS_EX_APPWINDOW = 0x00040000,
308         WS_EX_OVERLAPPEDWINDOW = 0x00000300,
309         WS_EX_PALETTEWINDOW = 0x00000188,
310         WS_EX_LAYERED = 0x00080000
311     }
312     #endregion
313 
314     #region ChildFromPointFlags
315     public enum ChildFromPointFlags
316     {
317         CWP_ALL = 0x0000,
318         CWP_SKIPINVISIBLE = 0x0001,
319         CWP_SKIPDISABLED = 0x0002,
320         CWP_SKIPTRANSPARENT = 0x0004
321     }
322     #endregion
323 
324     #region HitTest
325     public enum HitTest
326     {
327         HTERROR = (-2),
328         HTTRANSPARENT = (-1),
329         HTNOWHERE = 0,
330         HTCLIENT = 1,
331         HTCAPTION = 2,
332         HTSYSMENU = 3,
333         HTGROWBOX = 4,
334         HTSIZE = HTGROWBOX,
335         HTMENU = 5,
336         HTHSCROLL = 6,
337         HTVSCROLL = 7,
338         HTMINBUTTON = 8,
339         HTMAXBUTTON = 9,
340         HTLEFT = 10,
341         HTRIGHT = 11,
342         HTTOP = 12,
343         HTTOPLEFT = 13,
344         HTTOPRIGHT = 14,
345         HTBOTTOM = 15,
346         HTBOTTOMLEFT = 16,
347         HTBOTTOMRIGHT = 17,
348         HTBORDER = 18,
349         HTREDUCE = HTMINBUTTON,
350         HTZOOM = HTMAXBUTTON,
351         HTSIZEFIRST = HTLEFT,
352         HTSIZELAST = HTBOTTOMRIGHT,
353         HTOBJECT = 19,
354         HTCLOSE = 20,
355         HTHELP = 21
356     }
357     #endregion
358 
359     #region Windows Messages
360     public enum Msg
361     {
362         WM_NULL = 0x0000,
363         WM_CREATE = 0x0001,
364         WM_DESTROY = 0x0002,
365         WM_MOVE = 0x0003,
366         WM_SIZE = 0x0005,
367         WM_ACTIVATE = 0x0006,
368         WM_SETFOCUS = 0x0007,
369         WM_KILLFOCUS = 0x0008,
370         WM_ENABLE = 0x000A,
371         WM_SETREDRAW = 0x000B,
372         WM_SETTEXT = 0x000C,
373         WM_GETTEXT = 0x000D,
374         WM_GETTEXTLENGTH = 0x000E,
375         WM_PAINT = 0x000F,
376         WM_CLOSE = 0x0010,
377         WM_QUERYENDSESSION = 0x0011,
378         WM_QUIT = 0x0012,
379         WM_QUERYOPEN = 0x0013,
380         WM_ERASEBKGND = 0x0014,
381         WM_SYSCOLORCHANGE = 0x0015,

382         WM_ENDSESSION = 0x0016,
383         WM_SHOWWINDOW = 0x0018,
384         WM_CTLCOLOR = 0x0019,
385         WM_WININICHANGE = 0x001A,
386         WM_SETTINGCHANGE = 0x001A,
387         WM_DEVMODECHANGE = 0x001B,
388         WM_ACTIVATEAPP = 0x001C,
389         WM_FONTCHANGE = 0x001D,
390         WM_TIMECHANGE = 0x001E,
391         WM_CANCELMODE = 0x001F,
392         WM_SETCURSOR = 0x0020,
393         WM_MOUSEACTIVATE = 0x0021,
394         WM_CHILDACTIVATE = 0x0022,
395         WM_QUEUESYNC = 0x0023,
396         WM_GETMINMAXINFO = 0x0024,
397         WM_PAINTICON = 0x0026,
398         WM_ICONERASEBKGND = 0x0027,
399         WM_NEXTDLGCTL = 0x0028,
400         WM_SPOOLERSTATUS = 0x002A,
401         WM_DRAWITEM = 0x002B,
402         WM_MEASUREITEM = 0x002C,
403         WM_DELETEITEM = 0x002D,
404         WM_VKEYTOITEM = 0x002E,
405         WM_CHARTOITEM = 0x002F,
406         WM_SETFONT = 0x0030,
407         WM_GETFONT = 0x0031,
408         WM_SETHOTKEY = 0x0032,
409         WM_GETHOTKEY = 0x0033,
410         WM_QUERYDRAGICON = 0x0037,
411         WM_COMPAREITEM = 0x0039,
412         WM_GETOBJECT = 0x003D,
413         WM_COMPACTING = 0x0041,
414         WM_COMMNOTIFY = 0x0044,
415         WM_WINDOWPOSCHANGING = 0x0046,
416         WM_WINDOWPOSCHANGED = 0x0047,
417         WM_POWER = 0x0048,
418         WM_COPYDATA = 0x004A,
419         WM_CANCELJOURNAL = 0x004B,
420         WM_NOTIFY = 0x004E,
421         WM_INPUTLANGCHANGEREQUEST = 0x0050,
422         WM_INPUTLANGCHANGE = 0x0051,
423         WM_TCARD = 0x0052,
424         WM_HELP = 0x0053,
425         WM_USERCHANGED = 0x0054,
426         WM_NOTIFYFORMAT = 0x0055,
427         WM_CONTEXTMENU = 0x007B,
428         WM_STYLECHANGING = 0x007C,
429         WM_STYLECHANGED = 0x007D,
430         WM_DISPLAYCHANGE = 0x007E,
431         WM_GETICON = 0x007F,
432         WM_SETICON = 0x0080,
433         WM_NCCREATE = 0x0081,
434         WM_NCDESTROY = 0x0082,
435         WM_NCCALCSIZE = 0x0083,
436         WM_NCHITTEST = 0x0084,
437         WM_NCPAINT = 0x0085,
438         WM_NCACTIVATE = 0x0086,
439         WM_GETDLGCODE = 0x0087,
440         WM_SYNCPAINT = 0x0088,
441         WM_NCMOUSEMOVE = 0x00A0,
442         WM_NCLBUTTONDOWN = 0x00A1,
443         WM_NCLBUTTONUP = 0x00A2,
444         WM_NCLBUTTONDBLCLK = 0x00A3,
445         WM_NCRBUTTONDOWN = 0x00A4,
446         WM_NCRBUTTONUP = 0x00A5,
447         WM_NCRBUTTONDBLCLK = 0x00A6,
448         WM_NCMBUTTONDOWN = 0x00A7,
449         WM_NCMBUTTONUP = 0x00A8,
450         WM_NCMBUTTONDBLCLK = 0x00A9,
451         WM_NCXBUTTONDOWN = 0x00AB,
452         WM_NCXBUTTONUP = 0x00AC,
453         WM_NCXBUTTONDBLCLK = 0x00AD,
454         WM_KEYDOWN = 0x0100,
455         WM_KEYUP = 0x0101,
456         WM_CHAR = 0x0102,
457         WM_DEADCHAR = 0x0103,
458         WM_SYSKEYDOWN = 0x0104,
459         WM_SYSKEYUP = 0x0105,
460         WM_SYSCHAR = 0x0106,
461         WM_SYSDEADCHAR = 0x0107,
462         WM_KEYLAST = 0x0108,
463         WM_IME_STARTCOMPOSITION = 0x010D,
464         WM_IME_ENDCOMPOSITION = 0x010E,
465         WM_IME_COMPOSITION = 0x010F,
466         WM_IME_KEYLAST = 0x010F,
467         WM_INITDIALOG = 0x0110,
468         WM_COMMAND = 0x0111,
469         WM_SYSCOMMAND = 0x0112,
470         WM_TIMER = 0x0113,
471         WM_HSCROLL = 0x0114,
472         WM_VSCROLL = 0x0115,
473         WM_INITMENU = 0x0116,
474         WM_INITMENUPOPUP = 0x0117,
475         WM_MENUSELECT = 0x011F,
476         WM_MENUCHAR = 0x0120,
477         WM_ENTERIDLE = 0x0121,
478         WM_MENURBUTTONUP = 0x0122,
479         WM_MENUDRAG = 0x0123,
480         WM_MENUGETOBJECT = 0x0124,
481         WM_UNINITMENUPOPUP = 0x0125,
482         WM_MENUCOMMAND = 0x0126,
483         WM_CTLCOLORMSGBOX = 0x0132,
484         WM_CTLCOLOREDIT = 0x0133,
485         WM_CTLCOLORLISTBOX = 0x0134,
486         WM_CTLCOLORBTN = 0x0135,
487         WM_CTLCOLORDLG = 0x0136,
488         WM_CTLCOLORSCROLLBAR = 0x0137,
489         WM_CTLCOLORSTATIC = 0x0138,
490         WM_MOUSEMOVE = 0x0200,
491         WM_LBUTTONDOWN = 0x0201,
492         WM_LBUTTONUP = 0x0202,
493         WM_LBUTTONDBLCLK = 0x0203,
494         WM_RBUTTONDOWN = 0x0204,
495         WM_RBUTTONUP = 0x0205,
496         WM_RBUTTONDBLCLK = 0x0206,
497         WM_MBUTTONDOWN = 0x0207,
498         WM_MBUTTONUP = 0x0208,
499         WM_MBUTTONDBLCLK = 0x0209,
500         WM_MOUSEWHEEL = 0x020A,
501         WM_XBUTTONDOWN = 0x020B,
502         WM_XBUTTONUP = 0x020C,
503         WM_XBUTTONDBLCLK = 0x020D,
504         WM_PARENTNOTIFY = 0x0210,
505         WM_ENTERMENULOOP = 0x0211,
506         WM_EXITMENULOOP = 0x0212,
507         WM_NEXTMENU = 0x0213,
508         WM_SIZING = 0x0214,
509         WM_CAPTURECHANGED = 0x0215,
510         WM_MOVING = 0x0216,
511         WM_DEVICECHANGE = 0x0219,
512         WM_MDICREATE = 0x0220,
513         WM_MDIDESTROY = 0x0221,
514         WM_MDIACTIVATE = 0x0222,
515         WM_MDIRESTORE = 0x0223,
516         WM_MDINEXT = 0x0224,
517         WM_MDIMAXIMIZE = 0x0225,
518         WM_MDITILE = 0x0226,
519         WM_MDICASCADE = 0x0227,
520         WM_MDIICONARRANGE = 0x0228,
521         WM_MDIGETACTIVE = 0x0229,
522         WM_MDISETMENU = 0x0230,
523         WM_ENTERSIZEMOVE = 0x0231,
524         WM_EXITSIZEMOVE = 0x0232,
525         WM_DROPFILES = 0x0233,
526         WM_MDIREFRESHMENU = 0x0234,
527         WM_IME_SETCONTEXT = 0x0281,
528         WM_IME_NOTIFY = 0x0282,
529         WM_IME_CONTROL = 0x0283,
530         WM_IME_COMPOSITIONFULL = 0x0284,
531         WM_IME_SELECT = 0x0285,
532         WM_IME_CHAR = 0x0286,
533         WM_IME_REQUEST = 0x0288,
534         WM_IME_KEYDOWN = 0x0290,
535         WM_IME_KEYUP = 0x0291,
536         WM_MOUSEHOVER = 0x02A1,
537         WM_MOUSELEAVE = 0x02A3,
538         WM_CUT = 0x0300,
539         WM_COPY = 0x0301,
540         WM_PASTE = 0x0302,
541         WM_CLEAR = 0x0303,
542         WM_UNDO = 0x0304,
543         WM_RENDERFORMAT = 0x0305,
544         WM_RENDERALLFORMATS = 0x0306,
545         WM_DESTROYCLIPBOARD = 0x0307,
546         WM_DRAWCLIPBOARD = 0x0308,
547         WM_PAINTCLIPBOARD = 0x0309,
548         WM_VSCROLLCLIPBOARD = 0x030A,
549         WM_SIZECLIPBOARD = 0x030B,
550         WM_ASKCBFORMATNAME = 0x030C,
551         WM_CHANGECBCHAIN = 0x030D,
552         WM_HSCROLLCLIPBOARD = 0x030E,
553         WM_QUERYNEWPALETTE = 0x030F,
554         WM_PALETTEISCHANGING = 0x0310,
555         WM_PALETTECHANGED = 0x0311,
556         WM_HOTKEY = 0x0312,
557         WM_PRINT = 0x0317,
558         WM_PRINTCLIENT = 0x0318,
559         WM_THEME_CHANGED = 0x031A,
560         WM_HANDHELDFIRST = 0x0358,
561         WM_HANDHELDLAST = 0x035F,
562         WM_AFXFIRST = 0x0360,
563         WM_AFXLAST = 0x037F,
564         WM_PENWINFIRST = 0x0380,
565         WM_PENWINLAST = 0x038F,
566         WM_APP = 0x8000,
567         WM_USER = 0x0400,
568         WM_REFLECT = WM_USER + 0x1c00
569     }
570     #endregion
571 
572     #region SetWindowPosFlags
573     public enum SetWindowPosFlags
574     {
575         SWP_NOSIZE = 0x0001,
576         SWP_NOMOVE = 0x0002,
577         SWP_NOZORDER = 0x0004,
578         SWP_NOREDRAW = 0x0008,
579         SWP_NOACTIVATE = 0x0010,
580         SWP_FRAMECHANGED = 0x0020,
581         SWP_SHOWWINDOW = 0x0040,
582         SWP_HIDEWINDOW = 0x0080,
583         SWP_NOCOPYBITS = 0x0100,
584         SWP_NOOWNERZORDER = 0x0200,
585         SWP_NOSENDCHANGING = 0x0400,
586         SWP_DRAWFRAME = 0x0020,
587         SWP_NOREPOSITION = 0x0200,
588         SWP_DEFERERASE = 0x2000,
589         SWP_ASYNCWINDOWPOS = 0x4000
590     }
591     #endregion
592 }
593 
594     #region WINDOWINFO
595     [StructLayout(LayoutKind.Sequential)]
596     public struct WINDOWINFO
597     {
598         public UInt32 cbSize;
599         public RECT rcWindow;
600         public RECT rcClient;
601         public UInt32 dwStyle;
602         public UInt32 dwExStyle;
603         public UInt32 dwWindowStatus;
604         public UInt32 cxWindowBorders;
605         public UInt32 cyWindowBorders;
606         public UInt16 atomWindowType;
607         public UInt16 wCreatorVersion;
608     }
609     #endregion
610 
611     #region POINT
612     [StructLayout(LayoutKind.Sequential)]
613     public struct POINT
614     {
615         public int x;
616         public int y;
617 
618         #region Constructors
619         public POINT(int x, int y)
620         {
621             this.x = x;
622             this.y = y;
623         }
624 
625         public POINT(Point point)
626         {
627             x = point.X;
628             y = point.Y;
629         }
630         #endregion
631     }
632     #endregion
633 
634     #region RECT
635     [StructLayout(LayoutKind.Sequential)]
636     public struct RECT
637     {
638         public uint left;
639         public uint top;
640         public uint right;
641         public uint bottom;
642 
643         #region Properties
644         public POINT Location
645         {
646             get { return new POINT((int)left, (int)top); }
647             set
648             {
649                 right -= (left - (uint)value.x);
650                 bottom -= (bottom - (uint)value.y);
651                 left = (uint)value.x;
652                 top = (uint)value.y;
653             }
654         }
655 
656         public uint Width
657         {
658             get { return right - left; }
659             set { right = left + value; }
660         }
661 
662         public uint Height
663         {
664             get { return bottom - top; }
665             set { bottom = top + value; }
666         }
667         #endregion
668 
669         #region Overrides
670         public override string ToString()
671         {
672             return left + ":" + top + ":" + right + ":" + bottom;
673         }
674         #endregion
675     }
676     #endregion
677 
678     #region WINDOWPOS
679     [StructLayout(LayoutKind.Sequential)]
680     public struct WINDOWPOS
681     {
682         public IntPtr hwnd;
683         public IntPtr hwndAfter;
684         public int x;
685         public int y;
686         public int cx;
687         public int cy;
688         public uint flags;
689 
690         #region Overrides
691         public override string ToString()
692         {
693             return x + ":" + y + ":" + cx + ":" + cy + ":" + ((SWP_Flags)flags).ToString();
694         }
695         #endregion
696     }
697     #endregion
698 
699     #region NCCALCSIZE_PARAMS
700     [StructLayout(LayoutKind.Sequential)]
701     public struct NCCALCSIZE_PARAMS
702     {
703         public RECT rgrc1;
704         public RECT rgrc2;
705         public RECT rgrc3;
706         public IntPtr lppos;
707     }
708     #endregion
709 
710     #region NMHDR
711     [StructLayout(LayoutKind.Sequential)]
712     public struct NMHDR
713     {
714         public IntPtr hwndFrom;
715         public uint idFrom;
716         public uint code;
717     }
718     #endregion
719 
720     #region OFNOTIFY
721     [StructLayout(LayoutKind.Sequential)]
722     public struct OFNOTIFY
723     {
724         public NMHDR hdr;
725         public IntPtr OPENFILENAME;
726         public IntPtr fileNameShareViolation;
727     }
728     #endregion

复制代码

补充一下

1.代码只提供思路,不能拿来继承一下,就能实现自己想要的功能。

2.可以自己将代码中DialogNativeWindow类的addControl替换为其他控件,比如PictureBox用来预览图片、TextBox用来预览txt文件、RichTextBox用来预览代码文件等等,还可自由组合。

3.可以自己将代码中DialogNativeWindow类的两个事件(SelectedFileChanged、SelectPathChanged)移到MultiOpenFileDialog中,并使其对外开放,外部程序可以监听该事件。

4.如果想做成通用类,拿过来继承一下就可以实现自己想要的效果,建议使MultiOpenFileDialog从UserControl,并将addControl设为自己。也就是说将自己添加到OpenFileDialog中去,MultiOpenFileDialog的派生类就可以在VS中设计自己想要的效果。

5.一个窗体新建显示时,它的拥有者会接收许多消息,包括WM_ACTIVATE、WM_IDLE等等,并且Lparam参数为新建窗体的句柄。

View Code

复制代码

 1 class Form1:Form
 2 {
 3       private void Form1_Load(Object sender,EventArgs e)
 4       {
 5              using(OpenFileDialog dia = new OpenFileDialog())
 6              {
 7                     dia.ShowDialog(this);
 8              }
 9       }
10       protected override void WndProc(ref Message m)
11      {
12              //当dia显示时,它的拥有者即为this,这里会接受一连串的Window消息,并且它的Lparam参数为dia的句柄
13             base.WndProc(ref m);
14      }
15 }

复制代码

6.Windows中窗体和所谓的控件(button、textbox)本质上没有区别,任务栏与QQ聊天框或者Chrome浏览器的地址栏对我们程序员来讲,是同一个东西。

7.与窗体有关的Win32 API基本都需要窗体句柄,其实任何一个API几乎都需要知道操作对象的句柄(不一定是窗体)。

8.Windows中任何一个窗体(控件)理论上都是平级的,不管是否同一进程,也就是说,我的winform应用程序只要知道了Chrome浏览器窗体的句柄,就可以控制Chrome浏览器,监听Chrome窗体的Windows消息(除非Chrome程序本身禁止了此操作)。

9.Windows桌面应用程序开发中,(部分平台、语言)理解四个东西,即进程、线程 、窗体(已经说了,是广义上的窗体)、消息。

10.查看系统中以上四个东西,可以使用Spy++工具。

猜你喜欢

转载自blog.csdn.net/vera514514/article/details/8551653