Тема: Отображение диалогового окна экспортируемой функцией

Значит есть следующее:
1. Простейший загрузочный ARX модуль созданный визардом в который добавлена единственная команда загружающая/выгружающая DLL и выполняющая единственную экспортируемую функцию:
Добавлена команда MYCOMMAND:

AddCommand("XXX", "MYCOMMAND", "MYCOMMAND", ACRX_CMD_TRANSPARENT | ACRX_CMD_USEPICKSET, MyCommand);

Собственно фукция:

typedef int (WINAPI *pMyFunction)();
void MyCommand()
{
    HINSTANCE hMyDll;
    if((hMyDll = ::LoadLibrary("MyDll.dll"))!=NULL)
    {
        pMyFunction pfnMyFunction;
        pfnMyFunction = (pMyFunction)GetProcAddress(hMyDll,"CommandFunction");
        int iCode=(*pfnMyFunction)();
        ::FreeLibrary(hMyDll);
    }
    else acutPrintf("\nError");
}

2. Создана библиотека MyDll.dll с единственной экспортируемой функцией CommandFunction. Библиотека создавалась при помощи MFC AppWizard (dll) с режимом “MFC Extension DLL”. Вот что имеем:

HINSTANCE _hdllInstance = NULL;
static AFX_EXTENSION_MODULE MyModuleDLL = { NULL, NULL };
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
    // Remove this if you use lpReserved
    UNREFERENCED_PARAMETER(lpReserved);
    if (dwReason == DLL_PROCESS_ATTACH)
    {
        TRACE0("OPTMODULE.DLL Initializing!\n");
        
        // Extension DLL one-time initialization
        if (!AfxInitExtensionModule(OptModuleDLL, hInstance))
            return 0;
        _hdllInstance = hInstance;
        new CDynLinkLibrary(MyModuleDLL);
    }
    else if (dwReason == DLL_PROCESS_DETACH)
    {
        TRACE0("OPTMODULE.DLL Terminating!\n");
        // Terminate the library before destructors are called
        AfxTermExtensionModule(MyModuleDLL);
    }
    return 1;   // ok
}

Экспортируемая функция, которая должна отображать простой диалог:

extern "C" BOOL CALLBACK CommandFunction()
{
    CMyDlg *WDialog;
    WDialog = new CMyDlg(CWnd::FromHandle(adsw_acadMainWnd()));
    WDialog->DoModal();
    delete WDialog;
    return TRUE;
}

В общем после загрузки и вызова команды MYCOMMAND акад спотыкается о строчку WDialog->DoModal() и вываливается. Если выгасить указанную строчку, то все работает великолепно.
Понятно что в этой ситуации происходит конфликт с ресурсами. Причем обращение к другим ресурсам в теле функции с использованием ::FindResource с указанием дескриптора _hdllInstance работает без сучка и задоринки.
Решение проблемы похоже зарыто в традиционном вызове CAcModuleResourceOverride resOverride. Но указывать его перед WDialog->DoModal() бессмысленно т.к. у нас не объявлен AC_IMPLEMENT_EXTENSION_MODULE.
Пытался вызывать acDocManager->pushResourceHandle и acDocManager->popResourceHandle - результат нулевой.
Вызов AFX_MANAGE_STATE(AfxGetStaticModuleState()) также ни к чему не приводит.
Перерыл весь http://discussion.autodesk.com/ но достойного решения моей проблемы там нет.
В связи с чем с возгласом о помощи обращаюсь к Вам, господа....

Re: Отображение диалогового окна экспортируемой функцией

Попробуй так:

extern "C" BOOL CALLBACK CommandFunction()
{
  CMyDlg *WDialog;
  HINSTANCE hCur = AfxGetResourceHandle();
  AfxSetResourceHandle(_hdllInstance);
  WDialog = new CMyDlg(CWnd::FromHandle(NULL));
  WDialog->DoModal();
  delete WDialog;
  AfxSetResourceHandle(hCur);
  return TRUE;
}

Re: Отображение диалогового окна экспортируемой функцией

> Александр Ривилис
Уже пробовал. Акад падает уже на строчке AfxGetResourceHandle(). Причем AfxSetResourceHandle(_hdllInstance) съедает без ругани - но увы ничего не происходит.
Даже пробовал как описано здесь: http://www.codeguru.com/Cpp/W-P/dll/article.php/c107/ - ничего не помогает. Просто тупик какой-то... :(((

Re: Отображение диалогового окна экспортируемой функцией

