Pointeurs en C # pour récupérer Référence De DllImport Fonction
-
23-09-2019 - |
Question
Je suis référence à une DLL dans mon projet C # comme suit:
[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 fonction FeeCalculation est exportée comme suit dans la 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 fonction DLL renvoie une référence à sa structure interne sous la forme de char * si vous deviez faire référence à cette DLL en C ++, vous procédez comme suit pour faire le calcul et obtenir les structures retournées:
FeeCalculation(buff, (char *)&fans, (char *)fl, (char *)ft, (char *)fw, (char *)fi, (char *)fe, (char *)&fm, (char *)val, (char *)cpn);
Maintenant, comment puis-je récupérer les valeurs renvoyées par référence en utilisant C #? Ce qui signifie, comment dois-je faire la même chose en C # pour obtenir les structures de retour pour obtenir mon calcul retourné? Je sais que je dois créer une méthode dangereuse, mais je ne suis pas clair sur la façon de traiter avec les adresses mémoire en C # comme vous le feriez en C ++.
Modifier: Ci-dessous les États à utiliser IntPtr mais comment situez-vous dans la structure identique pour que les champs de la structure peuvent être référencées
Edit: Voici la structure de retour que je suis intéressé par (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
};
Voici le (cin) que je passerais ainsi que d'autres structures (ils sont nuls octets au moment, je veux que cela fonctionne d'abord je vais mettre en œuvre le reste):
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;
};
La solution
Edit: maintenant que nous avons des structures pour travailler avec, une meilleure solution est possible. Il suffit de déclarer struct en C # qui correspondent à vos struct C ++ de, et de les utiliser dans la déclaration 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,
...
....
réponse originale (avant que nous ayons struct) ci-dessous
Il me semble que ce ne sont pas des références à des chaînes internes, mais plutôt des pointeurs vers des tampons de chaîne qui seront comblées par l'appel. Si vous étiez retournaient pointeurs de chaîne, puis ceux-ci seraient déclarés char**
plutôt que char*
.
Je pense donc que ce ne sont que des paramètres standard sur. Il y a juste beaucoup d'entre eux. Donc, votre C # Interop ressemblerait à ceci
[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,
ou ceci si vos « chaînes » ne sont pas vraiment des chaînes
[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,
....
Autres conseils
Les paramètres char * dans ce cas ne sont pas des chaînes, mais des pointeurs vers des morceaux d'octets bruts représentant les données. Vous devez rassembler vos paramètres comme les instances du type IntPtr, en collaboration avec Marshal.AllocHGlobal pour créer un morceau de mémoire, puis Marshal.PtrToStructure pour convertir ce bloc de mémoire dans un type .NET utilisable.
Par exemple:
[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);
}
Pour répondre à votre édition, vous devez créer un struct, puis utilisez la balise StructLayoutAttribute sur les champs afin de rendre l'ordre des octets et le remplissage identique à la dll d'origine a fait.