مؤشرات في C# لاسترداد المرجع من وظيفة Dllimport
-
23-09-2019 - |
سؤال
أنا أشير إلى DLL في مشروع C# الخاص بي على النحو التالي:
[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);
يتم تصدير وظيفة الإثارة على النحو التالي في 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*
.
لذلك أعتقد أن هذه مجرد معلمات قياسية. هناك الكثير منهم فقط. لذا فإن interop 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 ، بالتزامن مع مارشال لإنشاء جزء من الذاكرة ثم مارشال لتحويل تلك الكتلة من الذاكرة إلى نوع .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);
}
للإجابة على تحريرك ، تحتاج إلى إنشاء بنية ، ثم استخدام structLayOutAttribute في الحقول من أجل جعل ترتيب البايت وحشو نفس DLL الأصلي.