2012-03-16 4 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되었습니다. 모두 똑같은 문제를 일으킨다.

이벤트 로그에있는 (편집 됨) 오류는 다음과 같습니다

윈도우 그룹 정책 클라이언트 측 확장 예외가 0xc0000005을 처리 할 수 ​​없습니다.

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

이 완벽하게 패치 된 XP 32 비트는 명확한 문제 중 하나입니다, 그냥 OS 년대에 상황이 흥미로운 확인하십시오. 2008R2 잘 작동합니다.

예 - XP 32 비트에서 작동해야합니다.

여기에 다른 이상한 동작이있을 수 있습니다. 이 함수를 여러 번 호출하면 세 번째 호출에서 실패합니다. 예외가 발생하지 않고 텍스트가 표시되지 않고 호출이 실행 된 후에도 코드가 실행되지 않으며 이벤트 로그에 추가 오류가 표시되지 않습니다. 타이밍은 여기에 요소가 아닙니다. 연속으로 3 회 또는 5 회 이상 3 회 호출하면 발생합니다. 일반적인 try/catch 블록에서 호출을 래핑하는 경우에는 발생하지 않습니다. 예외는 발견되지 않고 모든 텍스트가 표시됩니다. 모든 코드가 실행됩니다. 그러나 여전히 이벤트 로그에 오류가 발생합니다.

+1

긴 샷일 수도 있지만 상태 콜백의 두 번째 매개 변수는 LPWSTR (LPCWSTR과 반대)입니다. 아마도 실제로 문자열을 어떤 식 으로든 수정하려고 시도합니다 (la CreateProcessW). 문자열 리터럴 대신 스택에 로컬 버퍼를 전달하고 이것이 무엇인지 확인하십시오. – Luke

+0

이 코드는 정적 문자열, 스택의 바이트 배열, new'd의 바이트 배열 및 일부러 누출 된 바이트 배열을 사용하여 시도되었습니다. 메소드가 메모리 소유권을 가져 오는 경우를 대비하여. 또한 경우에 따라 CoTaskMemAlloc되었습니다. 모두 똑같은 문제를 일으킨다. –

답변

4

Google에서이 문제를 발견 한 것 같습니다.

문제점은 __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; 

그럼 우리는 호출 규칙을 __stdcall로 pStatusCallback 함수 포인터를 사용하여 일을 할 수 있습니다 올바르게 작동.

+0

좋은 직장! 컨벤션 버그를 호출하는 것은 종종 어렵습니다. –

관련 문제