简体   繁体   English

C#中的指针从DllImport函数检索引用

[英]Pointers in C# to Retrieve Reference From DllImport Function

I am referencing a DLL in my C# project as follows: 我在C#项目中引用的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);

The FeeCalculation function is exported as follows in the DLL: 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);

The DLL function returns a reference to it's internal structures in the form of char * so if you were to reference this DLL in C++, you would do the following to do the calculation and get the returned structures: DLL函数以char *的形式返回对其内部结构的引用,因此,如果要在C ++中引用此DLL,则可以执行以下操作进行计算并获取返回的结构:

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

Now, how do I retrieve those values that are returned by reference using C#? 现在,如何使用C#检索通过引用返回的那些值? Meaning, how do I do the same thing in C# to get the returned structures to get my returned calculation? 意思是,我该如何在C#中执行相同的操作来获取返回的结构以获取返回的计算结果? I know I need to create an unsafe method, but I am unclear on how to deal with the memory addresses in C# like you would in C++. 我知道我需要创建一个不安全的方法,但是我不清楚如何像在C ++中那样处理C#中的内存地址。

Edit: Below states to use IntPtr but how do you place into identical structure so the fields of the structure can be referenced? 编辑:下面说明要使用IntPtr,但是如何将其放入相同的结构中,以便可以引用结构的字段?

Edit: Here is the returned structure that I am interested in (cout): 编辑:这是我感兴趣的返回结构(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

};

Here is the (cin) that I would pass along with other structures (they are zero byte at the moment, I want to get this to work first then I will implement the rest): 这是我将与其他结构一起传递的(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;

};

The char* parameters in this case are not strings but pointers to chunks of raw bytes representing the data. 在这种情况下,char *参数不是字符串,而是指向表示数据的原始字节块的指针。 You should marshal your parameters as instances of the IntPtr type, in conjunction with Marshal.AllocHGlobal to create a chunk of memory and then Marshal.PtrToStructure to convert that block of memory into a usable .NET type. 您应该将参数编组为IntPtr类型的实例,并与Marshal.AllocHGlobal一起创建一个内存块,然后与Marshal.PtrToStructure一起将该内存块转换为可用的.NET类型。

As an example: 举个例子:

[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: now that we have structures to work with, a better solution is possible. 编辑:现在我们有了可以使用的结构,可能有更好的解决方案。 Just declare structs in C# that match your C++ structs, and use them in the extern declaration 只需在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,
           ...



        ....

original answer (before we had structs) below 原始答案(在使用结构之前)


It appears to me that these are not references to internal strings, but rather pointers to string buffers that will be filled in by the call. 在我看来,这些不是对内部字符串的引用,而是对将由调用填充的字符串缓冲区的指针。 If you were returning string pointers, then these would be declared char** rather than char* . 如果要返回字符串指针,则将其声明为char**而不是char*

So I think these are just standard out parameters. 因此,我认为这些只是标准输出参数。 There's just a lot of them. 只有很多。 So your C# interop would look like this 所以您的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,

or this if your "strings" aren't really strings 或如果您的“字符串”不是真正的字符串

[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,
        ....

要回答您的Edit,您需要创建一个结构,然后在字段上使用StructLayoutAttribute来使字节顺序和填充与原始dll相同。

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

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