Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Окно из DLL

12K
24 августа 2008 года
Sholah_Weras
99 / / 04.12.2007
Доброго времени суток!

Задача - сделать lib в которой бы создавалось окно, а в основной программе вызывалась функция по созданию этого окна из lib.

Есть код (сразу скажу, что взял в инете):

Основная программа (без проверок критичных мест):
Код:
#include "stdafx.h"
#include "windows.h"

typedef BOOL (CALLBACK * MY_FUNC)();
MY_FUNC ShowWnd;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR cmdline, int ShowCmd)
{
    HMODULE dll = LoadLibrary("myLib.lib");

    ShowWnd = (MY_FUNC)GetProcAddress(GetModuleHandleA("myLib.lib"), "ShowWnd");   
    ShowWnd();


    FreeLibrary(dll);
    return 0;
}


И сама lib:

Код:
#include "windows.h"

HINSTANCE hInstance;
HWND      hwnd;

LRESULT CALLBACK DllWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);

BOOL APIENTRY DllMain(HINSTANCE hModule,DWORD dwReason,LPVOID)
{
    switch(dwReason)
    {
    case DLL_PROCESS_ATTACH:
        WNDCLASS wnd;

        memset(&wnd,0,sizeof(WNDCLASS));

        wnd.style         = CS_OWNDC|CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS|CS_GLOBALCLASS;
        wnd.lpfnWndProc   = (WNDPROC)DllWndProc;
        wnd.hInstance     = hModule;
        wnd.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
        wnd.lpszClassName = "DllWndClass";
        wnd.lpszMenuName  = NULL;
        wnd.hCursor       = LoadCursor(NULL,IDC_ARROW);
        wnd.hIcon         = NULL;

        BOOL res  = RegisterClass(&wnd);
        hInstance = hModule;

        break;
    }
   
    return 1;
}

LRESULT CALLBACK DllWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
    switch (msg)
    {
        case WM_DESTROY:
            PostQuitMessage (0);
            break;
       
        default:
            return DefWindowProc(hwnd,msg,wParam,lParam);
    }
   
    return 0;
}

