2010-12-13 127 views
4

我的问题是有点一般,所以我不是在寻找一个确切的答案,但可能还有一些方向考虑,这将有助于我...C#的DllImport麻烦

在我工作的地方我编程主要是在C#。 我们有这个第三方公司,这给了我们一个我们需要使用的Native C++ dll。由于我需要的C++方法没有以易于从C#引用的方式公开,所以我将dll封装在另一个本机C++ Dll中。

所以,现在我有2倍本机C++的DLL中,一个包裹其他。

我创建的调用我在C++中创建的方法的小C#控制台应用程序。 我的方法签名如下所示:

[DllImport("HashMethodWrapper.dll")] 
[return: MarshalAs(UnmanagedType.LPStr)] 
private static extern string CreateHash(
      string input, 
      [MarshalAs(UnmanagedType.LPStr)]StringBuilder output); 

在我的控制台应用程序,一切工作正常,我总是收到串IM在结果期待。

但是,当我将它移动到一个Web服务或我创建了一个Web应用程序(因为这是我真的需要它),我看到字符串IM接收就是垃圾,甚至并不一致。看来,如果即时得到只是一些参考对丢失或类似的东西的内存,但是这仅仅是我的猜测......

我不知道为什么会这样,因为在我的控制台应用程序一切正常精细。

没有人有可能会帮助我一个方向??? ...

由于提前, gillyb

编辑: 我想这可能与一些未锁定的对象做,所以我试图在固定的声明中调用方法,如:

unsafe public static string CreateHashWrap(string pass) 
{ 
    String bb; 
    StringBuilder outPass = new StringBuilder(); 
    fixed (char* resultStr = CreateHash(pass, outPass)) 
    { 
     bb = new String(resultStr); 
    } 
    return bb; 
} 

...但这仍然没有为我做。这是固定物体的正确方法吗?

第二编辑: 在C++中的方法,签名看起来像这样:

extern "C" __declspec(dllexport) char *CreateRsaHash(char *inputPass, char *hashPass); 

第三编辑: 我改变的方法的签名是

extern "C" __declspec(dllexport) bool CreateRsaHash(char *inputPass, char *hashPass); 

和返回值im寻找放在*hashPass参数。

现在,我创建了一个简单的控制台应用程序来测试它。当将DllImport插入到我的主类中,并直接调用该方法时,一切都很好,但是当我移动DllImport并将该方法包装在不同的类中并从Console'Main'方法中调用该类时,出现StackOverflow异常!

任何人有任何想法,为什么发生这种情况?

+0

您能告诉我们如何在C/C++中声明函数头吗?这可以帮助:) – 2010-12-13 09:11:15

+0

杀死API的作者,有一个非常明显的内存泄漏发生... – leppie 2010-12-13 10:37:47

+0

为什么?你能解释一下为什么,以及为什么从签名中如此清楚?希望我们仍然可以解决它! – gillyb 2010-12-13 10:41:32

回答

0

我找到了解决我的问题,现在我觉得有点(如果不是真的!)愚蠢的...: - |

我在C++中使用LoadLibrary()方法来动态调用其他本地dll的方法。问题是我没有给这个方法任何路径,只是dll文件名。在.net中,它会在当前文件夹中搜索,但似乎在本地代码中,这不起作用。

在我的编程实践中的更大的问题显然是我没有完全覆盖我的本机C++ DLL中的错误处理!

所有我这个页面上收到的asnwers是不是没有,但...

一旦我发现我有问题的目录路径,我遇到了不同的异常有关试图访问损坏内存,等等。然后我需要创建固定的对象,并为我的StringBuilder对象声明一个大小。

感谢大家的帮助!

:)

+0

不错。做得好。 – 2010-12-16 19:57:07

1

这真的很难从稀疏的信息知道,但如果我猜我会说,你需要确保你钉扎输出对象。另外,我可能会将输出参数更改为某种其他类型,看起来很奇怪StringBuilder的工作是坦率的。

我知道如果你分配一个对象,它会得到一个指针,但这并不意味着它不会移动。因此,如果您尝试将指向托管对象的指针传递到非托管环境中,则需要确保告诉GC“锁定”内存,使其不会从内部移出。

这里是什么,我的意思是一个非常粗糙的版本由钉住:

string input = "..."; 
StringBuilder output = new StringBuilder(); 
var handle = System.Runtime.InteropServices.GCHandle.Alloc(output, GCHandleType.Pinned); 
try 
{ 
    CreateHash(input, output); 
} 
finally 
{ 
    handle.Free(); 
} 
+0

那么,关于StringBuilder,我读了一个地方,如果值发生变化,我需要一个stringbuilder,因为'String'是不可变的,在这种情况下不会执行这个任务。这是真的 ? – gillyb 2010-12-13 08:17:31

+0

关于固定的对象,我认为这可能是问题,所以我试图做一些固定。我会将它添加到我的问题中,请问您能告诉我我做了什么和您向GCHandle显示的内容有什么区别。 – gillyb 2010-12-13 08:17:58

+0

有两件事:你固定了char *而不是StringBuilder。另外为什么你有StringBuilder,它被称为“输出”,也是一个返回值?看起来好像你完全忽略了StringBuilder,只是返回返回值。 – 2010-12-13 08:26:10

0

我会考虑到C#的共享组件/ DLL,而不是C++ DLL里面弯曲,然后尝试让你的控制台应用程序与dll一起工作。无论如何,以这种方式封装外部依赖关系是一种很好的做法。
否则,一些传统的问题是32比64位,共享库的负载路径。它真的只是一个字符串或更复杂的东西吗?