문제

다음 pinvoke 서명을 사용하여 C#에서 Windows FilterSendMessage 함수를 (성공적으로) 호출하고 있습니다.

[DllImport("fltlib.dll")]
    public static extern IntPtr FilterSendMessage(
        IntPtr hPort,
        IntPtr inBuffer,
        UInt32 inBufferSize,
        IntPtr outBuffer,
        UInt32 outBufferSize,
        out UInt32 bytesReturned);

그만큼 아웃버퍼 매개변수는 C에서 다음과 같이 정의된 임의의 수의 구조체(연속 패킹됨)로 채워집니다.

typedef struct _BAH_RECORD {

    int evt
    int len;
    WCHAR name[1];

} BAH_RECORD, *PBAH_RECORD;

그만큼 이름 필드에는 가변 길이의 null로 끝나는 유니코드 문자열이 할당됩니다.그만큼 필드는 구조체의 전체 크기를 바이트 단위로 설명합니다(이름 문자열 포함).나는 관리되지 않는 측면에서 구조체가 처리되는 방식에 아무런 문제가 없다고 확신합니다.

내 문제는 outBuffer를 C#에서 다음과 같이 정의된 BAH_RECORD 구조체의 인스턴스로 마샬링하려고 할 때 발생합니다.

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct BAH_RECORD
{
    public UInt32 evt;
    public UInt32 len;
    public string name;
}

IntPtr outBuffer = Marshal.AllocHGlobal(OUT_BUFFER_SIZE);

hResult = Win32.FilterSendMessage(hPortHandle, inBuffer, IN_BUFFER_SIZE, outBuffer, OUT_BUFFER_SIZE, out bytesReturned);

BAH_RECORD bah = (BAH_RECORD)Marshal.PtrToStructure(outBuffer, typeof(BAH_RECORD));

<snip>

bah.name을 인쇄/보기/표시하려고 하면 쓰레기가 발생합니다...

outBuffer에 실제로 유효한 데이터가 포함되어 있는지 확인하기 위해 C#에서 Marshal.ReadInt32를 두 번 호출하고(처음 2개의 구조체 필드를 처리하기 위해) Marshal.ReadByte를 몇 번 호출하여 바이트를 채우는 조잡한 포인터 해커리를 수행했습니다. [] 그런 다음 Encoding.Unicode.GetString()에 대한 인수로 사용합니다...문자열이 제대로 나오므로 확실히 거기에 있습니다. 마샬러가 이를 올바르게 처리하도록 할 수 없는 것 같습니다. 할 수 있다?)

도움을 주시면 감사하겠습니다.

스티브

도움이 되었습니까?

해결책

문제는 C# BAH_RECORD 구조체의 'name' 문자열이 문자열(WCHAR*)에 대한 포인터로 마샬링되지만 C 측에서는 인라인 WCHAR 버퍼라는 것입니다.따라서 구조체를 마샬링하면 런타임은 버퍼의 처음 4바이트를 포인터로 읽은 다음 가리키는 문자열을 읽으려고 시도합니다.

불행하게도 런타임이 구조체 내부의 가변 크기 버퍼를 자동으로 마샬링하는 방법이 없으므로 수동 마샬링(또는 "포인터 해커"라고 말하는 것처럼)을 사용해야 합니다.그러나 버퍼를 가리키도록 포인터를 이동시키면 바이트를 개별적으로 읽은 다음 이를 문자열로 변환할 필요가 없습니다. Marshal.PtrToStringUni를 호출하기만 하면 됩니다.

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