Ранее я рассказывал здесь о проблеме создания библиотеки
DLL в Visual С++ 2005 Express Edition и её вызове из Maple. Эта проблема решиласть. Я благодарю всех, кто откликнулся и помог нам. По результатам проведённых вычислений мной и моими студентами была написана статья
arXiv:1601.00636. В
приложении к этой статье приведены исходные файлы DLL библиотеки, а также
makefile и
makefile.bat для их компиляции. DLL библиотека создаётся запуском
makefile.bat. В этом файле используется переменная окружения
VS80COMNTOOLS, которая соответствует Visual Studio 8. Если у Вас в Program Files стоит Visual Studio 9 или Visual Studio 10, то
makefile.bat следует отредактировать и заменить
VS80COMNTOOLS на
VS90COMNTOOLS или
VS100COMNTOOLS соответственно. Проверено, что во всех этих случаях библиотека DLL успешно создаётся и успешно работает при вызове из Maple 9, Maple 13 и Maple 16. Maple 9 и Visual Studio 8 использовались в Windows XP. В остальных случаях все происходило на платформе Windows 7.
Теперь мы решили сделать код независимым от Maple, заменив его оконным приложением, написанным на С++. Менять код DLL библиотеки, способ её создания, а также линковать её к с оконным приложением на С++ не хочется. Делается это для того, чтобы впоследствии студенты смогли в качестве тренировки создавать оболочки на Delphi, Java и может быть даже на HTML+Java Script к одной и той же DLL библиотеке.
Теперь опишу проблему. В графическом конструкторе Visual С++ создаю оконное приложение с одной формой и несколькими кнопками на ней. Образуются два файла
ProjectName.cpp и
Form1.h. Первый я вообще не трогаю. А во второй дописываю свой код.
#include "windows.h"
#include "string.h"
#include <stdio.h>
namespace ProjectName {
............................................................
public ref class Form1 : public System::Windows::Forms::Form
{
private:
// добавляю поля класса Form1
HMODULE My_DLL_Handle;
LPCWSTR My_DLL_WName;
LPCSTR My_Proc_Name;
char * My_buffer;
typedef unsigned int (__stdcall * Load_Cuboid_Binaries_ptr)();
Load_Cuboid_Binaries_ptr Load_Cuboid_Binaries;
unsigned int My_Proc_Result;
// далее следует метод, который является конструктором
public:
Form1(void)
{
InitializeComponent();
//TODO: Add the constructor code here
// Сказано дрбавлять - значит добавляю
this->My_DLL_WName = L"C:\\users\\...\\Cuboid_search_v01.dll";
this->My_Proc_Result = 1;
this->My_DLL_Handle = LoadLibrary(My_DLL_WName);
this->My_Proc_Result = GetLastError(); // здесь в отладчике код ошибки 0, библиотека грузится
this->My_buffer = new char[64];
sprintf(My_buffer,"My_DLL_Handle =%I32X",My_DLL_Handle);
this->My_Proc_Name = "_Load_Cuboid_Binaries@0";
this->My_Proc_Result = 1;
this->Load_Cuboid_Binaries = (Load_Cuboid_Binaries_ptr)GetProcAddress(My_DLL_Handle,My_Proc_Name);
this->My_Proc_Result = GetLastError(); // здесь в отладчике код ошибки тоже 0
// это значит функция Load_Cuboid_Binaries в библиотеке найдена
// однако указатель Load_Cuboid_Binaries в отладчике даёт <undefined value>
sprintf(My_buffer,"Load_Cuboid_Binaries=%I32X",Load_Cuboid_Binaries);
// после преобразования в строку видно, что указатель нулевой
}
protected:
...............................................................
private:
// здесь реакция на нажатие кнопки
System::Void button1_Click(System::Object^ sender,System::EventArgs^ e)
{
this->My_Proc_Result = this->Load_Cuboid_Binaries();
// она ожидаемым образом приводит к ошибке unhandled exception
// Attempted to read or write protected memory
}
};
}
Точками я обозначил стандартный код, графическим конструктором форм Visual С++. Спецификатор
this-> можно везде убрать. Он ни на что не влияет.
Резюмируя сказанное в комментариях к коду, скажу, что библиотека грузится, требуемая функция в ней находится, хотя имя функции слегка искажено. Это я учитываю при вызове GetProcAddress. Функция GetProcAddress срабатывает с нулевым кодом ошибки, но возвращает нулевой указатель (NULL), который не может использоваться для вызова функции Load_Cuboid_Binaries() в загруженной библиотеке DLL. Пожалуйста, помогите разобраться в чём дело.