extern "C" __declspec(dllexport) BOOL ShowWnd()
{
    hwnd = CreateWindowEx(WS_EX_TOPMOST,"DllWndClass","Dll Window",WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_CAPTION|WS_SYSMENU,225,175,350,250,NULL,NULL,hInstance,NULL);
    ShowWindow(hwnd,SW_SHOW);

    MSG msg;
   
    while (GetMessage(&msg,hwnd,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 1;
}


lib то создает, но подключиться к нему нельзя. Ругается виндовской ошибкой:
"Приложение или боблиотека "трам-пам-пам" не являются образом программы для Window NT. Проверьте наличие установочного диска"

Кто-нибудь знает, где похожий вопрос уже рассматривался? Либо статья какая есть, тема форума?
Или, быть может, кто подскажет, что надо сделать с этим кодом, что бы все стало хорошо)
341
24 августа 2008 года
Der Meister
874 / / 21.12.2007
Так код создания окна лежит в динамически подключаемой библиотеке, или в статически? Если в dll, то причём тут ShowWnd = (MY_FUNC) GetProcAddress(GetModuleHandleA("myLib.lib"), "ShowWnd")? Статические C++ библиотеки используются совсем по-другому, для связывания во время выполнения они не подходят. А если подключать нужно во время компоновки (т. е. явно), то проще и придумать нельзя: говорим компоновщику, что надо, мол, либу подключить (#pragma comment(lib, "<libname.lib>") для MSVC++, например) и всё. Такое связывание работает одинаково прикольно для обоих видов библиотек.
Кроме того, прототип экспортируемых из dll функций должен должен быть одинаковым и при реализации, и при исполльзовании. То есть, если у тебя в реализации ShowWnd() объявлена как extern "C" BOOL ShowWnd(), то почему при использовании она объявлена как BOOL CALLBACK ShowWnd()?
Делай, короче, проще: прототипы всех экспортируемых функций выноси в отдельный шашпошный (.h) файл, там же объяви макрос
 
Код:
// mylib.h
#ifdef _MYLIB_EXPORTS
#define MYLIB extern "C" __declspec(dllexport)
#else
#define MYLIB extern "C" __declspec(dllimport)
#endif

MYLIB BOOL ShowWnd();

В файле реализации (.cpp) библиотеки перед включением шапки определяем лексему, участвующую в условии при определении макроса.
 
Код:
// mylib.cpp
#define _MYLIB_EXPORTS
#include "mylib.h"

MYLIB BOOL ShowWnd()
{
    // далее по смыслу
}

Всё. Результат компиляции - два файла: mylib.dll и mylib.lib (конкретно в случае компиляции dll, .lib-файл никакого кода не содержит и нужен только для связывания, за подробностями - в поиск).
Дальше, в основной программе подключаем все наши дела
 
Код:
// main.cpp
#include "mylib.h"
#pragma comment(lib, "mylib.lib") // вот он зачем

int WINAPI _tWinMain()
{
    // туда-сюда
    if(!ShowWindow())
        // ;
}
Все. Получили приложение с явным связыванием. Для связывания во время выполнения, делаем по-другому:
Код:
// main.cpp

// Уже не нужно
// #include "mylib.h"
// #pragma comment(lib, "mylib.lib")

typedef BOOL (*ShowWndProc)();

int WINAPI _tWinMain
{
    LoadLibrary(TEXT("mylib.dll"))
    ShowWndProc showWnd = (ShowWndProc) GetProcAddress(GetModuleHandle(TEXT("mylib.dll")), TEXT("ShowWnd"))
    if (!showWnd())
        // ;
}
12K
24 августа 2008 года
Sholah_Weras
99 / / 04.12.2007
Здорово!
Спасибо огромное, выручили ;)
12K
26 августа 2008 года
Sholah_Weras
99 / / 04.12.2007
Есть мнение, что можно сделать тоже самое, но проще и без использования DllMain. Как - я не знаю. Подскажите?
2.1K
26 августа 2008 года
wAngel
129 / / 23.11.2004
Есть мнение, что можно думать не головой, а гораздо проще. Как - я не знаю...
Вы сами себя пробовали прочитать?
Вы что хотите? подключать библиотеку без точки входа? гораздо проще можно просто не использовать dll.
12K
26 августа 2008 года
Sholah_Weras
99 / / 04.12.2007
Передло мной поставили задачу - создать окно из dll, причем не ипользоваться ф-ию DllMain. В интернете я нашел только реализацию с DllMain, потому и спрашиваю, каким другим образом можно решить эту задачу. (dll использовать надо)
12K
26 августа 2008 года
lifs
163 / / 06.09.2007
Перенести код из DllMain в ShowWnd не подходит?
341
27 августа 2008 года
Der Meister
874 / / 21.12.2007
[QUOTE=Sholah_Weras]Передо мной поставили задачу - создать окно из dll, причем не ипользовать ф-ию DllMain.[/QUOTE]Да тебе просто сказали, чтобы окно создавалось извне. Оно у тебя уже так и есть.
[QUOTE=lifs]Перенести код из DllMain в ShowWnd не подходит?[/QUOTE]По-моему, код регистрации класса окна всё же лучше оставить в DllMain().
12K
27 августа 2008 года
lifs
163 / / 06.09.2007
Цитата: Der Meister
По-моему, код регистрации класса окна всё же лучше оставить в DllMain().


Я согласен, но если для кого-то дело принципа отсутствие DllMain, то почему бы не пойти людям навстречу? Правда это немного усложнит - нужно чтобы класс регистрировался единожды, но если хотят...

341
27 августа 2008 года
Der Meister
874 / / 21.12.2007
[QUOTE=lifs]Я согласен, но если для кого-то дело принципа отсутствие DllMain, то почему бы не пойти людям навстречу?[/QUOTE]Без точки входа не скомпилирует. А если и скомпилирует, то не подгрузит.[QUOTE=lifs]Правда это немного усложнит - нужно чтобы класс регистрировался единожды, но если хотят...[/QUOTE]Да без разницы, функция регистрации просто вернёт FALSE при повторном вызове. Иное дело, что такое значение может быть возвращено по совершенно иным причинам. Я сомневаюсь, что озадачивающий может быть настолько неадекватным, чтобы не понять логичность такого шага...[QUOTE=Sholah_Weras]Есть мнение, что можно сделать тоже самое, но проще и без использования DllMain.[/QUOTE]Кто этот мудрец? Кажется, его кунг-фу сильнее моего... Хочу стать его учеником!
12K
27 августа 2008 года
Sholah_Weras
99 / / 04.12.2007
2 Der Meister
Как узнаю прием кунгфустический - обязательно поделюсь.
12K
27 августа 2008 года
lifs
163 / / 06.09.2007
Цитата: Der Meister
Без точки входа не скомпилирует. А если и скомпилирует, то не подгрузит.


И скомпилирует, и подгрузит, наличие точки входа не обязательно в dll. К примеру, dll, используемые только для ресурсов, точки входа зачастую не имеют.

14
27 августа 2008 года
Phodopus
3.3K / / 19.06.2008
А мне сдается что скорей всего речь просто идет о
[QUOTE=Richter, Jeffrey]В документации Platform SDK утверждается, что DllMain должна выполнять лишь простые виды инициализации — настройку локальной памяти потока (см. главу 21), создание объектов ядра, открытие файлов и т. д. Избегайте обращений к функциям, связанным с User, Shell, ODBC, COM, RPC и сокетами (а также к функциям, которые их вызывают), потому что соответствующие DLL могут быть еще не инициализированы. Кроме того, подобные функции могут вызывать LoadLibrary(Ex) и тем самым приводить к взаимной блокировке.[/QUOTE]
взято отсюда
6.4K
28 августа 2008 года
Host
122 / / 22.09.2005
Цитата: Der Meister
Кто этот мудрец? Кажется, его кунг-фу сильнее моего... Хочу стать его учеником!




Шаг 1:
- Создаеш новый Win32 проект (dll, Empty Project).
- Добавляеш в него новый класс (например [SIZE=2]MyWindow[/SIZE]).
файл [SIZE=2]MyWindow.h:[/SIZE]
[SIZE=2]

Код:
[SIZE=2][COLOR=#0000ff]#pragma[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]once[/COLOR][/SIZE]
[SIZE=2][COLOR=#0000ff]#define[/COLOR][/SIZE][SIZE=2] EXPORT [/SIZE][SIZE=2][COLOR=#0000ff]__declspec[/COLOR][/SIZE][SIZE=2]([/SIZE][SIZE=2][COLOR=#0000ff]dllexport[/COLOR][/SIZE][SIZE=2])[/SIZE]
[SIZE=2][COLOR=#0000ff]class[/COLOR][/SIZE][SIZE=2] EXPORT MyWindow[/SIZE]
[SIZE=2]{[/SIZE]
[SIZE=2][COLOR=#0000ff]private[/COLOR][/SIZE][SIZE=2] :[/SIZE]
[SIZE=2]HWND hWnd;[/SIZE]
[SIZE=2]HINSTANCE hInstance; [/SIZE]
[SIZE=2][COLOR=#0000ff]void[/COLOR][/SIZE][SIZE=2] Proceed([/SIZE][SIZE=2][COLOR=#0000ff]void[/COLOR][/SIZE][SIZE=2]);[/SIZE]
[SIZE=2][COLOR=#0000ff]public[/COLOR][/SIZE][SIZE=2]:[/SIZE]
[SIZE=2]MyWindow([/SIZE][SIZE=2][COLOR=#0000ff]const[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]wchar_t[/COLOR][/SIZE][SIZE=2]* szClassName);[/SIZE]
[SIZE=2]~MyWindow([/SIZE][SIZE=2][COLOR=#0000ff]void[/COLOR][/SIZE][SIZE=2]);[/SIZE]
[SIZE=2][COLOR=#0000ff]static[/COLOR][/SIZE][SIZE=2] LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);[/SIZE]
[SIZE=2]};[/SIZE]

файл MyWindow.cpp:
Код:
[SIZE=2][COLOR=#0000ff]#include[/COLOR][/SIZE][SIZE=2][COLOR=#a31515]<windows.h>[/COLOR][/SIZE]
[SIZE=2][COLOR=#0000ff]#include[/COLOR][/SIZE][SIZE=2][COLOR=#a31515]"MyWindow.h"[/COLOR][/SIZE]
[SIZE=2]MyWindow::MyWindow([/SIZE][SIZE=2][COLOR=#0000ff]const[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]wchar_t[/COLOR][/SIZE][SIZE=2]* szClassName)[/SIZE]
[SIZE=2]{[/SIZE]
[SIZE=2]WNDCLASSEX wcex;[/SIZE]
[SIZE=2]hInstance = GetModuleHandle(L[/SIZE][SIZE=2][COLOR=#a31515]"testdll.dll"[/COLOR][/SIZE][SIZE=2]);[/SIZE]
[SIZE=2]wcex.cbSize = [/SIZE][SIZE=2][COLOR=#0000ff]sizeof[/COLOR][/SIZE][SIZE=2](WNDCLASSEX);[/SIZE]
[SIZE=2]wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;[/SIZE]
[SIZE=2]wcex.lpfnWndProc = WndProc;[/SIZE]
[SIZE=2]wcex.cbClsExtra = 0;[/SIZE]
[SIZE=2]wcex.cbWndExtra = 0;[/SIZE]
[SIZE=2]wcex.hInstance = hInstance;[/SIZE]
[SIZE=2]wcex.hIcon = LoadIcon(NULL, IDI_INFORMATION);[/SIZE]
[SIZE=2]wcex.hCursor = LoadCursor(NULL, IDC_ARROW);[/SIZE]
[SIZE=2]wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);[/SIZE]
[SIZE=2]wcex.lpszMenuName = NULL; [/SIZE]
[SIZE=2]wcex.lpszClassName = szClassName;[/SIZE]
[SIZE=2]wcex.hIconSm = LoadIcon(NULL, IDI_INFORMATION);[/SIZE]
[SIZE=2]RegisterClassEx(&wcex);[/SIZE]
[SIZE=2]hWnd = CreateWindow(szClassName, L[/SIZE][SIZE=2][COLOR=#a31515]"Test Window"[/COLOR][/SIZE][SIZE=2], WS_OVERLAPPEDWINDOW,[/SIZE]
[SIZE=2]CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);[/SIZE]
[SIZE=2]ShowWindow(hWnd, SW_NORMAL);[/SIZE]
[SIZE=2]UpdateWindow(hWnd);[/SIZE]
[SIZE=2]Proceed();[/SIZE]
[SIZE=2]}[/SIZE]
[SIZE=2]MyWindow::~MyWindow([/SIZE][SIZE=2][COLOR=#0000ff]void[/COLOR][/SIZE][SIZE=2])[/SIZE]
[SIZE=2]{[/SIZE]
[SIZE=2]}[/SIZE]
[SIZE=2][COLOR=#0000ff]void[/COLOR][/SIZE][SIZE=2] MyWindow::Proceed()[/SIZE]
[SIZE=2]{[/SIZE]
[SIZE=2]MSG msg;[/SIZE]
[SIZE=2][COLOR=#0000ff]while[/COLOR][/SIZE][SIZE=2] (GetMessage(&msg, NULL, 0, 0))[/SIZE]
[SIZE=2]{ [/SIZE]
[SIZE=2]TranslateMessage(&msg);[/SIZE]
[SIZE=2]DispatchMessage(&msg); [/SIZE]
[SIZE=2]}[/SIZE]
[SIZE=2]}[/SIZE]
[SIZE=2]LRESULT CALLBACK MyWindow::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)[/SIZE]
[SIZE=2]{[/SIZE]
[SIZE=2][COLOR=#0000ff]int[/COLOR][/SIZE][SIZE=2] wmId, wmEvent;[/SIZE]
[SIZE=2]PAINTSTRUCT ps;[/SIZE]
[SIZE=2]HDC hdc;[/SIZE]
[SIZE=2][COLOR=#0000ff]switch[/COLOR][/SIZE][SIZE=2] (message)[/SIZE]
[SIZE=2]{[/SIZE]
[SIZE=2][COLOR=#0000ff]case[/COLOR][/SIZE][SIZE=2] WM_LBUTTONDBLCLK:[/SIZE]
[SIZE=2]MessageBox(hWnd, L[/SIZE][SIZE=2][COLOR=#a31515]"Test Window from dll."[/COLOR][/SIZE][SIZE=2], L[/SIZE][SIZE=2][COLOR=#a31515]"MyWindow"[/COLOR][/SIZE][SIZE=2], NULL);[/SIZE]
[SIZE=2][COLOR=#0000ff]break[/COLOR][/SIZE][SIZE=2];[/SIZE]
[SIZE=2][COLOR=#0000ff]case[/COLOR][/SIZE][SIZE=2] WM_PAINT:[/SIZE]
[SIZE=2]hdc = BeginPaint(hWnd, &ps);[/SIZE]
[SIZE=2]EndPaint(hWnd, &ps);[/SIZE]
[SIZE=2][COLOR=#0000ff]break[/COLOR][/SIZE][SIZE=2];[/SIZE]
[SIZE=2][COLOR=#0000ff]case[/COLOR][/SIZE][SIZE=2] WM_DESTROY:[/SIZE]
[SIZE=2]PostQuitMessage(0);[/SIZE]
[SIZE=2][COLOR=#0000ff]break[/COLOR][/SIZE][SIZE=2];[/SIZE]
[SIZE=2][COLOR=#0000ff]default[/COLOR][/SIZE][SIZE=2]:[/SIZE]
[SIZE=2][COLOR=#0000ff]return[/COLOR][/SIZE][SIZE=2] DefWindowProc(hWnd, message, wParam, lParam);[/SIZE]
[SIZE=2]}[/SIZE]
[SIZE=2][COLOR=#0000ff]return[/COLOR][/SIZE][SIZE=2] 0;[/SIZE]
[SIZE=2]}[/SIZE]


- Компилиш dll (например testdll.dll)

Шаг 2:
- Создаеш проект (Windows Application, Empty project)
- Добавляеш файл (*.cpp):
Код:
[SIZE=2][COLOR=#0000ff]#include[/COLOR][/SIZE][SIZE=2][COLOR=#a31515]<windows.h>[/COLOR][/SIZE]
[SIZE=2][COLOR=#0000ff]#include[/COLOR][/SIZE][SIZE=2][COLOR=#a31515]"../testdll/MyWindow.h"[/COLOR][/SIZE]
[SIZE=2][COLOR=#0000ff]#pragma[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]comment[/COLOR][/SIZE][SIZE=2] ([/SIZE][SIZE=2][COLOR=#0000ff]lib[/COLOR][/SIZE][SIZE=2], [/SIZE][SIZE=2][COLOR=#a31515]"testdll.lib"[/COLOR][/SIZE][SIZE=2])[/SIZE]
 
 
[SIZE=2][COLOR=#0000ff]int[/COLOR][/SIZE][SIZE=2] APIENTRY WinMain(HINSTANCE hInstance,[/SIZE]
[SIZE=2]HINSTANCE hPrevInstance,[/SIZE]
[SIZE=2]LPSTR lpCmdLine,[/SIZE]
[SIZE=2][COLOR=#0000ff]int[/COLOR][/SIZE][SIZE=2] nCmdShow)[/SIZE]
[SIZE=2]{[/SIZE]
[SIZE=2]MyWindow * wnd = [/SIZE][SIZE=2][COLOR=#0000ff]new[/COLOR][/SIZE][SIZE=2] MyWindow(L[/SIZE][SIZE=2][COLOR=#a31515]"TestMyWindowCLS"[/COLOR][/SIZE][SIZE=2]);[/SIZE]
[SIZE=2][COLOR=#0000ff]return[/COLOR][/SIZE][SIZE=2] 0;[/SIZE]
[SIZE=2]}[/SIZE]

зы: путь к [COLOR=#a31515]MyWindow.h [COLOR=black]и[/COLOR] testdll.lib [/COLOR][COLOR=black]ставиш свои[/COLOR]
- компилиш.

Шаг 3:
- Постигаеш Кунг-Фу.
[/SIZE]
341
28 августа 2008 года
Der Meister
874 / / 21.12.2007
Так это такое же кунг-фу, как у меня и автора, только для прыжков в высоту верёвки к ушам привязаны. Только вот с другого конца они по земле волочатся и прока от них нет, только кода поприбавилось.
Можно гораздо проще: взять в руки проект MFC extension dll, добавить в ресурсы диалог, щёлкнуть на нём правой кнопкой, выбрать Add сlass и не париться с шаолинем. Но это не то пальто...
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог