كيفية القيام بما يلي: تنظيم وإرسال المؤشرات المضمنة باستخدام PInvoke

يمكن استدعاء الوظائف التي يتم تنفيذها في DLLs الغير المدارة من التعليمات البرمجية المدارة باستخدام وظيفة "استدعاء (Invoke) النظام الأساسي" (P/Invoke). في حالة عدم توفر مصدر التعليمات البرمجية لـ DLL فإن P/Invoke هو الخيار الوحيد للتفاعل . ومع ذلك، بخلاف لغات .NET الأخرى , ++Visual C يوفر بديل ل P/Invoke. للمزيد من المعلومات، راجع استخدام PInvoke) C++ Interop الضمني ) وكيفية القيام بما يلي: تنظيم وارسال المؤشرات المضمنة بـاستخدام C++ Interop.

مثال

تمرير بنيات لتعليمة برمجية أصلية يتطلب إنشاء بنية مدارة مكافئة من جهة تخطيط بيانات البنية الأصلية. ومع ذلك، تطلب البنيات التي تحتوي على مؤشرات معالجة خاصة. بالنسبة لكل مؤشر مضمن في البنية الأصلية يجب أن يحتوي الإصدار المدار من البنية على مثيل من نوع IntPtr . أيضاً، يجب أن يتم تخصيص ذاكرة هذه المثيلات بشكل صريح، و تهيئتها ثم إصدارها باستخدام الأساليب AllocCoTaskMem ، و StructureToPtr ، و FreeCoTaskMem.

التعليمات البرمجية التالية تتألف من وحدات نمطية مدارة و غير مدارة. الوحدة النمطية الغير المدارة هي DLL تُعرف الدالة التي تقبل بنية تسمى ListString تحتوي على مؤشر ، و دالة تسمى TakesListStruct. الوحدة النمطية المدارة هي تطبيق سطر أوامر يستورد دالة TakesListStruct و يقوم بتعريف بنية تسمى MListStruct مكافئة لـ ListStruct الأصلي، فيما عدا أن double* يتم تمثيله بمثيل IntPtr . قبل استدعاء TakesListStruct, تخصص الدالة الرئيسية الذاكرة التى يشير إليها هذا الحقل ثم تهيؤها.

يتم برمجيا ترجمة الوحدة النمطية المُدارة بواسطة /clr ولكن /clr:pure يصلح أيضاً .

// TraditionalDll6.cpp
// compile with: /EHsc /LD
#include <stdio.h>
#include <iostream>
#define TRADITIONALDLL_EXPORTS
#ifdef TRADITIONALDLL_EXPORTS
#define TRADITIONALDLL_API __declspec(dllexport)
#else
#define TRADITIONALDLL_API __declspec(dllimport)
#endif

#pragma pack(push, 8)
struct ListStruct {
   int count;
   double* item;
};
#pragma pack(pop)

extern "C" {
   TRADITIONALDLL_API void TakesListStruct(ListStruct);
}

void TakesListStruct(ListStruct list) {
   printf_s("[unmanaged] count = %d\n", list.count);
   for (int i=0; i<list.count; i++)
      printf_s("array[%d] = %f\n", i, list.item[i]);
}

// EmbeddedPointerMarshalling.cpp
// compile with: /clr
using namespace System;
using namespace System::Runtime::InteropServices;

[StructLayout(LayoutKind::Sequential, Pack=8)]
value struct MListStruct {
   int count;
   IntPtr item;
};

value struct TraditionalDLL {
    [DllImport("TraditionalDLL6.dll")]
   static public void TakesListStruct(MListStruct);
};

int main() {
   array<double>^ parray = gcnew array<double>(10);
   Console::WriteLine("[managed] count = {0}", parray->Length);

   Random^ r = gcnew Random();
   for (int i=0; i<parray->Length; i++) {
      parray[i] = r->NextDouble() * 100.0;
      Console::WriteLine("array[{0}] = {1}", i, parray[i]);
   }

   int size = Marshal::SizeOf(double::typeid);
   MListStruct list;
   list.count = parray->Length;
   list.item = Marshal::AllocCoTaskMem(size * parray->Length);

   for (int i=0; i<parray->Length; i++) {
      IntPtr t = IntPtr(list.item.ToInt32() + i * size);
      Marshal::StructureToPtr(parray[i], t, false);
   }

   TraditionalDLL::TakesListStruct( list );
   Marshal::FreeCoTaskMem(list.item);
}

لاحظ انه لا يوجد جزء من DLL يتعرض للتعليمات البرمجية المدارة باستخدام توجيه # التقليدي. في الحقيقة، الوصول إلى DLL يتم في وقت التشغيل فقط ،لذلك المشاكل مع الدالات المستوردة معDllImportAttribute لن يتم الكشف عنها في وقت التحويل البرمجي.

راجع أيضًا:

موارد أخرى

استخدام PInvoke Explicit في ++C (سمة DllImport)