Puntatori in C# per Recuperare Riferimento Da DllImport Funzione
-
23-09-2019 - |
Domanda
Io sono il riferimento a una DLL nel mio progetto C# come segue:
[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);
Il FeeCalculation funzione viene esportato come segue 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 DLL funzione restituisce un riferimento interno di strutture a forma di char * quindi, se si dovesse fare riferimento a questa DLL in C++, si deve fare il calcolo e il ottenere il restituiti strutture:
FeeCalculation(buff, (char *)&fans, (char *)fl, (char *)ft, (char *)fw, (char *)fi, (char *)fe, (char *)&fm, (char *)val, (char *)cpn);
Ora, come faccio a recuperare quei valori che sono tornato da riferimento per l'utilizzo di C#?Significato, come faccio a fare la stessa cosa in C# per ottenere il restituiti strutture per ottenere il mio restituito calcolo?So che ho bisogno di creare un sicuro metodo, ma io sono poco chiare su come trattare con gli indirizzi di memoria in C# come in C++.
Edit:Al di sotto di membri, di utilizzare IntPtr ma come si fa luogo, in identica struttura così i campi della struttura è possibile fare riferimento?
Edit:Qui è tornato struttura che mi interessa (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
};
Qui è l' (cin) che vorrei passare insieme con le altre strutture (che sono pari a zero byte al momento, voglio ottenere questo lavoro prima, poi mi attuare il 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;
};
Soluzione
Edit:ora che abbiamo strutture a lavorare, una soluzione migliore è possibile.Dichiarare nelle strutture in C# che corrispondono ai tuoi C++ le strutture da utilizzare per la dichiarazione 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,
...
....
originale risposta (prima avevamo struct) qui sotto
A me sembra che questi non sono i riferimenti interni corde, ma piuttosto puntatori a stringa buffer che sarà riempito dalla chiamata.Se si fosse di ritorno i puntatori di stringa, quindi questi sarebbero dichiarati char**
piuttosto che char*
.
Quindi penso che questi sono solo standard parametri.C'è solo un sacco di loro.Così il C# interoperabilità sarebbe simile a questa
[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 questo se il tuo "stringhe" non sono realmente stringhe
[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,
....
Altri suggerimenti
I char * parametri in questo caso non sono stringhe, ma i puntatori ai blocchi di byte non elaborati che rappresentano i dati. Si dovrebbe schierare i parametri come le istanze del tipo IntPtr, in collaborazione con Marshal.AllocHGlobal per creare un pezzo di memoria e quindi Marshal.PtrToStructure convertire tale blocco di memoria in un tipo NET utilizzabili.
Per fare un esempio:
[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);
}
Per rispondere alla tua Edit, è necessario creare una struttura, e quindi utilizzare il StructLayoutAttribute sui campi al fine di rendere l'ordine dei byte e imbottitura lo stesso come la dll originale ha fatto.