PInvoke DLL в C # - PullRequest
       4

PInvoke DLL в C #

2 голосов
/ 21 февраля 2012

Я хочу передать структуру функции C и написать следующий код.

Когда я ее запускаю, первая функция - Foo1 работает, а затем функция Foo получает исключение.Можете ли вы помочь мне понять, в чем проблема? ...

Код C:

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;
}

Код C #:

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);
        }
    }
}

Ответы [ 2 ]

4 голосов
/ 21 февраля 2012

Для нижестоящих пользователей : Этот ответ решает две проблемы: немедленную проблему соглашения о вызовах / атрибута MarhsalAs и проблему, которую он вскоре найдет, где его параметр TTest не будет работатьесли он примет мое предложение превратить TTest в структуру.

Ваш нативный код запрашивает void*, что в C # - IntPtr.Сначала вы должны определить TTest как структуру, а не класс.Во-вторых, вы должны изменить объявление Foo на:

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

И в-третьих, вы должны закрепить TTest с помощью ключевого слова fixed и передать его указатель на Foo.Если вы используете класс, вы можете использовать Marhsal.StructureToPtr, чтобы получить IntPtr от вашего TTest.

Это обеспечивает одинаковую функциональность с обеих сторон, где можно передать указатель на любой типin. Вы также можете записывать перегрузки со всеми типами классов, которые вы хотите использовать, поскольку все они равны void* на нативной стороне.Со структурой ваши параметры будут дополнены ref.

. Меня интересует, почему ваш нативный код требует void* вместо TTest*, когда первое, что вы делаете внеуправляемый код приведен к TTest*.Если вы переключили параметр на TTest*, то предоставление идентичных функций станет проще.Ваша декларация стала бы:

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

И вы бы назвали функцию как Program.Foo(ref Test);

Если вы используете класс, ref не требуется, так как классы являются справочнымитипы.

0 голосов
/ 16 января 2019

Вы используете вызов C, поэтому вам нужно указать CallingConvention.Cdecl

[DllImport(@"C:\.net course\unmanaged1\unmanaged3\Debug\unmanaged3.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]

По умолчанию его stdcall в C # pinvoke, как я помню;Вместо этого вы также можете изменить код C и оставить свой код C #, как показано ниже

__declspec(dllexport) void __stdcall  Foo(void  *Test);

Но для меня лучше всего объявить __cdecl (или stdcall) в вашем экспорте C и CallingConvention.Cdecl (илиstdcall) в вашем коде на C # для удобства.Вы можете проверить https://docs.microsoft.com/en-gb/cpp/cpp/argument-passing-and-naming-conventions?view=vs-2017 и https://docs.microsoft.com/en-gb/dotnet/api/system.runtime.interopservices.callingconvention?view=netframework-4.7.2 для получения дополнительной информации

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...