информационная безопасность
без паники и всерьез
 подробно о проектеRambler's Top100
Spanning Tree Protocol: недокументированное применениеАтака на InternetСетевые кракеры и правда о деле Левина
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Очередное исследование 19 миллиардов... 
 Оптимизация ввода-вывода как инструмент... 
 Зловреды выбирают Lisp и Delphi 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / форум / programming
Имя Пароль
если вы видите этот текст, отключите в настройках форума использование JavaScript
ФОРУМ
все доски
FAQ
IRC
новые сообщения
site updates
guestbook
beginners
sysadmin
programming
operating systems
theory
web building
software
hardware
networking
law
hacking
gadgets
job
dnet
humor
miscellaneous
scrap
регистрация





Легенда:
  новое сообщение
  закрытая нитка
  новое сообщение
  в закрытой нитке
  старое сообщение
[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