информационная безопасность
без паники и всерьез
 подробно о проектеRambler's Top100
Все любят медАтака на Internet
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Крупный сбой Azure и других сервисов... 
 Серьезный сбой AWS положил множество... 
 Фишинговая атака на Python-разработчиков 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / форум / programming
Имя Пароль
ФОРУМ
если вы видите этот текст, отключите в настройках форума использование JavaScript
регистрация





Легенда:
  новое сообщение
  закрытая нитка
  новое сообщение
  в закрытой нитке
  старое сообщение
  • Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
  • Новичкам также крайне полезно ознакомиться с данным документом.
[C++] Mannaged код в DLL 29.09.03 09:34  
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка>
Я «немного» в шоке, после того, как попробовал создать DLL с управляемым кодом (.NET) для обычных приложений с «неуправляемым» кодом.
То, что для простых задач это работает легко (unmanaged в managed и наоборот) не обсуждается. Статьи есть на MSDN, да и сам делал - «Hello world» легко печатается из экспортируемой функции DLL с управляемым кодом. Но вот, когда я попросил NET использовать соглашение __stdcall в экпортируемых функциях, то компилятор выдал предупреждение, что моя просьба проигнорирована - __stdcall заменён модификатором __clrcall. Это может быть важным ( возможно не только для меня ) , если потребуется создать классы-обёртки для использования в неуправляемом коде управляемого кода DLL.

Например, есть декларация «интерфейсов» неких объектов, пусть, для работы с СУБД. Эти объекты расположены в DLL. Спецификация методов интерфейсов объектов, положим, в файле publicdbinterface.h:

// file publicdbinterface.h struct IUnknownInterface { virtual HRESULT __stdcall QueryInterface(LPCTSTR int_type, void **ppv) = 0; virtual void __stdcall CanErrorMessage(const int can_msg) = 0; virtual void __stdcall ErrorMessage(LPTSTR* outval ) = 0; … … }; // basic database interface definition struct IDatabaseInterface : public IUnknownInterface { virtual HRESULT __stdcall Open (void) = 0; virtual void __stdcall Delete(void) = 0; virtual void __stdcall Close (void) = 0; virtual void __stdcall Connection(LPCTSTR ConnectionStr) = 0; virtual HRESULT __stdcall StartTransaction(void) = 0; virtual HRESULT __stdcall InTransaction(void) = 0; virtual void __stdcall Commit (void) = 0; virtual void __stdcall Rollback(void) = 0; virtual void __stdcall TransIsolation(LPCTSTR type) = 0; … … }; typedef HRESULT (__stdcall *pCreateDatabaseInstance) (IDatabaseInterface ** pInterface, LPCTSTR inst_type); // end of cut

Положим, в DLL выполнен экспорт только одной функции CreateDatabaseInstance, которая при создании DLL была объявлена, как:

#define DB_API extern "C" __declspec(dllexport) DB_API HRESULT __stdcall CreateDatabaseInstance (IDatabaseInterface ** pInterface, LPCTSTR inst_type);

И имеет в простейшем случае реализацию, вроде:

HRESULT __stdcall CreateDatabaseInstance(IDatabaseInterface ** pInterface, LPCTSTR inst_type) { try { if( !_tcsicmp(inst_type, _TEXT("ODBC.MFC")) ) *pInterface = (IDatabaseInterface *) new CI_ODBCdb(); else if( !_tcsicmp(inst_type, _TEXT("ADO.MFC")) ) *pInterface = (IDatabaseInterface *) new CI_ADOdb(); else *pInterface = NULL; } catch(...) { *pInterface = NULL; return E_FAIL; } return ( *pInterface )? S_OK : E_FAIL; }

Всё, что выше – это для «неуправляемого» кода (приложения и DLL). Например, программист здесь может выполнить следующие обычные вызовы типа:

