2009-10-22 2 views
3

COM 인터페이스의 일부 문자열 필드에 액세스하는 데 문제가 있습니다. 정수 필드를 호출해도 오류가 발생하지 않습니다. clientID(), deviceID() 또는 key()을 호출 할 때 이전 "보호 된 메모리를 읽거나 쓰려고했습니다." 오류가 발생합니다. (코드 here에서 공급) 여기서 PInvoke - 문자열 필드 값 읽기 - "보호 된 메모리를 읽거나 쓰려고 시도했습니다."

[scriptable, uuid(fab51c92-95c3-4468-b317-7de4d7588254)] 
interface nsICacheEntryInfo : nsISupports 
{ 
    readonly attribute string clientID; 
    readonly attribute string deviceID; 
    readonly attribute ACString key; 
    readonly attribute long fetchCount; 
    readonly attribute PRUint32 lastFetched; 
    readonly attribute PRUint32 lastModified; 
    readonly attribute PRUint32 expirationTime; 
    readonly attribute unsigned long dataSize; 
    boolean isStreamBased(); 
}; 

는 인터페이스에 액세스하기위한 C# 코드이다 : 이유에

[Guid("fab51c92-95c3-4468-b317-7de4d7588254"), ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
interface nsICacheEntryInfo 
{ 
    string clientID(); 
    string deviceID(); 
    nsACString key(); 
    int fetchCount(); 
    Int64 lastFetched(); 
    Int64 lastModified(); 
    Int64 expirationTime(); 
    uint dataSize(); 
    [return: MarshalAs(UnmanagedType.Bool)] 
    bool isStreamBased(); 
} 

어떤 제안 여기

소스 인터페이스 코드 필드를 읽으 려하면 액세스 위반이 발생합니다.

+0

인터페이스에는 멤버 lastFetched, lastModified 등이 PRUint32로 있습니다. 그게 뭔지는 모르겠지만 32 비트 인 것 같지만 C# 코드에서는 Int64를 사용하고 있습니다. 그게 문제가 될 수 있을까요? –

+0

나는 변화를 만들었지 만 같은 예외가있다 : ( –

+0

어떤 종류의 문자열이 C++ 코드로 내보내 집니까? –

답변

3

이 인터페이스의 문자열은 C 스타일 문자열 (char * 's)의 변형이지만 COM Interop은 기본적으로 문자열을 BSTR로 처리합니다. 마샬 러가 잘못된 종류의 문자열을 읽은 다음 CoTask 메모리 할당 자로 해방하려고 했으므로 액세스 위반이 발생하는 것은 놀라운 일이 아닙니다. 문자열이 [In] 매개 변수 인 경우 적절한 MarshalAs 특성으로 장식 할 수 있지만 반환 값 매개 변수에서는 작동하지 않습니다. 따라서 IntPtrs로 마샬링 한 다음 수동으로 마샬링하고 기본 메모리를 확보해야합니다.

나는 다음을 시도합니다 :

[Guid("fab51c92-95c3-4468-b317-7de4d7588254"), ComImport, 
    InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
interface nsICacheEntryInfo 
{ 
    IntPtr clientID { get; } 
    IntPtr deviceID { get; } 
    IntPtr key { get; } 
    int fetchCount { get; } 
    uint lastFetched { get; } 
    uint lastModified { get; } 
    uint expirationTime { get; } 
    uint dataSize { get; } 
    [return: MarshalAs(UnmanagedType.Bool)] 
    bool isStreamBased(); 
} 

크리스는 PRUint32s 위에서 언급 한 바와 같이 실제로 32 개 비트없는 64 비트 부호없는 정수 내가 그들을 변경했습니다 있도록. 또한 idl의 의미를 더 잘 포착하기 때문에 메서드에 대한 속성을 변경했습니다. 레이아웃에 실제로 영향을 미치지 않는 읽기 전용이므로 idl의 의미를 더 잘 포착합니다. 클라이언트 ID와의 DeviceID에 대한

문자열은 그래서 Marshal.PtrToStrAnsi를 사용하여 읽을 수 있습니다 :

당신이 문자열을 무료로 NS_Free 또는 메모리 인터페이스를 사용하든
 nsIMemory memoryManagerInstance = /*maybe get this from somewhere*/; 
     nsICacheEntryInfo cacheEntryInstance = /*definitely get this from somewhere*/; 
     IntPtr pClientID = cacheEntryInstance.clientID; 
     string clientID = Marshal.PtrToStringAnsi(pClientID); 

     NS_Free(pClientID); 

     //or 

     memoryManagerInstance.free(pClientID); 

당신이 전체 XPCOM 설정을 사용하는 방법에 따라 달라집니다. 키 값은 추상 문자열이므로 표현의 출처에 따라 다릅니다. 그것은 일반적으로 다른 사람과 같은 ANSI 문자열에 대한 포인터로 취급 될 수 있지만 나타납니다.

이 중 하나를 시도해 볼 수있는 설정이 없으므로 문서가 다소 불투명하기 때문에 조금 수정해야 할 수도 있습니다.

+0

너 +150 현상금을 잘받을 자격이있어! 관리되지 않는 코드에서 표준 stl c_str()을 전달한 C++ DLL에서 (비 COM) 레거시 코드를 처리하고있었습니다. 모두 32 비트에서 제대로 작동했지만 64 비트에서 손상되었습니다. 당신의 솔루션은 트릭을했습니다. 고맙습니다 !! – AVIDeveloper

0

[return : MarshalAs (UnmanagedType.BStr)] statememnt를 clientID 및 deviceID에 적용하면 어떻게됩니까?

+0

고마워, 도움이되지 않았어. –

관련 문제