Вызов dll с заголовком C ++ из C # - PullRequest
4 голосов
/ 12 января 2011

Я пытаюсь вызвать метод в DLL, для которого у меня есть заголовок C ++.Я звоню в DLL из C #.Входные данные представляют собой строку, а выходные данные - двоичные данные.Любой из следующих 3 методов, вероятно, будет работать, я просто не знаю, как заставить любой из них работать полностью.Объявление C # сделано мной, поэтому они могут быть неверными

1: я могу получить hGlobal, но я не знаю, как получить данные из дескриптора.

//CMBT_LL_WINAPI INT DLLPROC  LlConvertStringToHGLOBALW(LPCWSTR pszText, _PHGLOBAL phMemory);
 [DllImport("cmll15.dll", EntryPoint = "LlConvertStringToHGLOBALW", CharSet =   CharSet.Unicode, ExactSpelling = true)]
 private static extern int _LlConvertStringToHGlobal32(string text, ref IntPtr handle);

2:

[DllImport("cmll15.dll", EntryPoint = "LlConvertStringToBLOBW", CharSet = CharSet.Unicode, ExactSpelling = true)]
//CMBT_LL_WINAPI INT      DLLPROC  LlConvertStringToBLOBW(LPCWSTR pszText, _PUINT8 pBytes, UINT nBytes);
private static extern int _LlConvertStringToBLOBW(string text, ref IntPtr pBytes, UInt32 nBytes);

3:

[DllImport("cmll15.dll", EntryPoint = "LlConvertStringToStreamW", CharSet = CharSet.Unicode, ExactSpelling = true)]
//CMBT_LL_WINAPI INT      DLLPROC  LlConvertStringToStreamW(LPCWSTR pszText, _PISTREAM pStream);
private static extern int _LlConvertStringToStreamW(string text, ref IntPtr pStream);

Обновлен, вот код, который, я думаю, закончится.

    [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
    private static extern UIntPtr GlobalSize(IntPtr hMem);

    [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
    public static extern IntPtr GlobalLock(IntPtr handle);

    [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
    public static extern IntPtr GlobalUnlock(IntPtr handle);

    [DllImport("cmll15.dll", EntryPoint = "LlConvertStringToHGLOBALW", CharSet = CharSet.Unicode, ExactSpelling = true)]
    private static extern int _LlConvertStringToHGlobal32(string text, ref IntPtr handle);

    private static void Main(string[] args)
    {
        IntPtr dataHandle = IntPtr.Zero;
        _LlConvertStringToHGlobal32(Contents, ref dataHandle);
        try
        {
            var size = (uint) GlobalSize(dataHandle);
            var array = new byte[size];
            IntPtr dataPtr = GlobalLock(dataHandle);
            try
            {
                Marshal.Copy(dataPtr, array, 0, array.Length);
            }
            finally
            {
                GlobalUnlock(dataPtr);
            }

            using (var fs = new FileStream("c:\\file.dat", FileMode.Create))
            {
                fs.Write(array, 0, array.Length);
            }
        }
        finally
        {
            Marshal.FreeHGlobal(dataHandle);
        }
    }

Ответы [ 2 ]

1 голос
/ 12 января 2011

Первый должен быть самым легким для начала, потому что это позволяет вызываемому абоненту определить необходимый размер.Однако не очевидно, как вы должны знать размер распределения.Возможно возвращаемое значение.Вы всегда можете вызвать GlobalSize (), чтобы получить размер из дескриптора HGLOBAL.Вы должны вызвать GlobalLock (), чтобы преобразовать дескриптор в указатель, затем Marshal.CopyMemory (), чтобы скопировать его в байт [].Очистите, вызвав GlobalUnlock () и Marshal.FreeHGlobal (), чтобы освободить память, поместите ее в блок finally, чтобы избежать утечки.

Во втором случае вы должны объявить 2-й аргумент как byte [] (не реф).Проблема в том, что вам придется угадывать размер массива заранее.Режим сбоя будет предполагать слишком маленький размер.

Третий режим требует COM IStream.Объявите это как System.Runtime.InteropServices.ComTypes.IStream.Он ведет себя во многом как .NET Stream, вы бы позвонили Seek, чтобы искать в начале, и Read, чтобы прочитать данные.

Я бы пошел на первый, наименее вероятно, взорвется на вашем лице.

0 голосов
/ 12 января 2011

Для 1: вы должны иметь длину вывода двоичных данных, а затем использовать метод Marshal.Copy следующим образом: byte [] data = new byte [length];Marshal.Copy (ручка, данные, 0, длина);

Для 2 и 3: в чем ваша проблема?

...