2010-12-09 160 views
3

我正在努力弄清楚为什么我不能从我的C#应用​​程序调用旧C++ .dll中的外部方法。从C调用非托管dll困难#

这里的函数头:

int __export FAR PASCAL SimplePGPEncryptFile(
             HWND hWnd1, 
             LPSTR InputFileName, 
             LPSTR OutputFileName, 
             BOOL SignIt, 
             BOOL Wipe, 
             BOOL Armor, 
             BOOL TextMode, 
             BOOL IDEAOnly, 
             BOOL UseUntrustedKeys, 
             LPSTR RecipientList, 
             LPSTR SignerKeyID, 
             int SignerBufferLen, 
             LPSTR SignerPassphrase, 
             int SignerPwdBufferLen, 
             LPSTR IDEAPassphrase, 
             int IDEAPwdBufferLen, 
             LPSTR PublicKeyRingName, 
             LPSTR PrivateKeyRingName); 

这里是我的C#声明:

 [DllImport("smplpgp_32.dll", CallingConvention = CallingConvention.StdCall)] 
    public static extern int SimplePGPEncryptFile(
     IntPtr hWnd1, 
     [MarshalAs(UnmanagedType.LPStr)] string InputFileName, 
     [MarshalAs(UnmanagedType.LPStr)] string OutputFileName, 
     bool SignIt, 
     bool Wipe, 
     bool Armor, 
     bool TextMode, 
     bool IDEAOnly, 
     bool UseUntrustedKeys, 
     [MarshalAs(UnmanagedType.LPStr)] string RecipientList, 
     [MarshalAs(UnmanagedType.LPStr)] string SignerKeyID, 
     int SignerBufferLen, 
     [MarshalAs(UnmanagedType.LPStr)] string SignerPassphrase, 
     int SignerPwdBufferLen, 
     [MarshalAs(UnmanagedType.LPStr)] string IDEAPassphrase, 
     int IDEAPwdBufferLen, 
     [MarshalAs(UnmanagedType.LPStr)] string PublicKeyRingName, 
     [MarshalAs(UnmanagedType.LPStr)] string PrivateKeyRingName); 

当我把这种方法,我发现了以下两个错误之一(在头部声明):

#define SIMPLEPGPENCRYPTFILE_RECIPIENTLISTDOESNOTENDWITHNEWLINE 408 
#define SIMPLEPGPENCRYPTFILE_RECIPIENTLISTDOESNOTSTARTWITHGOODCODECHAR 409 

这也被定义为标题中的常数:

#define INCLUDE_ONLYUSERIDS 1 

这是已知可正常调用这个函数的C++代码:

char recipients[512]; 
recipients[0] = INCLUDE_ONLYUSERIDS; 
strcat(strcpy(&recipients[1], rID), "\n"); \\ rID is equal to "CA" 
return 0 == SimplePGPEncryptFile(INI.m_hWnd, 
    (char*)plain, (char*)cipher, 
    0, 
    0, 
    1, 
    0, 
    0, 
    1, // UseUntrustedKeys 
    recipients, 
    0, 0, 
    0, 0, 
    0, 0, 
    PGPKM.pub, 0); //PGPKM.pub is declared earlier 

传递此为 'RecipientList' 参数给我的 '409' 错误:

string recipientList = "1CA\n\0"; 

传这对于'RecipientList'参数给我'408'错误:

char[] recipients = new char[512]; 
recipients[0] = '1'; 
recipients[1] = 'C'; 
recipients[2] = 'A'; 
recipients[3] = '\n'; // also tried '\r', then '\n' 
recipients[4] = Char.MinValue; 
string paramValue = recipients.ToString(); 

任何人都可以发现我的一个明显的疏忽?我觉得我已经有了解决这个问题所需的一切,但没有任何事情按预期工作。

备注:我在同一个.dll文件中成功调用了不同的函数。另外,我尝试使用StringBuilder构造RecipientList参数。

感谢您的任何建议!

+1

recipients [0] = INCLUDE_ONLYUSERIDS; - 这不会变成收件人[0] = 1;这与收件人不同[0] ='1'; - C#等价物将是收件人[0] =(char)1; – jeffora 2010-12-09 05:01:29

+0

收件人的目的是什么[4] = Char.MinValue;? – 2010-12-09 05:10:52

回答

2

TLDR:

string recipientList = (char) 1 + "CA\n\0"; 

做了一些基于Jeffora的评论挖......他可能是对的,我的第一个建议可能不会买任何东西。我写了一些测试代码,这里是我的发现:

当您使用此代码:

string recipientList = "1CA\n\0"; 

你编组为一个LPSTR后结束了对函数内部的字节为:

49-67-65-10-0 

看起来像你想要的。

当您使用此代码:

char[] recipients = new char[512]; 
recipients[0] = '1'; 
recipients[1] = 'C'; 
recipients[2] = 'A'; 
recipients[3] = '\n'; // also tried '\r', then '\n' 
recipients[4] = Char.MinValue; 
string paramValue = recipients.ToString(); 

你上了函数的内部编组为LPSTR后的字节为:

83-121-115-116-101-109-46-67-104-97-114-91-93 

这是ASCII码为“System.Char [ ]”。所以你一定需要使用编码器将这个char []转换为你想要的字符串。

至于为什么第一个字符串不工作...我怀疑你的DLL真的在寻找值'1',而不是'1'(49)的ascii字符。在该工程的代码,你说:

recipients[0] = INCLUDE_ONLYUSERIDS; 

其中INCLUDE_ONLYUSERIDS = 1

试试这个:

string recipientList = (char) 1 + "CA\n\0"; 


原来的答复:
我相信这个问题是Char.ToString()将字符视为unicode字符,但是您将编组为LPStr,而不是LPWStr。 LPStr正在寻找一串ANSII字符。

要解决此问题,请尝试使用字节数组。

byte[] recipients= new byte[512]; 
... 
// Pass this string to SimplePGPEncryptFile 
string recipientsToPass = System.Text.ASCIIEncoding.ASCII.GetString(recipients); 

0

你尝试改变调用约定? 在C++中,您使用pascal调用约定来声明函数,并在C#中声明stdcall。 调用约定必须匹配。