Указатели в C# для получения ссылки из функции DllImport

StackOverflow https://stackoverflow.com/questions/2344929

Вопрос

Я ссылаюсь на DLL в своем проекте на С# следующим образом:

[DllImport("FeeCalculation.dll", CallingConvention = CallingConvention.StdCall,
           CharSet = CharSet.Ansi)]

        public static extern void FeeCalculation(string cin, string cout, string flimit,
            string frate, string fwindow, string fincrement, string fbird, 
            string fparameter, string fvalidation, string fcoupon);

Функция FeeCalculation экспортируется в DLL следующим образом:

extern "C" __declspec(dllexport) void __stdcall FeeCalculation(char *cin, 
char *cout, char *flimit, char *frate,
char *fwindow, char *fincrement, char *fbird,
char *fparameter, char *fvalidation, char *fcoupon);

Функция DLL возвращает ссылку на свои внутренние структуры в форме char *, поэтому, если бы вы ссылались на эту DLL в C++, вы бы сделали следующее, чтобы выполнить расчет и получить возвращаемые структуры:

FeeCalculation(buff, (char *)&fans, (char *)fl, (char *)ft, (char *)fw, (char *)fi, (char *)fe, (char *)&fm, (char *)val, (char *)cpn);

Теперь, как мне получить те значения, которые возвращаются по ссылке, с помощью C#?То есть, как мне сделать то же самое на C#, чтобы получить возвращаемые структуры для получения возвращенного расчета?Я знаю, что мне нужно создать небезопасный метод, но мне неясно, как обращаться с адресами памяти в C#, как в C++.

Редактировать:Ниже указано, как использовать IntPtr, но как поместить их в идентичную структуру, чтобы на поля структуры можно было ссылаться?

Редактировать:Вот возвращаемая структура, которая меня интересует (cout):

struct feeAnswer {


    unsigned int    fee;

    unsigned int    tax1;

    unsigned int    tax2;

    unsigned int    tax3;

    unsigned int    tax4;

    unsigned int    surcharge1;

    unsigned int    surcharge2;

    unsigned int    validationFee;

    unsigned int    couponFee1;

    unsigned int    couponFee2;

    unsigned int    couponFee3;

    unsigned int    couponFee4;

    unsigned short int dstay;       //Day Stay

    unsigned short int mstay;       //Minute Stay

};

Вот (cin), который я бы передал вместе с другими структурами (на данный момент они имеют нулевой размер, я хочу, чтобы это сначала работало, а затем реализую остальное):

struct feeRequest {

    unsigned char   day;

    unsigned char   month;

    unsigned int    year;   //2000 ~ 2099



    unsigned char   hour;

    unsigned char   minute;

    unsigned char   rate;

    unsigned char   validation;



    unsigned char   coupon1;

    unsigned char   coupon2;

    unsigned char   coupon3;

    unsigned char   coupon4;

};
Это было полезно?

Решение

Редактировать:теперь, когда у нас есть структуры для работы, возможно лучшее решение.Просто объявите структуры в C#, соответствующие вашим структурам C++, и используйте их в объявлении extern.

[StructLayout(LayoutKind.Sequential)]
public struct feeAnswer {
   public uint    fee;
   public uint    tax1;
   public uint    tax2;
   public uint    tax3;
   public uint    tax4;
   public uint    surcharge1;
   public uint    surcharge2;
   public uint    validationFee;
   public uint    couponFee1;
   public uint    couponFee2;
   public uint    couponFee3;
   public uint    couponFee4;
   public ushort  dstay;       //Day Stay
   public ushort  mstay;       //Minute Stay
   };

  [StructLayout(LayoutKind.Sequential, Pack=1)]
  public struct feeRequest {
   public byte   day;
   public byte   month;
   public uint   year;   //2000 ~ 2099
   public byte   hour;
   public byte   minute;
   public byte   rate;
   public byte   validation;
   public byte   coupon1;
   public byte   coupon2;
   public byte   coupon3;
   public byte   coupon4;
   };

  [DllImport ("FeeCalculation.dll", CallingConvention = CallingConvention.StdCall,
             CharSet = CharSet.Ansi)]
  public static extern void FeeCalculation (
          feeRequest cin,
          out feeAnswer cout,
           ...



        ....

оригинальный ответ (до того, как у нас появились структуры) ниже


Мне кажется, что это не ссылки на внутренние строки, а скорее указатели на строковые буферы, которые будут заполнены вызовом.Если бы ты был возвращение строковые указатели, тогда они будут объявлены char** скорее, чем char*.

Так что я думаю, что это просто стандартные параметры.Их просто много.Итак, ваше взаимодействие с C# будет выглядеть так

[DllImport("FeeCalculation.dll", CallingConvention = CallingConvention.StdCall,
           CharSet = CharSet.Ansi)]
public static extern void FeeCalculation(string cin, 
        [MarshalAs(UnmanagedType.LPStr, SizeConst=100)]
        out string cout, 
        [MarshalAs(UnmanagedType.LPStr, SizeConst=100)]
        out string flimit,

или это если ваши «строки» на самом деле не строки

[DllImport("FeeCalculation.dll", CallingConvention = CallingConvention.StdCall,
           CharSet = CharSet.Ansi)]
public static extern void FeeCalculation(string cin, 
        [MarshalAs(UnmanagedType.LPArray, SizeConst=100)]
        out byte[] cout, 
        [MarshalAs(UnmanagedType.LPArray, SizeConst=100)]
        out byte[] flimit,
        ....

Другие советы

Параметры char* в этом случае являются не строками, а указателями на фрагменты необработанных байтов, представляющих данные.Вам следует маршалировать свои параметры как экземпляры типа IntPtr в сочетании с Маршал.AllocHGlobal чтобы создать кусок памяти, а затем Маршал.PtrToStructure чтобы преобразовать этот блок памяти в пригодный для использования тип .NET.

В качестве примера:

[StructLayout(LayoutKind.Sequential)]
struct MyUnmanagedType
{
    public int Foo;
    public char C;
}

IntPtr memory = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(MyUnmanagedType)));

try
{
    FeeCalculation(memory);

    MyUnmanagedType result = (MyUnmanagedType)Marshal.PtrToStructure(
        memory, typeof(MyUnmanagedType));
}
finally
{
    Marshal.FreeHGlobal(memory);
}

Чтобы ответить на ваш Edit, вам нужно создать структуру, а затем использовать StructLayoutAttribute в полях, чтобы порядок байтов и заполнение были такими же, как в исходной dll.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top