2014-11-21 100 views
-1

我正在研究一个C++ DLL,它应该能够接收并将一些参数传递回C#应用程序。从C#传递参数到C++ Dll并返回的正确方法是什么?

我能够做到这一点,这是工作正常。至少我是这么想的。代码在我的电脑上工作正常,但不在我的同事的个人电脑上。在他的PC上,相同的代码(在我的电脑上运行时没有错误)会产生不同的输出,或产生错误。基本上它表现得很怪异。

C++函数:

extern "C" 
{ 
    __declspec(dllexport) BOOL __stdcall MyFunction(char * StringIn, char *StringOut, BOOL bState); 
} 

我用这种方式在C#:

[DllImport(@"PathToMyDll.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] 
    public static extern bool MyFunction(string StringToDLL, StringBuilder StringFromDLL, bool bState); 

    static void Main(string[] args) 
    { 
     int bufferSize = 16384; 

     string StringToDLL = "This is a sample string"; 
     StringBuilder StringFromDLL = new StringBuilder(bufferSize); 

     Console.WriteLine("Return value  = " + MyFunction(StringToDLL, StringFromDLL, true).ToString()); 
     Console.WriteLine("Sent to DLL  = " + StringToDLL.ToString()); 
     Console.WriteLine("Returned from DLL = " + StringFromDLL.ToString()); 

     Console.ReadLine(); 
    } 

所以我的问题是:
我做错什么了吗?还是有一些Visual Studio中的设置可能导致这种行为?另外,我应该如何正确地为C#中的StringOut分配内存?有一种情况可能出现在StringOut会比buffersize大的地方,但我不知道它到底有多大?(我只知道它在DLL里面) 有没有人有任何想法为什么相同的代码会自动运行不同地在不同的PC上?

在此先感谢!

+0

您允许将C#中声明的字符串直接转换为char *隐式吗?有一次,我使用C++/CLI为本地C++类编写了包装器(请参阅本教程:http://www.codeguru.com/cpp/cpp/cpp_managed/interop/article.php/c6867/Consuming-Unmanaged-C-Class -Libraries-from-Net-Clients.htm),我必须非常小心编译本机C++端和C++/CLI管理端之间的类型。 – Ian 2014-11-21 23:08:03

+0

@Ian是的,你可以。这是P/Invoke层的一部分。 – cdhowie 2014-11-21 23:14:18

+0

看起来这个代码没有问题。可能你应该在其他地方寻找问题。顺便说一句,你可以省略调用约定--stdcall是默认的。 – Nikolay 2014-11-21 23:14:36

回答

1

考虑到问题中的信息,您的代码是正确的。这个问题可能在别处。显而易见的地方是非托管代码。我建议你调试一下。

您的代码是等待发生的缓冲区溢出。如果被调用者不知道其大小,如何避免被缓冲区溢出?选项包括:

  1. 将缓冲区长度传递给非托管代码。
  2. 使用BSTR通过分配共享COM堆的方式允许任意长的字符串。
+0

另一种选择是使DLL函数的一个版本返回需要分配的缓冲区的最大大小。然后对函数的后续调用是使用适当大小的缓冲区完成的。有点过时,但这是一些API的工作方式。 – PaulMcKenzie 2014-11-22 13:27:41

+0

@Paul这是实现选项1的正常方法 – 2014-11-22 13:37:33

+0

@DavidHeffernan:基本上你说的是,我应该重写我的代码,以保持字符串长度的额外参数。然后我应该打电话给它两次。第一次,它应该返回长度,第二次,我应该通过正确的长度,只有然后我应该返回字符串?我理解正确吗?感谢idee,但这仍然不能解释它在我的电脑上工作。而且我返回的字符串比缓冲区大小更短。 – kampi 2014-11-22 15:57:57

0

如果这有帮助,这是我如何将我的基于C++的DLL接口到C#。

[DllImport("MyDLL.DLL", CharSet=CharSet.Ansi,ExactSpelling=true, 
      CallingConvention=CallingConvention.StdCall)] 
public static extern int MyFunction 
(MarshalAs(UnmanagedType.LPTStr)]StringBuilder strinIn, 
[MarshalAs(UnmanagedType.LPStr)]StringBuilder stringOut); 

所以区别在于我指定了编组类型。然后

C++的DLL(导出为 'C' 功能)将具有以下原型:

LONG WINAPI MyFunction(const char *In, char *Out); 

注:我不一个 C#专家。这是我需要做的,以便让我的C++ DLL函数被C#应用程序调用。

+1

你的MarshalAs言论在这里毫无意义。更重要的是你应该使用字符串作为in参数。 – 2014-11-22 06:50:40

+0

使用'string'而不是'StringBuilder'作为输入参数。 FWIW,该问题指出本机代码是C++。当然对于互操作,'std :: string'是不合适的。 – 2014-11-22 13:17:35

相关问题