PInvoke的DLL在C# [英] PInvoke DLL in C#

查看:149
本文介绍了PInvoke的DLL在C#的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想传递给C函数的结构和我写了下面的code。

当我运行它,第一个功能 - Foo1 工作,然后功能得到一个例外。你能帮我了解的问题是什么?...

在C code:

  typedef结构
{
    INT大小;
    //字符*阵;
} TTEST;__declspec(dllexport)的无效​​美孚(无效*测试);
__declspec(dllexport)的INT Foo1();无效美孚(void *的测试)
{
    TTEST * X =(t检验*)测试;
    INT I = X-GT&;尺寸;
    / *的for(int i = 0; I<&测试 - GT;尺寸;试验++)
    {
        试验 - >数组[我] = 127;
    } * /
}INT Foo1()
{
    返回10;
}

在C#code:

 使用系统;
使用System.Runtime.InteropServices;
使用System.Collections.Generic;
使用System.Linq的;
使用System.Text;命名空间的ConsoleApplication1
{
    [StructLayout(LayoutKind.Sequential)]
    公共类TTEST
    {
        公众诠释大小;
    }    类节目
    {
        函数[DllImport(@C:\\网络课程\\ unmanaged1 \\ unmanaged3 \\调试\\ unmanaged3.dll,字符集= CharSet.Auto)
        公共静态外部无效美孚(
            [的MarshalAs(UnmanagedType.LPStruct)
            TTEST lplf //特点
        );        函数[DllImport(@C:\\网络课程\\ unmanaged1 \\ unmanaged3 \\调试\\ unmanaged3.dll,字符集= CharSet.Auto)
        公共静态外部INT Foo1();        静态无效的主要(字串[] args)
        {
            TTEST测试=新TTEST();
            Test.Size = 25;            INT XX = Program.Foo1();
            Program.Foo(试验);
        }
    }
}


解决方案

应用于downvoters :这个答案解决了两个问题:调用约定的直接的问题/的 MarhsalAs 属性,他很快就会发现在那里,如果他需要我的转弯建议他的 t检验参数将无法工作的问题 TTEST 成一个结构。

您本地code是要求一个无效* ,这在C#是的IntPtr 。首先,你应该定义 t检验为结构而不是类。其次,你应该的声明更改为:

 函数[DllImport(@C:\\网络课程\\ unmanaged1 \\ unmanaged3 \\调试\\ unmanaged3.dll,字符集= CharSet.Auto,CallingConvention = CallingConvention.Cdecl)
公共静态外部无效美孚(IntPtr的lplf);

第三,你应该钉住 t检验使用固定关键字并通过它的指针。如果您使用的是类,你可以使用 Marhsal.StructureToPtr 来获得的IntPtr TTEST

这提供了两侧,其中一个指向任何类型中可以通过相同的功能,还可以编写过载与您要使用,因为它们都等同于虚空中的所有类类型* 关于本机端。有了一个结构,你的参数会以 REF ppended $ P $

我很好奇的是什么,为什么你的本地code想要一个无效* ,而不是 t检验* 当你在非托管code做的第一件事被转换为 t检验* 。如果您切换参数为 t检验* ,然后提供相同的功能变得更简单。你的声明将成为:

 函数[DllImport(@C:\\网络课程\\ unmanaged1 \\ unmanaged3 \\调试\\ unmanaged3.dll,字符集= CharSet.Auto,CallingConvention = CallingConvention.Cdecl)
公共静态外部无效美孚(参考TTEST lplf);

和你会调用该函数为 Program.Foo(参考测试);

如果您使用的类,在 REF 不是必要的,因为类是引用类型。

I want to pass a structure to C function and I write the following code.

When I run it, the first function - Foo1 is working and then function Foo gets an exception. Can you help me to understand what the problem is?...

The C code:

typedef struct 
{
    int Size; 
    //char *Array;
}TTest;

__declspec(dllexport) void Foo(void  *Test);
__declspec(dllexport) int  Foo1();

void Foo(void  *Test)
{
    TTest *X = (TTest *)Test;
    int i = X->Size;
    /*for(int i=0;i<Test->Size;Test++)
    {
        Test->Array[i] = 127;
    }*/
}

int Foo1()
{
    return 10;
}

The C# code:

using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    [StructLayout(LayoutKind.Sequential)]
    public class TTest 
    {
        public int Size; 
    }

    class Program
    {
        [DllImport(@"C:\.net course\unmanaged1\unmanaged3\Debug\unmanaged3.dll", CharSet = CharSet.Auto)]
        public static extern void Foo(
            [MarshalAs(UnmanagedType.LPStruct)]
            TTest lplf   // characteristics
        );

        [DllImport(@"C:\.net course\unmanaged1\unmanaged3\Debug\unmanaged3.dll", CharSet = CharSet.Auto)]
        public static extern int Foo1();

        static void Main(string[] args)
        {
            TTest Test = new TTest();
            Test.Size = 25;

            int XX = Program.Foo1();
            Program.Foo(Test);
        }
    }
}

解决方案

To the downvoters: This answer solves two issues: the immediate issue of the calling convention/the MarhsalAs attribute, and the issue he will soon find where his TTest parameter won't work if he takes my suggestion of turning TTest into a struct.

Your native code is asking for a void*, which in C# is an IntPtr. First you should define TTest as a struct and not a class. Second, you should change the declaration of Foo to:

[DllImport(@"C:\.net course\unmanaged1\unmanaged3\Debug\unmanaged3.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
public static extern void Foo(IntPtr lplf);

And third, you should pin the TTest using the fixed keyword and pass it's pointer to Foo. If you're using a class, you can use Marhsal.StructureToPtr to get an IntPtr from your TTest.

This provides the same functionality on both sides, where a pointer to any type can be passed in. You can also write overloads with all the class types that you want to use since they all equate to void* on the native side. With a struct, your parameters would be prepended with a ref.

What I'm curious about is why your native code wants a void* instead of a TTest* when the first thing you do in the unmanaged code is cast to a TTest*. If you switched the parameter to a TTest*, then providing identical functionality becomes simpler. You declaration would become:

[DllImport(@"C:\.net course\unmanaged1\unmanaged3\Debug\unmanaged3.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
public static extern void Foo(ref TTest lplf);

And you would call the function as Program.Foo(ref Test);

If you're using the class, the ref isn't necessary as classes are reference types.

这篇关于PInvoke的DLL在C#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