今天下午在回复longware的反馈问题时,发现的FindWindow 、FindWindowEX、SendMessage等部分WIN32 API在WIN 7下某些情况下会失效的问题。
发现过程是:longware网友反馈我《屏幕录像功能技术探索及分享 》里的实验程序在WIN 7下无法正常结束屏幕录像进程。经过我调试测试后,发现程序里调用的FindWindow无法获取到camstudio_cl.exe进程的句柄(返回0)。
表面原因:录制视频方法里,
//不创建进程窗口
p.StartInfo.CreateNoWindow = true;
在VISTA/WIN 7下 FindWindow或FindWindowEX无法获取到窗体句柄,所以无法发消息来结束进程。
理论原因:
Impact of Session 0 Isolation on Services and Drivers in Windows
来源http://www.microsoft.com/whdc/system/sysinternals/Session0Changes.mspx
In Windows XP, Windows Server 2003, and earlier versions of Windows, all services run in Session 0 along with applications. This situation poses a security risk. In Windows Vista, Windows Server 2008, and later versions of Windows, the operating system isolates services in Session 0 and runs applications in other sessions, so services are protected from attacks that originate in application code.
This paper describes changes to the way in which services are run. It provides guidelines for developers to modify application services and driver services to run in Windows Vista, Windows Server 2008, and later versions of Windows.
This information applies to the following operating systems:
Windows 7
Windows Server 2008 R2
Windows Server 2008
Windows Vista
理论上原因大意为:在VISTA之前的操作系统中(如XP/ WIN SERVER 2003等),所有的服务线程和应用程序都在Session 0里运行,这种方式具有安全风险,Vista/win7之后的操作系统隔离了服务和应用程序,这样服务就可以免于潜在的来自这应用程序代码的攻击。
我理解时,在WIN 7里当不创建窗体的程序进程,会被认为是服务,从而运行于Session 0里。所以,应用程序调用FindWindow方法也就无法获取进程的窗体句柄啦。
解决方法:
经过我试验,
1) “ [DllImport("kernel32.dll",SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr GetConsoleWindow();” 是无法解决问题的,同样无法获取句柄。
2) FindWindowEX代替FindWindow同样无法解决问题
3)只能在WIN 7下允许录制视频时创建窗体的情况下,p.StartInfo.CreateNoWindow = false;才能获取进程窗体句柄,进而结束录制进程。目前没找到更好的方法。
另外知识点:向外部程序中发送键盘按键值
1.首先启动进程, Process.Start("mspaint.exe","C:\\1.jpg");
2.然后激活画图程序
3.然后向改进程发送CTRL+S按键:SendKeys.Send("^S");
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr FindWindow(string className, string windowName);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern bool IsIconic(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern bool OpenIcon(IntPtr hWnd);
private void button1_Click(object sender, EventArgs e)
{
Process.Start("mspaint.exe");
IntPtr handle = FindWindow(null, "未命名 - 画图");
if (handle != IntPtr.Zero)
{
if (IsIconic(handle))
{
OpenIcon(handle);
}
else
{
SetForegroundWindow(handle);
}
}
SendKeys.Send("%{F4}");
}
---------回复--------------
保证可用~接分...先打开最小化,然后active,然后置顶!!!
C# code
[DllImport("user32.dll")] static extern IntPtr SetActiveWindow(IntPtr hWnd); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] static extern bool OpenIcon(IntPtr hWnd); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] static extern bool SetForegroundWindow(IntPtr hWnd); public static void GetMainWindow(string proName) { Process[] pros = Process.GetProcessesByName(proName.Trim()); if (pros.Length != 0) { IntPtr pGame = pros[0].MainWindowHandle; OpenIcon(pGame); SetActiveWindow(pGame); SetForegroundWindow(pGame); Thread.Sleep(2000); } else { Console.WriteLine("Can't get the Main Window."); } }
参考:
与我遇到相似的问题http://stackoverflow.com/questions/340122/findwindow-fails-from-service-application
http://www.experts-exchange.com/Programming/Programming_Languages/C_Sharp/Q_21590318.html
http://www.khgl.cn/html/82/n-895082.html
本博客声明:本人的技术探索过程中,得到了国信司南公司方面物质和精神支持。今后,本人博客里的所有技术探索成果将归“无痕客”、“国信司南”和“博客园”三方共同所有,原创作品如需转载,请注明本博客声明。