Pinvoke 中的问题

发布于 2024-11-07 16:42:30 字数 945 浏览 8 评论 0原文

我在 C++ 本机 dll 中有以下函数,我想在 C# 应用程序中使用它。

DWORD __cdecl Foo(
        LPCTSTR             Input,
        TCHAR**             Output,          
        DWORD               Options,        
        ErroneousWord**     List = NULL,
        LPDWORD             Count = 0
        );

使用 Pinvoke

[DllImport("dllName", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
        public static extern UInt32 Foo(string InputWord, out string Output, UInt32 Options, out object List,out UInt32 Count);

调用代码:

            string output;
            object dummyError = null;
            uint dummyCount = 0;
            uint x = 0;
            Foo(Text, out output, x | y,out  dummyError,out dummyCount);

出现以下异常

尝试读或写受保护 记忆。这通常是一个迹象 其他内存已损坏

P.S: ErroneousWord 是结构体,我不需要它的输出,因此我将其封送为对象

I have the following function in C++ native dll, and I want to use it in a C# app.

DWORD __cdecl Foo(
        LPCTSTR             Input,
        TCHAR**             Output,          
        DWORD               Options,        
        ErroneousWord**     List = NULL,
        LPDWORD             Count = 0
        );

Using Pinvoke

[DllImport("dllName", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
        public static extern UInt32 Foo(string InputWord, out string Output, UInt32 Options, out object List,out UInt32 Count);

Calling code:

            string output;
            object dummyError = null;
            uint dummyCount = 0;
            uint x = 0;
            Foo(Text, out output, x | y,out  dummyError,out dummyCount);

I got the following exception

Attempted to read or write protected
memory. This is often an indication
that other memory is corrupt

P.S:
ErroneousWord is struct and I do not need its output, so I marshal it as object

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

初心未许 2024-11-14 16:42:30

该错误很可能意味着您遇到了编组问题。

您没有向我们展示 ErroneousWord 类型是什么,但我假设它是您的 C++ 代码中定义的某种类。我的猜测是它没有被正确地编组到 .NET 对象

考虑到它是一个指针(或指向指针的指针),请尝试将该参数更改为 IntPtr 类型 来表示指针。这应该不重要,因为无论如何,您只是为参数传递 NULL ,可以使用静态 IntPtr.Zero 字段

您可能还想以完全相同的方式封送Output。如果将参数更改为 IntPtr 类型,您将收到一个指向 TCHAR* 的指针,然后您可以将其传递给您认为合适的其他非托管函数(例如,释放它)。

尝试以下代码:

[
DllImport("dllName",
CharSet = CharSet.Unicode,
CallingConvention = CallingConvention.Cdecl)
]
public static extern UInt32 Foo(
                                string InputWord,
                                out IntPtr Output,     // change to IntPtr
                                UInt32 Options,
                                out IntPtr List,       // change to IntPtr
                                out UInt32 Count);

IntPtr output;
IntPtr dummyError = IntPtr.Zero;
uint dummyCount = 0;
uint x = 0;
Foo(Text, out output, x | y, out dummyError, out dummyCount);

您可能还需要使用 Marshal.AllocHGlobal 方法 从进程中分配可供 C++ 代码访问的非托管内存。确保如果这样做,您还调用相应的 Marshal.FreeHGlobal 方法 释放内存。

That error more than likely means that you have a marshaling problem.

You don't show us what the ErroneousWord type is, but I assume it's some kind of class defined in your C++ code. My guess is that it's not being marshaled correctly to a .NET object.

Considering that it's a pointer (or a pointer to a pointer), try changing that parameter to an IntPtr type to represent a pointer, instead. It shouldn't matter, since you're simply passing NULL for the argument anyway, easily represented using the static IntPtr.Zero field.

You probably also want to marshal Output the exact same way. If you change the parameter to an IntPtr type, you'll receive a pointer to a TCHAR*, which you can then pass to the other unmanaged functions however you see fit (e.g., to free it).

Try the following code:

[
DllImport("dllName",
CharSet = CharSet.Unicode,
CallingConvention = CallingConvention.Cdecl)
]
public static extern UInt32 Foo(
                                string InputWord,
                                out IntPtr Output,     // change to IntPtr
                                UInt32 Options,
                                out IntPtr List,       // change to IntPtr
                                out UInt32 Count);

IntPtr output;
IntPtr dummyError = IntPtr.Zero;
uint dummyCount = 0;
uint x = 0;
Foo(Text, out output, x | y, out dummyError, out dummyCount);

You might also need to use the Marshal.AllocHGlobal method to allocate unmanaged memory from your process that is accessible to the C++ code. Make sure that if you do so, you also call the corresponding Marshal.FreeHGlobal method to release the memory.

深空失忆 2024-11-14 16:42:30

鉴于 Cody 的回答和注释,您必须这样做:

[DllImport("dllName", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
extern static UInt32 Foo(string InputWord, out IntPtr Output, UInt32 Options, out IntPtr List, out UInt32 Count);

现在要将输出中的字符串值编组到托管内存,您将执行以下操作:

string outputValue = Marshal.PtrToStringAnsi(Output);

您必须知道 TCHAR 是 Ansi 还是 Unicode,并使用适当的编组。

请记住保留 Output IntPtr,以便可以将其传递给本机 Free 方法。

Given Cody's answer and the comments, you will have to do it this way:

[DllImport("dllName", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
extern static UInt32 Foo(string InputWord, out IntPtr Output, UInt32 Options, out IntPtr List, out UInt32 Count);

Now to get the string value in Output marshalled over to managed memory you will do:

string outputValue = Marshal.PtrToStringAnsi(Output);

You must know if TCHAR is Ansi or Unicode and use the appropriate marshal.

Remember to hang onto the Output IntPtr so you can pass that to the native Free method.

笨笨の傻瓜 2024-11-14 16:42:30

感谢 Cody 的回答,但我想制作一个单独的答案,第一个输出是由 Foo 从本机端创建的,我调用 FreeFoo 来释放 Foo 分配的内存。
下面是

[DllImport("dllname", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
        public static extern UInt32 Correct(string InputWord, out IntPtr Output, UInt32 Options, out object List,out UInt32 Count);

        [DllImport("dllname", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
        public static extern void FreeFoo(IntPtr Output);

}

使用它的代码:

    public string FooWrapper(string Text)
    {
        IntPtr output;
        object dummyError = null;
        uint dummyCount = 0;
        uint x = 0;
        Foo(Text, out output, x,out  dummyError,out dummyCount);
        string str = Marshal.PtrToStringUni(output);
        FreeFoo(output);
        return str;
    }

Thanks Cody for your answer but I want to make a seperate one, first Output is created by Foo from the native side, and I call FreeFoo to free the allocated memory by Foo.
The following is the code

[DllImport("dllname", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
        public static extern UInt32 Correct(string InputWord, out IntPtr Output, UInt32 Options, out object List,out UInt32 Count);

        [DllImport("dllname", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
        public static extern void FreeFoo(IntPtr Output);

}

To use it:

    public string FooWrapper(string Text)
    {
        IntPtr output;
        object dummyError = null;
        uint dummyCount = 0;
        uint x = 0;
        Foo(Text, out output, x,out  dummyError,out dummyCount);
        string str = Marshal.PtrToStringUni(output);
        FreeFoo(output);
        return str;
    }
彼岸花似海 2024-11-14 16:42:30

无论 ErroneousWord 类型是什么,您都无法将数组编组为单个输出对象。如果有可能作为一个对象编组......

Whatever the ErroneousWord type is, you can't marshal an array as a single out object. If it is at all possible to marshal as an object...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文