确保生成的进程的窗口在主应用程序的前面?

确保生成的进程的窗口在主应用程序的前面?,第1张

概述确保生成进程的窗口在主应用程序的前面?

在我的GUI应用程序中,我使用C# Process类生成可能启动窗口的外部进程。 subprocess窗口可能通过第三方API调用显示,所以并不总是可以得到窗口句柄。 有没有办法确保subprocess的窗口显示在主应用程序窗口的前面?

计划基于sql表时间戳的.exe执行

各种剪贴板/拖放格式是什么意思?

System.Serializable属性在windows 10 UWP应用程序?

DoD CAC身份valIDation – .NET C#的客户端证书问题,windows Server 2008 R2,IIS 7.5

C#更改非Unicode语言或更改位置

通常的方法是:

1。 获取Process.Start()返回的Process类实例


2。 查询Process.MainWindowHandle


3。 调用非托管Win32 API函数“ShowWindow”或“SwitchToThisWindow”

你的问题的诀窍是“子流程窗口可能通过第三方API调用显示”。 在这种情况下,您将需要获取生成的EXE和Enum子窗口的窗口句柄。 一旦你有API调用后显示的窗体句柄,你可以使用BringWindowTotop API 。

我使用WIN32 API作为启发,使用“ 如何枚举windows”进行小测试。 使用1个窗体和2个按钮创建一个windows应用程序:

public partial class Form1 : Form { [Dllimport("user32.dll",SetLastError = true)] static extern bool BringWindowTotop(IntPtr hWnd); [Dllimport("user32")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool EnumChildwindows(IntPtr window,EnumWindowProc callback,IntPtr i); public Form1() { InitializeComponent(); } private system.intPtr hWnd; private voID button1_Click(object sender,EventArgs e) { Process p = Process.Start(@"C:TFSSandBox3rdPartyAppExample.exe"); try { do { p.Refresh(); } while (p.MainWindowHandle.ToInt32() == 0); hWnd = new IntPtr(p.MainWindowHandle.ToInt32()); } catch (Exception ex) { //Do some stuff... throw; } } private voID button2_Click(object sender,EventArgs e) { 3rdPartyAppExample.Form1 f = new 3rdPartyAppExample.Form1(); f.ShowForm2(); //Bring main external exe window to front BringWindowTotop(hWnd); //Bring child external exe windows to front BringExternalExeChildwindowsToFront(hWnd); } private voID BringExternalExeChildwindowsToFront(IntPtr parent) { List<IntPtr> childwindows = GetChildwindows(hWnd); foreach (IntPtr chilDWindow in childwindows) { BringWindowTotop(chilDWindow); } } // <summary> /// Returns a List of child windows /// </summary> /// <param name="parent">Parent of the windows to return</param> /// <returns>List of child windows</returns> public static List<IntPtr> GetChildwindows(IntPtr parent) { List<IntPtr> result = new List<IntPtr>(); GCHandle ListHandle = GCHandle.Alloc(result); try { EnumWindowProc childProc = new EnumWindowProc(EnumWindow); EnumChildwindows(parent,childProc,GCHandle.ToIntPtr(ListHandle)); } finally { if (ListHandle.IsAllocated) ListHandle.Free(); } return result; } /// <summary> /// Callback method to be used when enumerating windows. /// </summary> /// <param name="handle">Handle of the next window</param> /// <param name="pointer">Pointer to a GCHandle that holds a reference to the List to fill</param> /// <returns>True to continue the enumeration,false to bail</returns> private static bool EnumWindow(IntPtr handle,IntPtr pointer) { GCHandle gch = GCHandle.FromIntPtr(pointer); List<IntPtr> List = gch.Target as List<IntPtr>; if (List == null) { throw new InvalIDCastException("GCHandle Target Could not be cast as List<IntPtr>"); } List.Add(handle); // You can modify this to check to see if you want to cancel the operation,then return a null here return true; } /// <summary> /// Delegate for the EnumChildwindows method /// </summary> /// <param name="hWnd">Window handle</param> /// <param name="parameter">Caller-defined variable; we use it for a pointer to our List</param> /// <returns>True to continue enumerating,false to bail.</returns> public delegate bool EnumWindowProc(IntPtr hWnd,IntPtr parameter); }

3rdPartyAppExample是一个带有两种形式的Winform应用程序。 我引用这个应用程序并调用Form1的Public方法来显示Form2:

public partial class Form1 : Form { public Form1() { InitializeComponent(); } public voID ShowForm2() { var f = new Form2(); f.Show(); }

或者,您可能希望检查windows标题 :

hInst = Processstart("calc.exe") // Begin search for handle hWndApp = GetWinHandle(hInst) If hWndApp <> 0 Then // Init buffer buffer = Space$(128) // Get caption of window numChars = GetwindowText(hWndApp,buffer,Len(buffer))

另一个解决方案(这不是很稳定)在这里讨论: http : //www.shloemi.com/2012/09/solved-setforegrounDWindow-win32-API-not-always-works/

诀窍是使windows“认为”我们的进程和目标窗口(hwnd)通过附加线程(使用AttachThreadinput API)相关联。

关于mytopForm.topMost = true答案,这不适用于外部应用程序。

这与“流程”无关,而与windows关注的一切无关。

你也许可以做这样的事情:

http://msdn.microsoft.com/en-us/library/3saxwsad.aspx

public voID MakeOntop() { mytopForm.topMost = true; }

但总的来说,你需要Window句柄(生成的过程可以很容易地找出自己的句柄),你需要这样的东西:

http://support.microsoft.com/kb/186431

你可以尝试使用SetwindowPos API调用窗口到窗口的z命令的返回。

http://msdn.microsoft.com/en-us/library/windows/desktop/ms633545(v=vs.85).aspx

[Dllimport("user32.dll",EntryPoint = "SetwindowPos")] public static extern IntPtr SetwindowPos(IntPtr hWnd,int hWndInsertAfter,int x,int Y,int cx,int cy,uint wFlags); const UInt32 SWP_NOSIZE = 0x0001; const UInt32 SWP_NOMOVE = 0x0002; static Readonly IntPtr HWND_BottOM = new IntPtr(1); static voID SenDWindowBack() { var hWnd = this.Handle; SetwindowPos(hWnd,HWND_BottOM,SWP_NOSIZE | SWP_NOMOVE); }

(几个编辑用于winforms而不是wpf)

没有直接和100%可靠的方法来做到这一点。 我会以一种有点迂回的方式去解决这个问题:

获取您启动的进程的进程ID,然后使用C#相当于Enumwindows函数。 在回调中,调用GetwindowThreadProcessID来获取窗口的进程ID,并将其与刚刚启动的窗口的进程ID进行比较。 如果它们匹配,那么可以使用SetForegrounDWindow将该窗口置于前台。

如果有问题的应用程序显示多个顶级窗口,则会找到第一个,这可能不是正确的。 但在应用程序缺乏一些“合作”的情况下,我认为我所概括的是你可以做的最好的。

总结

以上是内存溢出为你收集整理的确保生成的进程的窗口在主应用程序的前面?全部内容,希望文章能够帮你解决确保生成的进程的窗口在主应用程序的前面?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1291879.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-10
下一篇 2022-06-10

发表评论

登录后才能评论

评论列表(0条)

保存