Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++;dll和C#调用 我有一个C++函数,调用COM接口的函数 签字: BOOL func(LPWSTR strIn, __out LPWSTR strOut) { //initcom //do something // release pointers }_C#_C++_Pinvoke - Fatal编程技术网

C++;dll和C#调用 我有一个C++函数,调用COM接口的函数 签字: BOOL func(LPWSTR strIn, __out LPWSTR strOut) { //initcom //do something // release pointers }

C++;dll和C#调用 我有一个C++函数,调用COM接口的函数 签字: BOOL func(LPWSTR strIn, __out LPWSTR strOut) { //initcom //do something // release pointers },c#,c++,pinvoke,C#,C++,Pinvoke,在C#中: [DllImport(“funcdll.dll”)] 静态外部布尔函数(String strIn,ref String strOut); //使用它 对于(int i=0;i<p>),很难在没有看到C++方法的细节的情况下进行说明……但是,我从来没有过多的运气,使用p/INKEKE使用字符串< /代码>。 尝试使用IntPtr而不是String,对传出字符串使用Marshal.PtrToStringUni,并使用Marshal.StringToHGlobalUni将托管字符串封送到非

在C#中:

[DllImport(“funcdll.dll”)]
静态外部布尔函数(String strIn,ref String strOut);
//使用它

对于(int i=0;i<p>),很难在没有看到C++方法的细节的情况下进行说明……但是,我从来没有过多的运气,使用p/INKEKE使用<代码>字符串< /代码>。 尝试使用
IntPtr
而不是
String
,对传出字符串使用
Marshal.PtrToStringUni
,并使用
Marshal.StringToHGlobalUni
将托管字符串封送到非托管区域,在函数调用后,确保使用
Marshal.FreeHGlobal
释放非托管字符串

也从C99土地上来,我的BOOLS不与.NET BOOL一起工作…我不知道为什么。我必须使用字节和Chc==1。不知道你是否会用C++来运行这个……但是,如果你想让我的建议在一个地方开始,在我的经验中,这个地方似乎是最不可破解的,那么,YAG: < /P>

[DllImport("funcdll.dll")]
static extern byte func(IntPtr strIn, out IntPtr strOut);

// use it
string myString = "Testing";

IntPtr stringOut;
IntPtr stringIn = Marshal.StringToHGlobalUni(myString);

   if(func(stringIn, out stringOut) == 1)
   {
      //do something with strout
      string stringOutValue = Marshal.PtrToStringUni(stringOut);
      // Depending on how you dealt with stringOut in your
      // unmanaged code, you may have to: Marshal.FreeCoTaskMem(stringOut);
      // or Marshal.FreeHGlobal(stringOut) if you're returning
      // an owning reference to a copied string.
   }

Marshal.FreeHGlobal(stringIn);

我相信你有一个调用约定不匹配。C++中的默认调用约定是CDECL,而.NET是STDCULL。

[DllImport("funcdll.dll", CallingConvention = CallingConvention.Cdecl)] 
static extern bool func(String strIn, ref String strOut); 
另外,您可能必须明确地告诉marshallar,您希望使用[Marshallas(UnmanagedType.LPWSTR)]属性将字符串封送为LPWSTR

[DllImport("funcdll.dll", CallingConvention = CallingConvention.Cdecl)] 
static extern bool func([MarshalAs(UnmanagedType.LPWStr)]String strIn
                       ,[MarshalAs(UnmanagedType.LPWStr)]ref String strOut);

看看

我可以看出你有三个问题

调用约定不匹配。您的C++代码是“代码> CDECL < /COD>”,而C代码是“代码> STDCALL< /COD> < < /LI>”。 C++代码使用宽字符串,但C代码则封ANSI字符串。 <> LI>第二个参数不匹配。C++代码假定C++代码返回一个C指针的新指针,C代码随后与COM分配器进行分配。C++代码不执行此操作。 现在,更详细地处理这些问题

呼叫约定

<>这是很容易解决的。简单的将C++代码改为<代码> STDCALL> /CODE >,或者C代码到 CCDL> <代码>。但是不要同时做这两个。我将更改C代码:

Unicode/ANSI字符串

我假定你想使用Unicode字符串,因为你已经在C++代码中明确地选择了它们。但是P/Uncess默认是编组ANSI字符串的。你可以在 dLimPult中再次改变这一点:
[DllImport("funcdll.dll"), CallingConvention=CallingConvention.Cdecl, 
    CharSet=CharSet.Unicode]

<强>将字符串从C++返回到C<<强>

您当前的C++函数声明为:

BOOL func(LPWSTR strIn, __out LPWSTR strOut)
\uuu out
装饰器没有实际效果,除了记录您想要修改strOut
指向的缓冲区并将这些修改返回给调用方之外

您的C#声明是:

static extern bool func(String strIn, ref String strOut);
现在,
ref String strOut
根本不匹配。在C++中,
ref
String参数与此匹配:

BOOL func(LPWSTR strIn, LPWSTR *strOut)
换句话说,C#code希望您返回一个新指针。事实上,它将通过调用
CoTaskMemFree
,继续释放您在
strOut
中返回的缓冲区。我相信这不是您想要的

原始的C++代码只能通过修改传递给它的缓冲区来将字符串返回到C代码中。

BOOL func(LPWSTR strIn, __out LPWSTR strOut)
{
    ...
    wcscpy(strOut, L"the returned string");
    ...
}
如果这是您想要的,那么您应该在
StringBuilder
对象中的C#中分配足够的缓冲区

[DllImport("funcdll.dll"), CallingConvention=CallingConvention.Cdecl, 
    CharSet=CharSet.Unicode]
static extern bool func(string strIn, StringBuilder strOut);
...
StringBuilder strOutBuffer = new StringBuilder(128);
bool res = func("input string", strOutBuffer);
string strOut = StringBuilder.ToString();

如果你不能在C代码中决定你需要多大的缓冲区,那么你最好用一个<代码> BSTR < /C>来整理Strut。请参阅详细信息。C++中的

< P>确保你有类似的东西(至少对于第二个参数)

在C#中写下如下内容(对于第二个参数):


很抱歉,我没有一个大的答案,但只是从我的经验中记住一些东西。您是否尝试使用StringBuilder,例如将c#导入函数签名更改为

   [System.Runtime.InteropServices.DllImport("funcdll.dll")]
static extern bool func(String strIn, System.Text.StringBuilder strOut);

您是否尝试过添加一些调试输出或日志记录,并看到函数中的哪个部分崩溃了?在DllImport属性中使用字符集比在单个Marshallas中使用字符集要简单得多。我不认为两者相等,将字符集设置为Unicode只会告诉它字符串是Unicode,Bstr和LPWStr都是Unicode,但您仍然不知道是哪一个显然,使用MalSalas来显式设置它是更好的,两个选项是等价的。当你使用字符集时默认为LPTSTR。更重要的是,REF LPWSTR实际上是BSTR,因为这是封送者将要处理的返回内存。这与代码中的C++声明不匹配。harSet默认为任何值。在没有任何显式文档的情况下,我不信任隐式。至于第二部分,是的,这是一个问题,当我第一次阅读这个问题时,我没有看到这一点。但是从什么时候开始LPWSTR(可能以null结尾,可能以长度为前缀)和BStr(总是以null结尾,以长度为前缀)平等?这在很大程度上是一个糟糕的建议。在这里使用IntPtr只会在C#端产生不必要的复杂性。这种复杂性很容易避免。Hrm…它对我来说始终如一。来自未管理的土地,很容易理解正在发生的事情,而不是其他一些“神奇”的可能性。我想称之为“糟糕的建议”可能有点太远了。当然它是有效的,但是它不必要的复杂。在没有IntPtr的情况下封送字符串是非常容易的。你把它称为魔法的事实仅仅表明你还没有掌握这样做。这是你的问题。如果它有效,那么它肯定不是“坏建议”。“次优”可能…但远不是“坏建议”.你为什么这么暴躁?不,我会说这是个错误的建议。要正确编写代码,你真的需要尝试/最终,但你错过了。你对第二个参数的处理非常不完整。根本不需要如此复杂。而且你所说的
bool
是错误的。C#
bool
的默认编组是
bool。这里没有C99
bool
。我不是脾气暴躁。我只是相信给别人最好的建议很重要
[DllImport("funcdll.dll"), CallingConvention=CallingConvention.Cdecl, 
    CharSet=CharSet.Unicode]
static extern bool func(string strIn, StringBuilder strOut);
...
StringBuilder strOutBuffer = new StringBuilder(128);
bool res = func("input string", strOutBuffer);
string strOut = StringBuilder.ToString();
extern "C" BOOL __stdcall func( BSTR * pBstr )
{
    *pBstr = SysAllocString( L"Foobar" );
    return 0;
}
static extern bool func( [MarshalAs(UnmanagedType.BStr)] ref String strOut); 
   [System.Runtime.InteropServices.DllImport("funcdll.dll")]
static extern bool func(String strIn, System.Text.StringBuilder strOut);