HINSTANCE hlib; pCreateDatabaseInstance CreateDatabaseInstance; void _tmain( void ) { hlib = LoadLibrary(_TEXT("mydb.dll")); if (!hlib) { _tprintf(_TEXT("Can't load library")); return; } CreateDatabaseInstance = (pCreateDatabaseInstance) GetProcAddress(hlib,_TEXT("CreateDatabaseInstance")); if (!CreateDatabaseInstance ) { _tprintf(_TEXT("Function CreateDatabaseInstance not found\n")); FreeLibrary(hlib); return; } IDatabaseInterface* IDatabase; if( FAILED( CreateDatabaseInstance(&IDatabase, _TEXT("BDE") )) ) { _tprintf(_TEXT("...Can't create BDE database instance\n")); FreeLibrary(hlib); return; } IDatabase->Connection( _TEXT("ExampleDB") ); if( FAILED( IDatabase->StartTransaction() ) ) { IQuery->Delete(); IDatabase->Delete(); FreeLibrary(hlib); _tprintf(_TEXT("Can't open transaction\n")); return; } … … … }


В этом коде консольного приложения и коде DLL нет ничего, что касалось бы managed. Но, положим, захотелось сделать так, чтобы «обернуть» классы ADO.NET для работы с СУБД и «расширить» указанную выше DLL. Если попытаться пойти проторенной дорожной (как для обычных DLL), и попробовать создать в managed-DLL класс, типа того, что ниже – это будет крах:

// msadonet.h #include "publicdbinterface.h" #using <System.dll> #using <System.Data.dll> using namespace System; using namespace System::Data; using namespace System::Data::OleDb; #define DB_API extern "C" __declspec(dllexport) namespace msadonet { DB_API HRESULT __stdcall CreateDatabaseInstance (IDatabaseInterface ** pInterface, LPCTSTR inst_type); class CI_ADONETdb: public IDatabaseInterface { private: OleDbConnection* Database; … … public: CI_ADONETdb(); ~CI_ADONETdb(); // IDatabaseInterface HRESULT __stdcall Open( void ); void __stdcall Delete( void ); … … // IUnknownInterface HRESULT __stdcall QueryInterface(LPCTSTR int_type, void **ppv); void __stdcall CanErrorMessage(const int can_msg); void __stdcall ErrorMessage(LPTSTR* outval); … … }; } // end file msadonet.h

Это не компилируется, поскольку нельзя в неуправляемом коде (класс CI_ADONETdb, см. выше) использовать ссылки на объекты классов, которые работают только под CLR (указатель OleDbConnection* Database, см. выше).

Положение можно «подправить», сделав код класса CI_ADONETdb управляемым:

public __gc class CI_ADONETdb: public IDatabaseInterface { private: OleDbConnection* Database; … … };

Но при этом «просто так» снова не получится. Компилятор выдаст ошибку – нельзя managed классы наследовать от unmanaged. Поэтому придётся переписать и интерфейсы IDatabaseInterface и IUnknownInterface, чтобы сделать их managed тоже.
Т.е. то, что было написано выше относительно «чисто абстрактных» классов IDatabaseInterface и IUnknownInterface теперь придётся изменить на следующее:

public __gc class IUnknownInterface { virtual HRESULT __stdcall QueryInterface(LPCTSTR int_type, void **ppv) … … }; public __gc class IDatabaseInterface : public IUnknownInterface { virtual HRESULT __stdcall Open (void) = 0; … … };

Результат таков – копилируется. При этом компилятор сообщает о предупреждении - warning C4440: calling convention redefinition from '__clrcall ' to '__stdcall ' ignored.
То, что компилируется – не большое утешение. Я уже не могу использовать эту DLL в своих проектах из–за ignored '__clrcall ' to '__stdcall '. Несмотря на то, что DLL компилируется, даже пробовать использовать её не стоит.

Как мне быть? Как «обернуть» объекты типа OleDbConnection так, чтобы сохранить соглашения __stdcall, указанные в начале моего поста?
1




Rambler's Top100
Рейтинг@Mail.ru


  Copyright © 2001-2025 Dmitry Leonov   Page build time: 0 s   Design: Vadim Derkach