Nasıl yapılır: P/Invoke kullanarak eklenmiş işaretçileri hazırlama
Yönetilmeyen DLL'lerde uygulanan işlevler, Platform Çağırma (P/Invoke) işlevi kullanılarak yönetilen koddan çağrılabilir. DLL'nin kaynak kodu kullanılamıyorsa, birlikte çalışmak için tek seçenek P/Invoke'tır. Ancak, diğer .NET dillerinden farklı olarak, Visual C++ P/Invoke'a bir alternatif sağlar. Daha fazla bilgi için bkz . C++ Birlikte Çalışma Kullanma (Örtük P/Invoke) ve Nasıl yapılır: C++ Birlikte Çalışma kullanarak eklenmiş işaretçileri hazırlama.
Örnek
Yapıların yerel koda geçirilmesi, veri düzeni açısından yerel yapıya eşdeğer bir yönetilen yapının oluşturulmasını gerektirir. Ancak, işaretçiler içeren yapılar özel işleme gerektirir. Yerel yapıdaki her eklenmiş işaretçi için, yapının yönetilen sürümü türün bir örneğini IntPtr içermelidir. Ayrıca, bu örnekler için bellek açıkça ayrılmalı, başlatılmalı ve , StructureToPtrve FreeCoTaskMem yöntemleri kullanılarak AllocCoTaskMemserbest bırakılmalıdır.
Aşağıdaki kod yönetilmeyen ve yönetilen bir modülden oluşur. Yönetilmeyen modül, işaretçi içeren adlı bir yapıyı ve adlı ListString
TakesListStruct
bir işlevi kabul eden bir işlevi tanımlayan bir DLL'dir.
// 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]);
}
Yönetilen modül, işlevini içeri aktaran TakesListStruct
ve yerel ile eşdeğer ListStruct
olarak adlandırılan MListStruct
bir yapıyı tanımlayan bir komut satırı uygulamasıdır, ancak double*
örneğiyle IntPtr temsil edilir. çağrısından TakesListStruct
main
önce işlev, bu alanın başvurduğunu belleği ayırır ve başlatır.
// 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'nin hiçbir bölümü, geleneksel #include
yönerge kullanılarak yönetilen koda sunulmaz. Aslında DLL'ye yalnızca çalışma zamanında erişilir, bu nedenle kullanılarak DllImportAttribute içeri aktarılan işlevlerdeki sorunlar derleme zamanında algılanamaz.