如何将指针从C#传递到DLL中的本机函数?

这是我在DLL中的函数的签名:

int __stdcall myFun( void * const context, const char * const pszFileName, const unsigned int buffSize, void * const pWaveFormatex ); 

所有参数均为[in]。 用户应该通过最后一个参数将指针传递给WAVEFORMATEX结构。 返回后,它将被填补。 所有这些在C ++中都很有效。

现在,我正在尝试使用C#中的相同DLL,但它根本不起作用。 问题出在最后一个参数中。 由于我根本不了解C#,我想问一下这是否可行。 如果是,我会很感激一个例子。

我最后一次尝试是这样的:

 [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct WAVEFORMATEX { public ushort wFormatTag; public ushort nChannels; public uint nSamplesPerSec; public uint nAvgBytesPerSec; public ushort nBlockAlign; public ushort wBitsPerSample; public ushort cbSize; } 

注意:我还使用Struct Member Alignment = 1构建了用C ++编写的DLL。也许我很愚蠢,但我认为上面的Pack = 1与C ++中的相关,但我不知道它是否……

 [DllImport("myLib.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)] public static extern int myFun( IntPtr context, [MarshalAs( UnmanagedType.LPStr )] string pszFileName, int bufferSize, ref IntPtr pWfx ); IntPtr unmanaged_pWfx = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WAVEFORMATEX))); result = DLLWrapper.myFun(context, "C:\\video.wmv", 176400, ref unmanaged_pWfx ); WAVEFORMATEX wfxFormat = (WAVEFORMATEX)Marshal.PtrToStructure( unmanaged_pWfx, typeof(WAVEFORMATEX)); 

行为未定义。 有时它会挂起,有时它会终止……有些事情是非常错误的。 但是,问题不在DLL中,问题出在C#端。 C#是否能够使用指针?

感谢您提供的任何反馈。

编辑(工作C ++代码):

 void * context; WAVEFORMATEX wfx; int success = getContext( &context ); success = myFun( context, "C:\\video.wmv", 176400, &wfx ); 

C#中的等价物是:

 IntPtr context; WAVEFORMATEX wfx; int success = getContext( out context ); success = myFun( context, "C:\\video.wmv", 176400, out wfx ); extern "C" __stdcall int getContext( void ** pContext ); [DllImport("myLib.dll", CallingConvention = CallingConvention.StdCall)] public static extern int getContext(out IntPtr context); 

那么,根据您提供的信息,我会说您需要声明C#函数,如下所示:

 [DllImport("myLib.dll")] public static extern int myFun( IntPtr context, string fileName, uint bufferSize, out WAVEFORMATEX wfx ); 

并调用这样的函数:

 WAVEFORMATEX wfx; int result = DLLWrapper.myFun(context, @"C:\video.wmv", 176400, out wfx); 

实际上不需要手动编组此结构。 这是一个非常简单的blittable结构,让框架处理编组更加清晰。

当您声明最终的struct参数不需要初始化并且其成员由函数填写时,我假设您是准确的。

包装看起来合理。 我认为你不需要以任何特殊的方式构建你的DLL。 我希望您从Windows头文件中获取WAVEFORMATEX ,并且他们已经为该结构指定了打包。

如果你仍然卡住那么你应该显示成功的C ++调用代码。


从评论来看,你的代码中仍然存在一个错误。 在这种情况下,特别是当您怀疑互操作时,进行简单的再现以确定互操作是否是问题是值得的。 这是我的:

C ++ DLL

 #include  #include  #include  BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } __declspec(dllexport) int __stdcall myFun(void * const context, const char * const pszFileName, const unsigned int buffSize, void * const pWaveFormatex) { std::cout << context << std::endl << pszFileName << std::endl << buffSize << std::endl; WAVEFORMATEX wfx; wfx.cbSize = 1; wfx.nAvgBytesPerSec = 2; wfx.nBlockAlign = 3; wfx.nChannels = 4; wfx.nSamplesPerSec = 5; wfx.wBitsPerSample = 6; wfx.wFormatTag = 7; CopyMemory(pWaveFormatex, &wfx, sizeof(wfx)); return 666; } 

C#控制台应用

 using System; using System.Runtime.InteropServices; namespace ConsoleApplication13 { class Program { [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct WAVEFORMATEX { public ushort wFormatTag; public ushort nChannels; public uint nSamplesPerSec; public uint nAvgBytesPerSec; public ushort nBlockAlign; public ushort wBitsPerSample; public ushort cbSize; } [DllImport(@"Win32Project1.dll", EntryPoint = "?myFun@@YGHQAXQBDI0@Z")] public static extern int myFun( IntPtr context, string fileName, uint bufferSize, out WAVEFORMATEX wfx ); static void Main(string[] args) { WAVEFORMATEX wfx; int result = myFun((IntPtr)42, @"C:\video.wmv", 176400, out wfx); Console.WriteLine(result); Console.WriteLine(wfx.cbSize); Console.WriteLine(wfx.nAvgBytesPerSec); Console.WriteLine(wfx.nBlockAlign); Console.WriteLine(wfx.nChannels); Console.WriteLine(wfx.nSamplesPerSec); Console.WriteLine(wfx.wBitsPerSample); Console.WriteLine(wfx.wFormatTag); Console.ReadLine(); } } } 

产量

 0000002A
 C:\ video.wmv
 176400
 666
 1
 2
 3
 4
五
 6
 7

问题是通过IntPtr。 您正在将堆栈分配的变量(保存实际指针的变量)传递给您的代码,但是您希望传递指针。 只需从代码中删除“ref”关键字即可。