2012-03-16 86 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

相關問題