Вот вывод, который я получил от dumpbin.exe. Попытайтесь теперь понять причину неудачи.
Microsoft (R) COFF Binary File Dumper Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
Dump of file C:/Debug/MyDLL.dll
File Type: DLL
Section contains the following exports for MyDll.dll
0 characteristics
40A4A315 time date stamp Fri May 14 14:44:37 2004
0.00 version
1 ordinal base
12 number of functions
12 number of names
ordinal hint RVA name
1 0 00012186 ??0Geometry@@QAE@HH@Z
2 1 0001287F ??0Geometry@@QAE@XZ
3 2 00012569 ??1Geometry@@QAE@XZ
4 3 000125DC ??4Geometry@@QAEAAV0@ABV0@@Z
5 4 000126F9 ?AllocMatrix@@YAXAAPAPANHH@Z
6 5 0001271C ?ClearMatrix@@YAXAAPAPANH@Z
7 6 000127CB ?Gauss@@YA_NPAPANPANH@Z
8 7 000126A4 ?Init@Geometry@@AAEXHH@Z
9 8 0001281B ?Say@Geometry@@QAEPADXZ
10 9 00012389 ?Solve@@YA_NPAVGeometry@@AAPAPANHH@Z
11 A 0003BB40 ?error@@3PADA
12 B 0003CF00 ?progress@@3HA
Summary
4000 .data
1000 .idata
5000 .rdata
2000 .reloc
24000 .text
11000 .textbss
Дело в том, что имена всех экспортируемых функций декорированы, поэтому они не могут быть вызваны по имени из управляемого кода. Неуправляемый код, как мы видели, прекрасно справляется с этой задачей, а управляемый — нет. Выхода два: отказаться от декораций или вызывать по порядковому номеру (см. в дампе колонку ordinal).
Опять сошлюсь на то, что время бежит неумолимо. В указанной выше статье приведено другое решение: Устранить декорирование имен автоматически (с помощью утилиты VisualDumpbin).
Второй способ напомнил мне о COM и Mighty Basic. Там для вызова функции с помощью метода Invoke, провозглашенного интерфейсом IDispatch, используется индекс типа DISPID. Суть та же, но DISPID'ами мы управляем одним способом, а этими номерками — другим. Например, мы можем их задать их в DEF-файле. Как вы помните, мы пошли другим путем — путем __declspec(dllexport), поэтому номерки присвоены функциям автоматически.
Немного о декорации. Например, функция void test() декорируется компилятором С++ следующим образом: ?test@@ZAXXZ (прелесть, неправда, ли?). А вот функция void __stdcall test() будет декорирована иначе: ?test@@YGXXZ (тоже красивая). Та же функция test, но с другим способом передачи параметров — через регистр (__fastcall) будет декорирована так: ?test@@YIXXZ. Если функция имеет совмещенную версию с другим набором параметров (например, void test(int)), то декорация опять изменится. В настоящее время нет стандарта на то, как декорировать имена, поэтому разные компиляторы делают это по-разному.
Как вы уже поняли, управляемый код пытается устранить все неопределенности, а декорация имен вносит беспорядок в стройную систему типов и отношений платформы .NET. Видимо, лучше от нее отазаться, но перед этим рассмотрим все-таки, как вызвать функцию по номеру, оставив при этом декорацию имен. Для этого надо рассмотреть дамп, выяснить порядковые номера функций и использовать их в атрибутах имортируемых функций. Внесите изменения, показанные ниже, и проверьте работу клиентского приложения.
[DllImport("C:/Debug/MyDLL.dll", EntryPoint="#5",
CallingConvention=CallingConvention.StdCall)]
public unsafe static extern void AllocMatrix (ref double** a, int ny, int nx);
[DllImport("C:/Debug/MyDLL.dll", EntryPoint="#6")]
public unsafe static extern void ClearMatrix (ref double** a, int n);
[DllImport("C:/Debug/MyDLL.dll", EntryPoint="#7")]
public unsafe static extern bool Gauss (double** a, double[] x, int n);
Числа 5, 6 и 7 соответствуют декорированным именам, которые теперь не нужны для того, чтобы правильно определить точку входа. Атрибут CallingConvention можно опустить, он приведен с целью иллюстрации технологии. Запустите клиента, он должен работать.
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.