Вопрос снят, проблема решена. Никакого тупика нет, все генеальное просто... Генерить проект библиотеки надо так: MFC AppWizard (dll) без поддержки “MFC Extension DLL”.
Забываем про DllMain и во всю используем функции Afx... Все компилится и летает на "ура"...

Re: Отображение диалогового окна экспортируемой функцией

> Debalance
Я не зря написал тебе попробовать - у себя это проверил - работает (AutoCAD и ObjectARX 2006). Сделал точно так как ты описал. Я увидел, что ты используешь в DLL-функции из ObjectARX SDK (adsw_acadMainWnd()). Зря. Если это не arx-файл, то вызывать функции ObjectARX не следует, так как dll-файл не инициализирован, как arx-файл.
Кроме того я немного модифицировал arx-файл:

  void CallDll(void)
  {
    // Add your code for command CallDll.CallDll here
    typedef BOOL (CALLBACK *pMyFunction)();
    pMyFunction func;
    HMODULE hDll = ::LoadLibrary("MyDll.dll");
    if (hDll) {
      pMyFunction pfnMyFunction;
      pfnMyFunction = (pMyFunction)GetProcAddress(hDll,"CommandFunction");
      if (pfnMyFunction) {
        int iCode=(*pfnMyFunction)();
      } else {
        acutPrintf("\nОшибка GetProcAddress");
      }
      ::FreeLibrary(hDll);
    } else {
      acutPrintf("\nОшибка LoadLibrary");
    }
  }

У тебя не корректный typedef!!!
Кроме того DLL-файл следует компилировать с RELEASE библиотеками MFC - иначе крах:

#if defined(_DEBUG) && !defined(_FULLDEBUG_)
#define _DEBUG_WAS_DEFINED
#undef _DEBUG
#pragma message ("     Compiling MFC / STL / ATL header files in release mode.")
#endif
#include <afxwin.h>                //----- MFC core and standard components
#include <afxext.h>                //----- MFC extensions
#ifndef _AFX_NO_OLE_SUPPORT
#include <afxole.h>                //----- MFC OLE classes
#include <afxodlgs.h>            //----- MFC OLE dialog classes
#include <afxdisp.h>            //----- MFC Automation classes
#endif //----- _AFX_NO_OLE_SUPPORT
#ifndef _AFX_NO_DB_SUPPORT
#include <afxdb.h>                //----- MFC ODBC database classes
#endif //----- _AFX_NO_DB_SUPPORT
#ifndef _AFX_NO_DAO_SUPPORT
#include <afxdao.h>                //----- MFC DAO database classes
#endif //----- _AFX_NO_DAO_SUPPORT
#include <afxdtctl.h>            //----- MFC support for Internet Explorer 4 Common Controls
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h>                //----- MFC support for Windows Common Controls
#endif //----- _AFX_NO_AFXCMN_SUPPORT
//-----------------------------------------------------------------------------
#ifdef _DEBUG_WAS_DEFINED
#define _DEBUG
#undef _DEBUG_WAS_DEFINED
#endif

Ну если и это не поможет - пришли мне свой проект. Попробую разобраться в чем проблема. Только не забудь выкинуть лишнее и сархивировать его.

Re: Отображение диалогового окна экспортируемой функцией

> Александр Ривилис
Спасибо, Александр!
Да, действительно DEBUG крепко мешал. С RELEASE все работает без вопросов. Но для чего так накручено? Почему же отсутствует возможность компиляции с DEBUG библиотеками?
Кстати есть такой вопрос... В данный момент я работаю с OARX2002 под VC6. Если я скомпелю тело моего проекта (в данном случае это MyDll.dll) скажем из-под VC7.0 или VC7.1 со всеми lib'ами OARX2002 будет ли работать мое приложение под ACAD2000-2002?

Re: Отображение диалогового окна экспортируемой функцией

Debalance пишет:

Но для чего так накручено? Почему же отсутствует возможность компиляции с DEBUG библиотеками?

Все очень просто. AutoCAD и сам использует MFC библиотеки в Release. Arx-файл, это dll-файл работающий в том же адресном пространстве, что и AutoCAD. Одновременная загрузка в одно приложение MFC Debug и MFC Release невозможна (так уж его реализовала Microsoft). Так что остается выкручиваться.

Если я скомпелю тело моего проекта (в данном случае это MyDll.dll) скажем из-под VC7.0 или VC7.1 со всеми lib'ами OARX2002 будет ли работать мое приложение под ACAD2000-2002?

1) Еще раз повторяю - очень не рекомендую использовать функции ObjectARX в dll-файле - наверняка нарвешься на неприятности. Если нужно использовать функции ObjectARX - сделай arx-файл и грузи его как arx-файл.
2) Если ты не будешь использовать в этом dll-файле ни ObjectARX-функции, ни MFC-функции, то работать будет. Иначе нарвешься на неприятности. Например, на разные версии MFC в VC6 и VC7, которые между собой не совместимы.

