写了一个小程序,用钩子来监测窗口,当发现被测窗口后在C# (UI)做出响应。
众所周知,C++中交互是消息机制的,而消息机制依托于回调(CallBack)函数。C#中是事件(event),事件又依托于代理(delegate),所以要实现在C#中响应非托管C++的消息,只能从delegate下手了。
先写一个C++的回调:
typedef void(*CallFun)(LPTSTR title);
void FindOutWnd(CallFun f, LPTSTR s);
CallFun m_cfFun = NULL;
extern "C" __declspec(dllexport) void __stdcall SetActive(CallFun f); //在C#中调用这个函数来设置回调函数指针。
函数原型:
void FindOutWnd(CallFun f, LPTSTR s)
{
f(s);
}
__declspec(dllexport) void __stdcall SetActive(CallFun f)
{
m_cfFun = f;
}
在钩子函数中调用:
void CALLBACK WinCreateNotifyProc(HWINEVENTHOOK hEvent, DWORD event,
HWND hwndMsg, LONG idObject,
LONG idChild, DWORD idThread, DWORD dwmsEventTime)
{
if( event != EVENT_OBJECT_NAMECHANGE /*&& event != EVENT_OBJECT_CREATE*/)
return;
TCHAR strName[STR_SIZE];
IAccessible *pacc = NULL;
VARIANT varChild;
VariantInit(&varChild);
HRESULT hr = AccessibleObjectFromEvent(hwndMsg, idObject, idChild, &pacc, &varChild);
if(!SUCCEEDED(hr))
{
VariantClear(&varChild);
return;
}
GetObjectName(pacc, &varChild, strName, STR_SIZE);
if(_tcsstr(strName, _T("(***"))) //Your window’s name.
{
if(m_actFun)
FindOutWnd(m_cfFun, strName);
}
}
在C#的代码:
[DllImport("WinEngine.dll", ExactSpelling = false, CallingConvention = CallingConvention.StdCall)]
public static extern void SetActive(DelegateFind f);
public delegate void DelegateFind([MarshalAs(UnmanagedType.LPWStr)] StringBuilder sb);
public static void OnFind(StringBuilder sb)
{
MessageBox.Show("Call Back Test:" + sb.ToString());
}
static DelegateFind find = new DelegateFind(OnFind);
别忘了:调用SetActive()将代理与回调关联。
SetActive(find);
最后别忘了统一一下C#和C++的调用方式,C#默认是stdcall,C++默认是cdecl方式。