2012-03-16 91 views
4

我试图帮助一位同事在客户端扩展中的一些代码。由于添加了对回调的调用,该函数似乎完成正常,但Windows事件日志中的事件在处理组策略对象时抱怨访问冲突。为什么调用ProcessGroupPolicyEx回调会导致访问冲突?

删除现有代码后,只需添加对回调的调用,它仍会报告此访问冲突。

您能否帮助确定我们可能会丢失什么?

// 
// 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); 
} 

此代码已被使用静态字符串,字节堆栈上的阵列试过,字节阵列的被new'd和故意泄漏 - 的情况下,该方法是获得对存储器的所有权。以防万一,也是CoTaskMemAlloc'd。所有产生相同的问题。

在事件日志中(节录)错误是:

Windows不能处理组策略客户端扩展异常0000005。

Windows cannot process Group Policy Client Side Extension Exception 0xc0000005.

为了让事情变得有趣,这仅仅是一些操作系统的,完全修补XP 32位是定的问题之一。 2008R2工作正常。

是的 - 我们需要它在XP 32位上工作。

其他可能在这里有一个方位的怪异行为: 如果我们多次调用此函数,它会在第3次调用时失败。没有发生异常,没有显示文本,执行调用后我们的代码都没有,事件日志中没有其他错误。时间安排并不是一个因素:如果您连续3次或5分钟以上3次,则会发生这种情况。 如果我们将调用包装在通用try/catch块中,则不会发生这种情况。没有发现异常 - 显示所有文本。所有代码都运行。 但是,我们仍然在事件日志中发现错误。

+1

可能是一个长镜头,但状态回调的第二个参数是LPWSTR(而不是LPCWSTR)。也许它确实尝试以某种方式修改字符串(a CreateProcessW)。试着在堆栈上传递一个本地缓冲区而不是字符串文字,然后看看它是什么。 – Luke 2012-03-16 18:20:01

+0

此代码已经尝试使用静态字符串,堆栈中的字节数组,已新建的字节数组以及故意泄漏的字节数组,以防方法取得内存所有权。以防万一,也是CoTaskMemAlloc'd。所有产生相同的问题。 – 2012-03-19 08:43:30

回答

4

看起来我们发现了这个问题。

问题是,回调需要使用__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); 

该回调是非常重要的,它扩展这样的:

#define CALLBACK __stdcall 

这意味着,在默认情况下,所有的窗口回调定义为使用__stdcall调用约定,除了这个,出于某种原因。

如果我们创造我们自己的回调确定指标:

typedef DWORD (CALLBACK *PFNSTATUSMESSAGECALLBACK_STDCALL)(__in BOOL bVerbose, __in LPWSTR lpMessage); 

而且我们的函数指针分配给它:

PFNSTATUSMESSAGECALLBACK_STDCALL pStatusCallback = (PFNSTATUSMESSAGECALLBACK_STDCALL)pRawStatusCallback; 

然后我们可以使用pStatusCallback函数指针与__stdcall调用约定,并有事情好好工作。

+0

不错的工作!调用约定错误往往难以发现。 – 2012-03-22 13:36:06

相关问题