Re: Отображение диалогового окна экспортируемой функцией

> Александр Ривилис
Александр, спасибо за рекомендации.
И тем не менее есть большое желание создать так называемый сплит-проект, когда основное тело программы вынесено в отдельный dll, а загрузка осуществляется при помощи arx-загрузчика.
Идея и стремления просты - проект не висит все время в памяти (в памяти находится загрузчик, размеры которого минимальны), а загружается по мере необходимости (когда пользователь набирает соответствующую команду). Кроме того есть возможность защиты от дезассемблирования основного модуля ну например каким-нибудь ASProtect'ом...

Re: Отображение диалогового окна экспортируемой функцией

1) Что касается "висения проекта в памяти" - все это ерунда на современных компьютерах. Какой размер dll-файла? Вряд ли десятки мегабайт. Важнее внимательнее использовать ограниченные ресурсы, пользоваться интеллектуальными указателями и т.д., чтобы ограничить утечки этих ресурсов. Более того ::FreeLibrary(hDll) не гарантирует реальную выгрузку dll-файла, т.е. освобождение занятой ею памяти.
2) Я бы не стал слишком полагаться на ASProtect, как и на другие аналогичные программы... Но если уж защищать, то можно защищать от дизасемблирования отдельные dll-файлы, которые выполняют какие-то важные расчеты, запрашивают от пользователя информацию в диалоговом окне, и т.д. Но это будут "чистые" dll-файлы, а не dll-файлы использующие ObjectARX-функции.
Но это все сугубо IMHO.

Re: Отображение диалогового окна экспортируемой функцией

> Александр Ривилис
>так как dll-файл не инициализирован, как arx-файл.
А что, arx-файлы инициализируются как-то особенно? smile
Я уже давно использую пустой arx-модуль, который вообще ничего не делает, а только переадресует вызовы в другие библиотеки (реально используется несколько dll и большинство из них используют возможности ObjectArx). И ничего... Правда, я не использую MFC - это постоянный источник неприятностей...

Re: Отображение диалогового окна экспортируемой функцией

Ну и замечательно! :)

Re: Отображение диалогового окна экспортируемой функцией

archimag пишет:

Я уже давно использую пустой arx-модуль, который вообще ничего не делает, а только переадресует вызовы в другие библиотеки...

Правильно ли я понимаю что Вы загружаете свою библиотеку ::LoadLibrary, а затем передете управление на точку входа задействуя IMAGE_NT_HEADERS? Где-то слышал о таком способе, но самому применять не доводилось...
Если программная реализация этого способа загрузки не представляет интеллектуально-коммерческой тайны, то попросил бы Вас (в целях повышения квалификации) опубликовать или выслать на мыло данный врагмент кода...

Re: Отображение диалогового окна экспортируемой функцией

> Debalance
Попробую объяснить свою систему.
Во-первых, по целому ряду причин я использую VC++7.1 (на самом деле, Microsoft Visual C++ Toolkit 2003). Фирма Autodesk считает, что использовать этот компилятор для написания arx-приложений нельзя smile, поэтому всячески препятствует непосредственной загрузке моих модулей.
Во-вторых, как я уже сказал, я разбиваю приложени на большое количество раздельно компилируемых модулей (dll). Это хорошо с точки зрения повторного использования и отладки относительно небольших кусков кода. Однако, если просто поместить все модули в одной папке, то Автокад не может их корректно загрузить. Ситуация усложняется тем, что в одном дистрибутиве могут быть несколько dll с одинаковым именем, но откомпилированные под разные версии Автокада.
Для решения этих проблем я использую загрузчик. Это arx-приложение, откомпилированное VC++7.0, в котором есть только acrxEntryPoint. В паре с ним идёт конфигурационый файл (в формате XML), в котором записаны зависимости и указ модуль, в котором находится реальная acrxEntryPoint. Загрузчик первым делом загружает все dll  (LoadLibrary), от которых зависит приложение, а затем загружает главный модуль, с точкой входой и передаёт на неё управление непосредственным вызовом.  Все последующие вызовы acrxEntryPoint загрузчик просто передает в главный модуль.
Вот. В общем, ничего военного или сложного. Исходный код это модуля ничего не даст, потому что он привязан к нашей системе каталогов и к нашим библиотекам.

Re: Отображение диалогового окна экспортируемой функцией

> archimag
Спасибо. Вполне исчерпывающий ответ.