Pregunta

Me estoy refiriendo a una DLL en mi proyecto de C # de la siguiente manera:

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

La función FeeCalculation se exporta como sigue en el 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);

La función DLL devuelve una referencia a su estructura interna en forma de char * por lo que si se va a hacer referencia a este archivo DLL en C ++, tendría que hacer lo siguiente para hacer el cálculo y obtener las estructuras devueltos:

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

Ahora, ¿cómo puedo recuperar esos valores devueltos por referencia usando C #? Es decir, ¿cómo lo hago lo mismo en C # para obtener las estructuras vuelto a conseguir mis cálculos vuelto? Sé que necesito para crear un método inseguro, pero no tengo muy claro sobre cómo tratar con las direcciones de memoria en C # como lo haría en C ++.

Editar:? A continuación los estados utilizar IntPtr pero ¿cómo colocan en una estructura idéntica por lo que se puede hacer referencia a los campos de la estructura

Edit: Aquí está la estructura devuelta que estoy interesado en (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

};

Esta es la (CIN) que iba a pasar junto con otras estructuras (son cero byte en este momento, quiero conseguir que esto funcione primero y luego voy a poner en práctica el resto):

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;

};
¿Fue útil?

Solución

Edit: ahora que tenemos estructuras de trabajar, una solución mejor es posible. Sólo declarar estructuras en C # que responden a su C ++ estructuras, y utilizarlos en la declaración externa

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



        ....

respuesta original (antes de tener estructuras) a continuación


Me parece que estas no son las referencias a las cadenas internas, sino más bien punteros a buffers de cadena que serán llenados por la llamada. Si se va regresando punteros de cadena, char** entonces estos serían declarados en lugar de char*.

Así que creo que estos son sólo parámetros out estándar. Sólo hay un montón de ellos. Por lo que su C # interoperabilidad se vería así

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

o esto si sus "cadenas" no son realmente cadenas

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

Otros consejos

El char * parámetros en este caso no son secuencias pero punteros a trozos de bytes que representan los datos en bruto. Usted debe reunir sus parámetros como las instancias del tipo IntPtr, conjuntamente con Marshal.AllocHGlobal para crear un trozo de la memoria y luego Marshal.PtrToStructure para convertir ese bloque de memoria en un tipo de .NET utilizable.

A modo de ejemplo:

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

Para responder a su edición, es necesario crear una estructura, y luego usar el StructLayoutAttribute en los campos con el fin de hacer que el orden de los bytes y el relleno de la misma que la DLL original, lo hicieron.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top