문제

따라서 C#에서 최종 사용을 위해 C ++/CLI로 래퍼를 작성하는 데 사용한 (.lib 및 .hpp 파일)로 작업중인 기본 제 3 자 C ++ 코드 기반이 있습니다.

디버그에서 릴리스 모드로 전환 할 때 콜백의 코드가 반환 될 때 액세스 위반 예외가 발생한다는 점에서 특정 문제가 발생합니다.

콜백 함수 형식의 원래 HPP 파일의 코드 :

typedef int (*CallbackFunction) (void *inst, const void *data);

콜백 함수 형식에 대한 C ++/CLI 래퍼의 코드 : (순간에 두 명을 선언 한 이유를 설명하겠습니다)

public delegate int ManagedCallbackFunction (IntPtr oInst, const IntPtr oData);
public delegate int UnManagedCallbackFunction (void* inst, const void* data);

-Quickly, 두 번째 "ManagedCallbackFunction"을 선언 한 이유는 래퍼에서 "중개"콜백을 만들려고했기 때문에 체인이 기본 C ++> C#에서 기본 C ++> C ++/CLI 래퍼 버전으로 변경되었습니다. ... 전체 공개, 문제는 여전히 살아 있으며, 이제 같은 줄 (반환)에서 C ++/CLI 래퍼로 밀려났습니다.

마지막으로 C#의 충돌 코드 :

public static int hReceiveLogEvent(IntPtr pInstance, IntPtr pData)
    {
        Console.WriteLine("in hReceiveLogEvent...");
        Console.WriteLine("pInstance: {0}", pInstance);
        Console.WriteLine("pData: {0}", pData);

        // provide object context for static member function
        helloworld hw = (helloworld)GCHandle.FromIntPtr(pInstance).Target;
        if (hw == null || pData == null)
        {
            Console.WriteLine("hReceiveLogEvent: received null instance pointer or null data\n");
            return 0;
        }

        // typecast data to DataLogger object ptr
        IntPtr ip2 = GCHandle.ToIntPtr(GCHandle.Alloc(new DataLoggerWrap(pData)));
        DataLoggerWrap dlw = (DataLoggerWrap)GCHandle.FromIntPtr(ip2).Target;

        //Do Logging Stuff

        Console.WriteLine("exiting hReceiveLogEvent...");
        Console.WriteLine("pInstance: {0}", pInstance);
        Console.WriteLine("pData: {0}", pData);
        Console.WriteLine("Setting pData to zero...");
        pData = IntPtr.Zero;
        pInstance = IntPtr.Zero;
        Console.WriteLine("pData: {0}", pData);
        Console.WriteLine("pInstance: {0}", pInstance);

        return 1;
    }

콘솔에 대한 모든 쓰기가 완료된 후 우리는 반품에 끔찍한 충돌을 봅니다.

helloworld.exe에서 0x04D1004C에서 처리되지 않은 예외 : 0xc0000005 : 액세스 위반 읽기 위치 0x04D1004C.

여기에서 디버거로 들어가면 통화 스택의 마지막 항목은 :> "04d1004c ()"이라는 것입니다.

당신이 다음을 보여주는 콘솔을 보는 경우에만 흥미 롭습니다.

entering registerDataLogger
pointer to callback handle: 790848
fp for callback: 2631370
pointer to inst: 790844
in hReceiveLogEvent...
pInstance: 790844
pData: 80805964
exiting hReceiveLogEvent...
pInstance: 790844
pData: 80805964
Setting pData to zero...
pData: 0
pInstance: 0

이제 디버그와 릴리스 사이에 일부는 Microsoft 세계에서 상당히 다르다는 것을 알고 있습니다. 물론 바이트 패딩 및 변수 초기화에 대해 걱정하고 있으므로 여기에 제공하지 않는 것이 있으면 알려 주시면 (이미 긴) 게시물에 추가하겠습니다. 또한 관리되는 코드가 모든 소유권을 공개하지 않을 수 있다고 생각합니다. 그런 다음 네이티브 C ++ 재료 (코드가없는)가 PDATA 객체를 삭제하거나 킬려고하여 앱을 충돌 시키려고 할 수 있습니다.

더 완전한 공개, 디버그 모드에서 모두 (겉보기) 잘 작동합니다!

어떤 도움에 감사 할 진정한 머리 스크래치 문제!

도움이 되었습니까?

해결책

불일치 전화 컨벤션으로 인해 스택이 부서진 것 같아요 : 속성을 넣으십시오.

 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]

콜백 대의원 선언에서.

다른 팁

이것은 귀하의 질문에 직접 대답하지 않습니다, 그러나 디버그 모드까지 올바른 방향으로 이어질 수 있습니다.

디버거는 스택에 많은 레코드 유지 정보를 추가하고, 일반적으로 메모리에서 내 프로그램의 크기와 레이아웃을 패딩하기 때문에, 나는 매우 중요하지 않은 912 바이트 이상의 메모리를 삭감하여 디버그 모드에서 "운이 좋은"것입니다. . 그러나 디버거가 없으면, 나는 다소 중요한 것들 위에 낙서를하고 결국 내 메모리 공간 밖으로 걸어 가서 Interop이 소유하지 않은 메모리를 삭제하게했습니다.

DataLoggerWrap의 정의는 무엇입니까? 수신중인 데이터에는 너무 작을 수 있습니다.

나는 당신이 무엇을 달성하려고하는지 잘 모르겠습니다.

몇 가지 요점 :

1) 쓰레기 수집기는 릴리스 모드에서 더 공격적이므로 소유권이 잘못되면 설명하는 행동은 드문 일이 아닙니다.

2) 아래 코드가 무엇을하려고하는지 이해가 안 돼요?

IntPtr ip2 = GCHandle.ToIntPtr(GCHandle.Alloc(new DataLoggerWrap(pData)));
DataLoggerWrap dlw = (DataLoggerWrap)GCHandle.FromIntPtr(ip2).Target;

GCHANDLE.ALLOC을 사용하여 메모리에 DataloGgerWrap의 인스턴스를 잠그지 만 관리하지 않는 것으로 전달하지 않습니다. 왜 잠그는가? 당신은 또한 그것을 자유롭게 해제하지 않습니까?

그런 다음 두 번째 줄은 기준을 되 찾습니다. 왜 원형 경로입니까? 왜 참조 - 당신은 그것을 사용하지 않습니까?

3) intptrs를 null로 설정했습니다. 왜? - 기능 범위 외부에 영향을 미치지 않습니다.

4) 콜백의 계약이 무엇인지 알아야합니다. 누가 PDATA 콜백 또는 호출 기능을 소유하고 있습니까?

CallingConvetion.stdcall은 특히 제 3 자 LIB가 BC ++로 작성 될 때 @jdehaan과 함께 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top