简体   繁体   English

c#中的marshal c ++“char **”

[英]marshal c++ “char**” in c#

I'm calling C# method from C++ and passing char** as argument. 我从C ++调用C#方法并将char **作为参数传递。 It has to be char** because I need to return value through parameter. 它必须是char **因为我需要通过参数返回值。

c# code: c#代码:

    [ExportDll("test",
        System.Runtime.InteropServices.CallingConvention.StdCall)]

    public static int test([MarshalAs(UnmanagedType.AnsiBStr)] ref string p)
    {
        Console.WriteLine(p);
    }

c++ code to invoke function: 用于调用函数的c ++代码:

typedef int (__stdcall *MYPROC)(char **); 

VOID main(VOID) 
{ 
HINSTANCE hinstLib; 
MYPROC MyProc; 
BOOL fFreeResult, fRunTimeLinkSuccess = FALSE; 

hinstLib = LoadLibrary(TEXT("mydll.dll")); 

if (hinstLib != NULL) 
{ 
    ProcAdd = (MYPROC) GetProcAddress(hinstLib, "test"); 

    if (NULL != ProcAdd) 
    {
        fRunTimeLinkSuccess = TRUE;
        char s1[] = "test"; 
        char *s2 = s1;
        char **s3 = &s2;

        (MyProc) (s3); 
        cout << s3;
    }

    fFreeResult = FreeLibrary(hinstLib); 
} 
}

It's simple to pass char* (remove ref in c#, and use char* in c++), but when trying to pass char** i get a runtime error on line where I call the function :( 传递char *很简单(在c#中删除ref,并在c ++中使用char *),但是当尝试传递char **时,我在线上调用函数时遇到运行时错误:(

in c#, Console.WriteLine prints out correct value, but after that, I get an error: 在c#中,Console.WriteLine打印出正确的值,但在那之后,我收到一个错误:

Windows has triggered a breakpoint in COMDynamicLoad.exe.

This may be due to a corruption of the heap, which indicates a bug in COMDynamicLoad.exe or any of the DLLs it has loaded.

This may also be due to the user pressing F12 while COMDynamicLoad.exe has focus.

The output window may have more diagnostic information.

How should I do this? 我该怎么做?

这很可能是因为你把char*指向一个字符串文字 - 这很糟糕,因为修改那个内存是未定义的行为。

You declare ref UnmanagedType.AnsiBStr but you expect a char** . 你声明ref UnmanagedType.AnsiBStr但你期望一个char** This cannot work, since a ref to a BSTR is not a char**. 这不起作用,因为对BSTR的引用不是char **。 See Default Marshaling for Strings for examples of marshaling declarations. 有关编组声明的示例,请参阅字符串的默认编组。 These are possible declarations for an input-output string: 这些是输入输出字符串的可能声明:

PassStringRef2([in, out] BSTR *s);
PassStringRef3([in, out] LPStr *s);
PassStringRef4([in, out] LPWStr *s);

and the equivalent C# marshaling declarations are: 和等效的C#编组声明是:

PassStringRef2([MarshalAs(UnmanagedType.BStr)]ref String s);
PassStringRef3([MarshalAs(UnmanagedType.LPStr)]ref String s);
PassStringRef4([MarshalAs(UnmanagedType.LPWStr)]ref String s);

Your char** declaration is the equivalent of LPStr *s , so the correct marshaling is [MarshalAs(UnmanagedType.LPStr)]ref String s . 你的char**声明相当于LPStr *s ,所以正确的编组是[MarshalAs(UnmanagedType.LPStr)]ref String s But a better option is to use BSTR because of the explicit length declaration, and manipulate it in C++ with the BSTR helpers . 但更好的选择是使用BSTR因为显式长度声明,并使用BSTR助手在C ++中操作它。

这会有用吗?

public static int test([In, Out, MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr)] string[] p)

In many cases and as seems to be the situation here (see accepted answer by Remus Rusanu ), using the proper marshaling attributes in the API declarations is all that is needed to have the interop "glue" on both ends of the interface start "playing nice with one another" and result in... 在许多情况下并且看起来像这里的情况(参见Remus Rusanu接受的答案),在API声明中使用正确的编组属性就是在界面的两端开始互操作“粘合”所需的全部内容彼此很好“并导致......

  • the proper data values being sent/delivered [good!] 发送/交付正确的数据值[好!]
  • Windows not triggering automatic breakpoint upon various suspected 各种疑似Windows不会触发自动断点
    ... corruption of the heap ... [better! ... corruption of the heap ... [更好! ;-)] ;-)]

I am adding this answer, 5 months after the original post, because this question and its responses were very useful in fixing a recent interop bug of mine, but failed to mention directly information about the very plausible cause of many interop issues, namely: 我在原帖后5个月添加了这个答案,因为这个问题及其答案在修复我最近的互操作错误方面非常有用,但没有直接提到有关许多互操作问题的非常可信的原因的信息,即:

Mismatch in the Memory Ownership conventions 内存所有权约定不匹配
(and/or in the memory allocation and freeing methods). (和/或在内存分配和释放方法中)。

The January 2008 article on MSDN Magazine titled Marshaling between Managed and Unmanaged Code provided me with the info I needed in regards to memory ownership conventions. 2008年1月在MSDN杂志上发表的一篇题为“ 托管代码与非托管代码之间的密钥”的文章为我提供了内存所有权约定所需的信息。 Indeed this article provides a complete overview of the marshaling process. 实际上,本文提供了编组过程的完整概述。 It covers in specific details and examples the issues of 它涵盖了具体的细节和例子

  • [InAttribute] and [OutAttribute] aka [ In ] and [ Out ] [InAttribute]和[OutAttribute]又名[ In ]和[ Out ]
  • Keywords Out and Ref and passing by reference 关键词OutRef以及通过引用传递
  • Return values 返回值
  • StringBuilder and marshaling StringBuilder和编组
  • Copying and pinning 复制和固定
    (Pinning = optiimization by CLR when it deems it safe to lock data area in the CLR heap and pass corresponding pointers to unmanaged code) (当它认为可以安全地锁定CLR堆中的数据区并将相应的指针传递给非托管代码时,由CLR进行固定=优化)
  • Memory Ownership : 记忆所有权
    No change allowed vs. In-place change vs. Reference change 不允许更改与就地更改与参考更改
    Also, on the need of using CoTaskMemFree() and CoTaskMemAlloc() to free or allocate memory respectively received from or sent to the Managed code. 此外,还需要使用CoTaskMemFree()CoTaskMemAlloc()来释放或分配分别从托管代码接收或发送到托管代码的内存。
  • Reverse P/Invoke and delegate lifetime 反向P / Invoke和委托生命周期
  • P/Invoke Interop Assistant P / Invoke Interop助手

This article is very useful because it gathers in a single document and in an accessible fashion information otherwise disseminated across dozen of technically authoritative but dry [and oft' confusing] reference documents (cf. the old but on-point joke about Microsoft's documentation at large ). 这篇文章非常有用,因为它收集了一个文档,并以一种可访问的方式提供信息,这些信息在十几个技术上权威但干燥[和经常“令人困惑的]参考文档中传播(参见关于微软文档古老但有点开玩笑的笑话) )。
In short, it makes it a good primer or refresher for casual implementers of interop solutions . 简而言之,它使其成为互操作解决方案的临时实施者的良好入门或复习

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM