我试图帮助一个同事在客户端扩展中的一些代码。 由于向callback中添加了一个调用,函数似乎完成了,但Windows事件日志中的事件在处理组策略对象时抱怨访问冲突。
删除现有代码后,只需添加对callback的调用,它仍会报告此访问冲突。
你能否帮助确定我们可能会错过什么?
// // Entry point for processing group policy objects. // // For full details, see http://msdn.microsoft.com/en- us/library/windows/desktop/aa374383(v=vs.85).aspx. // extern "C" DWORD CALLBACK ProcessGroupPolicyEx ( __in DWORD dwFlags, __in HANDLE hToken, __in HKEY hKeyRoot, __in PGROUP_POLICY_OBJECT pDeletedGPOList, __in PGROUP_POLICY_OBJECT pChangedGPOList, __in ASYNCCOMPLETIONHANDLE pHandle, __in BOOL *pbAbort, __in PFNSTATUSMESSAGECALLBACK pStatusCallback, __in IWbemServices *pWbemServices, __out HRESULT *pRsopStatus) { if(pStatusCallback) pStatusCallback (FALSE, L"Aaaaargh!"); return (0); }
这个代码已经被尝试过使用静态string,堆栈中的字节数组,一个新的字节数组,并故意泄漏 – 以防万一方法取得了内存的所有权。 以防万一,也是CoTaskMemAlloc'd。 所有产生相同的问题。
事件日志中的(redacted)错误是:
Windows无法处理组策略客户端扩展exception0xc0000005。
为了使事情有趣,这只是在一些操作系统的,完全修补的XP 32位是一个明确的问题。 2008R2工作正常。
是的 – 我们需要它在XP 32位上工作。
在这里可能有其他一些怪异的行为:如果我们多次调用这个函数,它会在第三次调用时失败。 没有exception抛出,没有文本显示,我们的代码没有执行调用后,事件日志中没有额外的错误。 时间安排并不是一个因素:如果您连续三次打电话,或在五分钟之内打电话三次,则会发生这种情况。 如果我们将调用封装在通用的try / catch块中,这种情况就不会发生。 没有发现exception – 显示所有文本。 所有的代码都运行。 但是,我们仍然在事件日志中发现错误。
看起来我们已经发现这个问题。
问题是,回调需要使用__stdcall调用约定。 默认情况下,Visual Studio使用__cdecl调用约定创建项目。 如果将/ Gz标志添加到项目中,则默认情况下将使用__stdcall。 但是,我们不能这样做,因为我们正在使用不同调用约定的其他模块。
根本的问题是UserEnv.h像这样定义回调:
typedef DWORD (*PFNSTATUSMESSAGECALLBACK)(__in BOOL bVerbose, __in LPWSTR lpMessage);
这是一个奇怪的定义。 所有其他的窗口回调都是这样定义的:
typedef INT_PTR (CALLBACK* DLGPROC)(HWND, UINT, WPARAM, LPARAM);
那个CALLBACK很重要,它是这样扩展的:
#define CALLBACK __stdcall
这意味着默认情况下,所有窗口回调被定义为使用__stdcall调用约定,除了这个之外,出于某种原因。
如果我们创建自己的回调定义:
typedef DWORD (CALLBACK *PFNSTATUSMESSAGECALLBACK_STDCALL)(__in BOOL bVerbose, __in LPWSTR lpMessage);
并分配我们的函数指针:
PFNSTATUSMESSAGECALLBACK_STDCALL pStatusCallback = (PFNSTATUSMESSAGECALLBACK_STDCALL)pRawStatusCallback;
然后,我们可以使用带有__stdcall调用约定的pStatusCallback函数指针,让事情正常工作。