بســم الله الـرحمــن الرحيــم
السلام عليكــم ورحمـة الله وبركاتــة
عملت جاهدا خلال أكثر من أسبوعين لحل هذه المشكلة، ولكن دون جدوى، لذا أرجو التكرم بالنظر فيها، فقد أجد ضالتي في هذا المنتدى المبارك.
يقوم برنامجي بنداء أحد الأوامر من مكتبة خارجية ، أي أن هذا الأمر مسجل في ملف (DLL) كما ستشاهد في الكود المرفق. هذه المكتبة تم عملها بواسطة سي بلس بلس (وليس دوت نيت) أي أنه لايمكن التعامل معها على أنها Assembly.
عند محاولة تنفيذ بعض الأوامر التي لا تأخذ متغيرات، أو تأخذ متغيرات من النوع integer فقط، فإن كل شي يعمل بشكل سليم
المشكلة هي مع أحد الأوامر والتي تعيد مصفوفة طويلة لـ structure (مع ملاحظة أن هناك أمر آخر يرجع لي طول المصفوفة ويمكن استخدام قيمته لحجز ذاكرة كافية فيما بعد)
ما يلي هو ترويسة C للأمر المراد استخدامه (وهو ما يتطلب التعامل معه بالـ سي شارب)
///////////////////////////////////////////////////////
// C DLL header for Read_Log function and structure //
///////////////////////////////////////////////////////
typedef struct {
unsigned int id;
unsigned short year;
unsigned char month;
unsigned char day;
unsigned char hour;
unsigned char min;
unsigned char sec;
unsigned char log_data;
} Log_Struct;
int Read_Log (int op, int flag, unsigned char *log)ولتحويل ما سبق إلى سي شارب قمت بعمل ما يلي
///////////////////////////////////////////////////////
// C# //
///////////////////////////////////////////////////////
[StructLayout(LayoutKind.Sequential)]
struct LogStruct
{
UInt32 id;
UInt16 year;
Byte day;
Byte hour;
Byte min;
Byte sec;
Byte log_data;
}
[DllImport("TheDll.dll")]
static extern int Read_Log(int op, int flag, out IntPtr log);عملية النداء للأمر Read_Log من السي شارب تتم بشكل سليم، وترجع القيمة 1 وذلك دليل نجاحها، كما أن الباراميتر الأخير log يحتوي على نتيجة وليس صفر. يعني أنه أصبح معبأ بالقيمة المطلوبة
مشكلتي هنا بالضبط، كيف أحول هذه القيمة إلى مصفوفة من الـ structure حتى أتمكن من التعامل مع القيم الموجودة فيها.
قمت بما يلي كمحاولة لحل المشكلة ولكن لم تنفع، وربما أكون قريب من الحل بحيث لا أراه:
LogStruct[] GetLogs(int op, int flag)
{
IntPtr logStructPtr = IntPtr.Zero;
int numOfStructs = TestPInvoke.Read_Log(op, flag, out logStructPtr);
LogStruct[] logStructs = new LogStruct[numOfStructs];
for (int logLoop = 0; logLoop < numOfStructs; logLoop++)
{
logStructs[logLoop] = (LogStruct)Marshal.PtrToStructure(logStructPtr, typeof(LogStruct));
logStructPtr = (IntPtr)((int)logStructPtr + Marshal.SizeOf(typeof(LogStruct)));
}
return logStructs;
}هناك ملاحظة جديرة بالذكر، وهي ، عندما أحاول استبدال نوع المتغير log في ترويسة الأمر بحيث أضع LogStruct بدلا من IntPtr ، فإن نتيجة تنفيذ الأمر تكون السجل الأول فقط، ولكن عندما أضع البوينتر وأحاول قراءته أو الدوران معه بالشكل السابق ، أحصل على AccessViolationException من الدورة الأولى (الصفرية) مباشرة. ذلك للسطر
logStructs[logLoop] = (LogStruct)Marshal.PtrToStructure(logStructPtr, typeof(LogStruct));
أعتقد أن مشكلتي هي في عدم فهمي لطريقة عمل البوينترز وكيفية التعامل معها، بحثت حول الإنترنت كثيرا وهذا ما تمكنت من كتابته حتى الآن ودون جدوى
لذا أرجو إن كان لدى أحد الخبراء حل ، أن يعاجلني به مشكورا
تحياتي
حامد