所以我做了一个win应用程序,每当我打开"页面设置"时,我都希望它能在屏幕前弹出。从记事本中,每当我关闭记事本时关闭它。
我试过了:
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static extern IntPtr GetParent(IntPtr hWnd);
[DllImport("User32", CharSet = CharSet.Auto)]
public static extern int ShowWindow(IntPtr hWnd, int cmdShow);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsIconic(IntPtr hwnd);
[DllImport("user32.dll")]
public static extern int SetForegroundWindow(IntPtr hWnd);
ManagementEventWatcher watcher;
public Form1()
{
InitializeComponent();
var query = new WqlEventQuery("SELECT * FROM Win32_ProcessStartTrace WHERE ProcessName = 'Notepad.exe'");
var mew = new ManagementEventWatcher(query) { Query = query };
mew.EventArrived += (sender, args) => { AppStarted(); };
mew.Start();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
watcher = new ManagementEventWatcher("Select * From Win32_ProcessStopTrace");
watcher.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);
watcher.Start();
}
protected override void OnFormClosed(FormClosedEventArgs e)
{
watcher.Stop();
watcher.Dispose();
base.OnFormClosed(e);
}
void watcher_EventArrived(object sender, EventArrivedEventArgs e)
{
// var _windowHandle = FindWindow(null, "Page Setup");
if ((string)e.NewEvent["ProcessName"] == "notepad.exe")
{
Invoke((MethodInvoker)delegate
{
TopMost = false;
Location = new System.Drawing.Point(1000, 1);
});
}
}
async void AppStarted()
{
await Task.Delay(300);
BeginInvoke(new System.Action(PoPInFront));
}
void PoPInFront()
{
var _notepadProcess = Process.GetProcesses().Where(x => x.ProcessName.ToLower().Contains("notepad")).DefaultIfEmpty(null).FirstOrDefault();
if (_notepadProcess != null)
{
var _windowHandle = FindWindow(null, "Page Setup");
var _parent = GetParent(_windowHandle);
if (_parent == _notepadProcess.MainWindowHandle)
{
Invoke((MethodInvoker)delegate
{
Location = new System.Drawing.Point(550, 330);
TopMost = true;
});
}
}
//var ExternalApplication = Process.GetProcessesByName("Notepad").FirstOrDefault(p => p.MainWindowTitle.Contains("Page Setup"));
//Location = new System.Drawing.Point(550, 330);
//TopMost = true;
}
到目前为止,只要我打开记事本,我的应用就会弹出屏幕并设置TopMost = true
,而不是"页面设置"记事本,当我关闭记事本时它会移回屏幕的一角。
我想将应用移动到屏幕中央,并在“"页面设置”时设置TopMost = true
。当"页面设置"被打开并回到角落TopMost = false
。已关闭。
Location = new System.Drawing.Point(550, 330);
- 屏幕中心
Location = new System.Drawing.Point(1000, 1);
- 角落
我也试过这个,但没有运气。
void PoPInFront()
{
//IntPtr hWnd = IntPtr.Zero;
//foreach (Process pList in Process.GetProcesses())
//{
// if (pList.MainWindowTitle.Contains("Page Setup"))
// {
// hWnd = pList.MainWindowHandle;
// Location = new System.Drawing.Point(550, 330);
// TopMost = true;
// }
//}
var ExternalApplication = Process.GetProcessesByName("Notepad").FirstOrDefault(p => p.MainWindowTitle.Contains("Page Setup"));
Location = new System.Drawing.Point(550, 330);
TopMost = true;
}
我认为问题出在这里。我不知道如何做这样的事情:
var query = new WqlEventQuery("SELECT * FROM Win32_ProcessStartTrace WHERE ProcessName = 'Notepad.exe' AND MainWindowTitle = 'Page Setup'");
AND MainWindowTitle = 'Page Setup'
答案 0 :(得分:4)
您可以使用以下任一选项:
解决方案1 - 使用SetWinEventHook方法
使用comments,您可以从其他进程收听SetWinEventHook
并注册some events回调方法,以便在事件发生时接收事件。
EVENT_SYSTEM_FOREGROUND
可以帮助我们。
我们限制事件接收器从特定进程接收此事件,然后我们检查导致事件的窗口文本是否等于Page Setup
然后我们可以说Page Setup
窗口目标进程是开放的,否则我们可以告诉Page Setup
对话框未打开。
为了简化以下示例,我假设应用程序启动时notepad
实例已打开,但您也可以使用Win32_ProcessStartTrace
来检测notepad
应用程序何时运行。
更具体地说,当对话框关闭时,您可以收听EVENT_OBJECT_DESTROY
并检测该消息是否适用于我们感兴趣的窗口。
public const uint EVENT_SYSTEM_FOREGROUND = 0x0003;
public const uint EVENT_OBJECT_DESTROY = 0x8001;
public const uint WINEVENT_OUTOFCONTEXT = 0;
public delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd,
int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
[DllImport("user32.dll")]
public static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr
hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess,
uint idThread, uint dwFlags);
[DllImport("user32.dll")]
public static extern bool UnhookWinEvent(IntPtr hWinEventHook);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
IntPtr hook = IntPtr.Zero;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
var p = System.Diagnostics.Process.GetProcessesByName("notepad").FirstOrDefault();
if (p != null)
hook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND,
IntPtr.Zero, new WinEventDelegate(WinEventProc),
(uint)p.Id, 0, WINEVENT_OUTOFCONTEXT);
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
UnhookWinEvent(hook);
base.OnFormClosing(e);
}
void WinEventProc(IntPtr hWinEventHook, uint eventType,
IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
string s = "Page Setup";
StringBuilder sb = new StringBuilder(s.Length + 1);
GetWindowText(hwnd, sb, sb.Capacity);
if (sb.ToString() == s)
this.Text = "Page Setup is Open";
else
this.Text = "Page Setup is not open";
}
解决方案2 - 处理UI自动化事件
根据Hans的评论中的建议,您可以使用WinEventProc
API订阅WindowOpenedEvent
和WindowClosedEvent
。
在下面的示例中,我认为有一个notepad
的打开实例,并检测到其Page Setup
对话框的打开和关闭:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
var notepad = System.Diagnostics.Process.GetProcessesByName("notepad")
.FirstOrDefault();
if (notepad != null)
{
var notepadMainWindow = notepad.MainWindowHandle;
var notepadElement = AutomationElement.FromHandle(notepadMainWindow);
Automation.AddAutomationEventHandler(
WindowPattern.WindowOpenedEvent, notepadElement,
TreeScope.Subtree, (s1, e1) =>
{
var element = s1 as AutomationElement;
if (element.Current.Name == "Page Setup")
{
//Page setup opened.
this.Invoke(new Action(() =>
{
this.Text = "Page Setup Opened";
}));
Automation.AddAutomationEventHandler(
WindowPattern.WindowClosedEvent, element,
TreeScope.Subtree, (s2, e2) =>
{
//Page setup closed.
this.Invoke(new Action(() =>
{
this.Text = "Closed";
}));
});
}
});
}
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
Automation.RemoveAllEventHandlers();
base.OnFormClosing(e);
}
不要忘记添加对UIAutomationClient
和UIAutomationTypes
程序集的引用,并添加using System.Windows.Automation;
。
答案 1 :(得分:1)
我需要使用user32.dll导入。
首先,在您的使用中确保您拥有:
using System.Runtime.InteropServices;
using System.Linq;
然后,在顶部的类中插入此代码以从DLL导入方法。
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static extern IntPtr GetParent(IntPtr hWnd);
现在,在您自己的方法中,以下代码应该起作用:
var _notepadProcess = System.Diagnostics.Process.GetProcesses().Where(x => x.ProcessName.ToLower().Contains("notepad")).DefaultIfEmpty(null).FirstOrDefault();
if ( _notepadProcess != null )
{
var _windowHandle = FindWindow(null, "Page Setup");
var _parent = GetParent(_windowHandle);
if ( _parent == _notepadProcess.MainWindowHandle )
{
//We found our Page Setup window, and it belongs to Notepad.exe - yay!
}
}
这应该让你开始。
*****编辑******
好的,你有这个:
mew.EventArrived += (sender, args) => { AppStarted(); };
这将确保在notepad.exe进程启动时触发AppStarted()方法。
然后等待300毫秒(出于某种原因?!)然后调用PopInFront:
async void AppStarted()
{
await Task.Delay(300);
BeginInvoke(new System.Action(PoPInFront));
}
在PopInFront()内部,您尝试查找“页面设置”窗口
var _windowHandle = FindWindow(null, "Page Setup");
但是,我的查询是:在0.3秒内,你可以安全地说你已经能够打开记事本,等待GUI初始化并导航到文件 - >页面设置菜单在.3秒内为下一个代码区找到窗口? - 我的猜测不是,你需要的是一个循环。
你应该做的是: