C#调用Windows API总结

来源:互联网 发布:openjdk源码下载 编辑:程序博客网 时间:2024/05/16 19:01

==================comaple 2010-12-04=====================
       客户突然提出了一个应用,然我措手不及。经过两天的奋战终于得到彻底解决以下是我的经历和一些经验。写出来以作总结,同时也可分享给有需要的朋友,不要走弯路。相信对你一定有很大的帮助。
=================================================================
功能描述:要实现我们的程序控制其他程序的窗口隐藏和显示,以减少窗口的复杂度。
==============================================================
       解决过程分解:
===============起初的设想是================================
1,利用.NET提供的Process类提供的GetProcessesByName方法来获得你要得到的窗口的进程信息,===>之后根据process类的属性获得该进程的主窗口线程的句柄,然后调用Windows API来实现控制其他窗口程序。
2,C#调用Windows api方法,通过托管代码调用非托管代码要利用.NET的DllImportAttribute特性关于特性的叙述我在这里就不多说了,有兴趣的朋友可以查阅相关资料,推荐书籍C#高级编程第六版(清华大学出版社)===>第十三章反射 ===> 定制特性www.worx.com上有源码下载。特性的具体用法是:比如你要调用Windows 32 的User32.dll可以这样来用写,以下贴一些源代码来诠释:
 /*EntryPoint 即你要调用的API函数,函数名必须写正确,负责clr是找不到的 函数的定义可以和EntryPoint 的名字不一样,但一般都一样为了方便记忆和使用,使用是跟一般的函数使用一样即可*/
[DllImport("kernel32.dll", EntryPoint = "WinExec")]
        public static extern int WinExec(string lpCmdLine, int nCmdShow);
3,在调用API函数时定义的本地函的参数类型如何确定:

<1>、数值型直接用对应的就可。(DWORD -> int , WORD -> Int16)

<2>、API中字符串指针类型 -> .net中string

<3>、API中句柄 (dWord | hWnd ) -> .net中IntPtr
 这里只是一部分如果你要查看详细的对应关系和如何映射请参考这个连接是一个博客写的,个人认为已经足够用了一下是连接
http://www.yesky.com/106/1880106.shtml
4,下面接着将所调用的API函数,具体有
    [DllImport("user32.dll", EntryPoint = "ShowWindow", SetLastError = true)]
        static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow);
该函数的用法是:hWnd是指你要控制的窗口的句柄,nCmdShow是控制参数0表示将图标从任务栏隐藏到系统托盘1表示将窗口从任务栏最大化并改变活动状态2表示把窗口最小化到任务栏图标4最大化不改变活动状态
5,遇到的问题===>这种方式可以是窗口以藏掉,但是找不回来了,就是隐藏了就无法在显示了,是API的问题么,答案是否定的。那肯定是.NET的问题,打开程序一步一步调试这才发现,第一调用Process.GetProcesses();时从获得的进程信息里可以找到,你要的窗口句柄,但当你隐藏了以后就会发现这是在调用次函数获得的进程还是那个进程但不同的是这时的窗口句柄为0就没有窗口句柄。所以无法把隐藏掉的窗口再次打开。那么我们可不可以把第一调用此函时的句柄值保存下来当需要显示的直接用就是了。按照这个思路调试成功。
============新的问题=======================================
6,当用户自己隐藏了窗口时在想把他通过我们的程序调出来,我们的程序就束手无策了。
=====================解决=====================
分析:.NET是托管的资源管理运行的代码的。在.net中定义的process 和thread 只有当start()时clr才会在任务管理器里映射一个进程出来。否则无法找到我们的进程,就是说当我们把窗口隐藏掉以后窗口的线程就成为后台线程实际没有运行。所以我们的.NET认为我们第二次找到的进程没有主窗口。即主窗口句柄为0,那么既然这样我们该如何解决呢,查看API函数发现新的解决方案。
=======================解决方案============================

利用      [DllImport("User32.dll", EntryPoint = "FindWindow")]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
这个函数的用法是:lpClassName就运行这个窗口的类库,这个不好确定,因为对方的开发语言我们都不好知晓,所以这一项为空,即NULL,lpWindowName是你要查找的窗口名称。这个不能为空。
结果顺利解决上面的问题。
======================下一步完善============================
利用API里的EnumWindows(myCallBack, lbCurProcess.Handle.ToInt32());方法把当Windows打开的所有包括前台和后台的窗口全部枚举出来,在通过showwindow()改变他们的显示属性。
=========================进一步研究====================
其实我们可以通过远程过程调用来达到动态创建线程,并挂接到远程进程执行。这样就更加方便了,这就是线程注入技术。