Callback dll return value
У меня есть библиотека (на C++) с обратным вызовом, отслеживающая состояние хранителя экрана.
В дальнейшем данная библиотека будет работать с кодом c#.
Сейчас при активации хранителя в файл записывается тестовый текст.
Хочется получать ответ из dll в exe в виде булево значения. Я пересмотрел кучу примеров и на msdn-е, и на codeproject.com, и еще на многих сайтах, однако мне это не помогло. Все время упираюсь в логику конструкции самой dll-ки.
Что имеем на данный момент:
.dll
#include <conio.h>
#include <stdio.h>
#include <time.h>
#pragma argsused
//---------------------------------------------------------------------------
bool bSCRSAVEACTIVE; // Установлен ли ScreenSaver
//---------------------------------------------------------------------------
extern "C" __declspec(dllexport) LRESULT CALLBACK ScreenSaverHook(UINT,WPARAM,LPARAM);
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
if(reason==DLL_PROCESS_ATTACH) // Проецируем на адр. простр.
{
if(!SystemParametersInfo(SPI_GETSCREENSAVEACTIVE,0, &bSCRSAVEACTIVE,0))
MessageBox(0,"Не могу получить данные об установленном"
"хранителе экрана",
"Внимание!",MB_ICONERROR);
}
return 1;
}
void fileW()
{
int bal;
FILE *file;
if ((file = fopen("3.txt","a")) != NULL)
{
fputs("Test DLL", file );
}
fclose(file);
getch();
}
//---------------------------------------------------------------------------
LRESULT CALLBACK ScreenSaverHook(UINT nCode , WPARAM wParam, LPARAM lParam)
{
MSG *msg = (MSG *)lParam;
if ( msg->message == WM_SYSCOMMAND && msg->wParam == SC_SCREENSAVE)
{
fileW();
}
return CallNextHookEx(ScreenSaverHook, nCode, wParam, lParam);
}
#pragma hdrstop
#define MYWM_NOTIFY (WM_APP+100)
#define IDC_MYICON 1006
HINSTANCE hinst; // Описатель экземпляра приложения
NOTIFYICONDATA NotIconD; // Для значка в Tray
HWND MainWnd; // Окно
HINSTANCE hLib; // Библиотека с ловушками
HHOOK hScreenSaverHook;
LRESULT CALLBACK (__stdcall *pScreenSaverHook)(int,WPARAM,LPARAM);
//---------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int);
InitApplication(HINSTANCE,int);
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
void vfSetTrayIcon(HINSTANCE);
void vfResetTrayIcon();
#pragma argsused
WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
//----------------
hLib=LoadLibrary("../DLL/dll.dll");
if(hLib)
{
(void*)pScreenSaverHook=GetProcAddress(hLib,"ScreenSaverHook");
hScreenSaverHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)(pScreenSaverHook), hLib,0);
//----------------
if (InitApplication(hInstance,nCmdShow))
{
vfSetTrayIcon(hInstance); // Создаём окна
while (GetMessage(&msg,(HWND)(NULL),0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
//----------------
UnhookWindowsHookEx(hScreenSaverHook); // Завершаем
FreeLibrary(hLib);
vfResetTrayIcon();
return 0;
}
}
return 1;
}
//---------------------------------------------------------------------------
BOOL InitApplication(HINSTANCE hinstance,int nCmdShow)
{ // Создание главного окна
WNDCLASS wcx; // Класс окна
wcx.style=NULL;
wcx.lpfnWndProc=MainWndProc;
wcx.cbClsExtra=0;
wcx.cbWndExtra=0;
wcx.hInstance=hinstance;
wcx.hIcon=LoadIcon(hinstance,"MAINICON");
wcx.hCursor=LoadCursor(NULL,IDC_ARROW);
wcx.hbrBackground=(HBRUSH)(COLOR_APPWORKSPACE);
wcx.lpszMenuName=NULL;
wcx.lpszClassName="HookWndClass";
if(RegisterClass(&wcx)) // Создаём окно
{
MainWnd=CreateWindow("HookWndClass","SSHook", WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/,
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,NULL,NULL,hinstance,NULL);
if(!MainWnd)
return FALSE;
return TRUE;
}
return false;
}
//---------------------------------------------------------------------------
LRESULT CALLBACK MainWndProc(HWND hwnd,UINT uMsg,WPARAM wParam, LPARAM lParam)
{ // Оконная процедура
switch (uMsg)
{
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
//------------
case MYWM_NOTIFY:
{
if(lParam==WM_RBUTTONUP) // Правый щелчок на значке - завершаем
PostQuitMessage(0);
break;
}
default:
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
return 0;
}
//---------------------------------------------------------------------------
void vfSetTrayIcon(HINSTANCE hInst)
{ // Значок в Tray
char* pszTip="Хранитель экрана";
NotIconD.cbSize=sizeof(NOTIFYICONDATA);
NotIconD.hWnd=MainWnd;
NotIconD.uID=IDC_MYICON;
NotIconD.uFlags=NIF_MESSAGE|NIF_ICON|NIF_TIP;
NotIconD.uCallbackMessage=MYWM_NOTIFY;
NotIconD.hIcon=LoadIcon(hInst,"MAINICON");
lstrcpyn(NotIconD.szTip,pszTip,sizeof(NotIconD.szTip));
Shell_NotifyIcon(NIM_ADD,&NotIconD);
}
//---------------------------------------------------------------------------
void vfResetTrayIcon()
{ // Удаляем значок
Shell_NotifyIcon(NIM_DELETE,&NotIconD);
}
Я пробовал конструкцию объявления обратного вызова:
HINSTANCE hMod=NULL;
extern "C" __declspec(dllexport) bool InstallHook(DWORD ThreadID){
hHook=SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)ScreenSaverHook,(HINSTANCE) hMod, 0);
return hHook ? true:false;
}
UINT WM_SCRNSVSTART = RegisterWindowMessage("ScreenSaverStarted");
void load_and_call(void)
{
HMODULE hmod = LoadLibrary(...);
InstallHook func = (InstallHook)GetProcAddress(hLib, "InstallHook");
func(ThreadID);
}
Подскажите, как грамотно организовать конструкцию обратного вызова с возвратом значения.
Если есть пример, опишите его здесь.
Тыж сам используешь это.
В dll:
.....
extern "C" __declspec(dllexport) bool InstallHook(/*Это лишнее DWORD ThreadID,*/void (*foo)(bool)){
hHook=SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)ScreenSaverHook,(HINSTANCE) hMod, 0);
callBack=foo;
return hHook ? true:false;
}
...
LRESULT CALLBACK ScreenSaverHook(UINT nCode , WPARAM wParam, LPARAM lParam)
{
MSG *msg = (MSG *)lParam;
if ( msg->message == WM_SYSCOMMAND && msg->wParam == SC_SCREENSAVE)
{
//fileW();
(*callBack)(true);
}
return CallNextHookEx(ScreenSaverHook, nCode, wParam, lParam);
}
...
static void myCallBack(bool hz)
{
if(hz)
die();
else
live();
}
void load_and_call(void)
{
HMODULE hmod = LoadLibrary(...);
InstallHook func = (InstallHook)GetProcAddress(hLib, "InstallHook");
func(/*Это лишнее ThreadID,*/&myCallBack);
}
Project ...test.exe raised too many consecutive exceptions: 'access violation at 0x00000000: read of address 0x00000000'
При пошаговом прохождении заметил, что после установки крючка, он остается пустым.
InstallHook func = HULL. Видимо из-за этого программа вылетает на строке func(&myCallBack);
Мне кажется, что при проецировании адресного пространства в библиотеку не передаются параметры окна
exe
#include <stdio.h>
#include <time.h>
#pragma hdrstop
//////////////////////////////////////////////////////////////////////////
// Глобальные переменные //
//////////////////////////////////////////////////////////////////////////
#define MYWM_NOTIFY (WM_APP+100)
#define IDC_MYICON 1006
HINSTANCE hinst; // Описатель экземпляра приложения
NOTIFYICONDATA NotIconD; // Для значка в Tray
HWND MainWnd; // Окно
HINSTANCE hLib; // Библиотека с ловушками
HHOOK hMouseHook;
HHOOK hScreenSaverHook;
LRESULT CALLBACK (__stdcall *pScreenSaverHook)(int,WPARAM,LPARAM);
LRESULT CALLBACK (__stdcall *pMouseHook)(int,WPARAM,LPARAM);
//---------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int);
InitApplication(HINSTANCE,int); // Прототипы
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
void vfSetTrayIcon(HINSTANCE);
void vfResetTrayIcon();
//////////////////////////////////////////////////////////////////////////
// Функции //
//////////////////////////////////////////////////////////////////////////
#pragma argsused
void fileW()
{
int bal;
FILE *file;
if ((file = fopen("3.txt","a")) != NULL)
{
fputs("Test DLL", file );
}
fclose(file);
}
typedef BOOL (*InstallHook)(void (*)(bool));
static void myCallBack(bool hz)
{
if(hz)
{
fileW();
}
}
WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
//----------------
hLib=LoadLibrary("../DLL/dll.dll");
if(hLib)
{
InstallHook func = (InstallHook)GetProcAddress(hLib, "InstallHook");
func(&myCallBack);
//(void*)pScreenSaverHook=GetProcAddress(hLib,"ScreenSaverHook");
// hScreenSaverHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)(pScreenSaverHook), hLib,0);// Ставим ловушки
(void*)pMouseHook=GetProcAddress(hLib,"MouseHook");
hMouseHook=SetWindowsHookEx(WH_MOUSE,(HOOKPROC)(pMouseHook), hLib,0);
//----------------
if (InitApplication(hInstance,nCmdShow))
{
vfSetTrayIcon(hInstance); // Создаём окна
while (GetMessage(&msg,(HWND)(NULL),0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
//----------------
//UnhookWindowsHookEx(hScreenSaverHook);
UnhookWindowsHookEx(hMouseHook); // Завершаем
FreeLibrary(hLib);
vfResetTrayIcon();
return 0;
}
}
return 1;
}
//---------------------------------------------------------------------------
BOOL InitApplication(HINSTANCE hinstance,int nCmdShow)
{ // Создание главного окна
WNDCLASS wcx; // Класс окна
wcx.style=NULL;
wcx.lpfnWndProc=MainWndProc;
wcx.cbClsExtra=0;
wcx.cbWndExtra=0;
wcx.hInstance=hinstance;
wcx.hIcon=LoadIcon(hinstance,"MAINICON");
wcx.hCursor=LoadCursor(NULL,IDC_ARROW);
wcx.hbrBackground=(HBRUSH)(COLOR_APPWORKSPACE);
wcx.lpszMenuName=NULL;
wcx.lpszClassName="HookWndClass";
if(RegisterClass(&wcx)) // Создаём окно
{
MainWnd=CreateWindow("HookWndClass","SSHook", WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/,
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,NULL,NULL,hinstance,NULL);
if(!MainWnd)
return FALSE;
return TRUE;
}
return false;
}
//---------------------------------------------------------------------------
LRESULT CALLBACK MainWndProc(HWND hwnd,UINT uMsg,WPARAM wParam, LPARAM lParam)
{ // Оконная процедура
switch (uMsg)
{
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
case MYWM_NOTIFY:
{
if(lParam==WM_RBUTTONUP) // Правый щелчок на значке - завершаем
PostQuitMessage(0);
break;
}
default:
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
return 0;
}
//---------------------------------------------------------------------------
void vfSetTrayIcon(HINSTANCE hInst)
{ // Значок в Tray
char* pszTip="Хранитель экрана";
NotIconD.cbSize=sizeof(NOTIFYICONDATA);
NotIconD.hWnd=MainWnd;
NotIconD.uID=IDC_MYICON;
NotIconD.uFlags=NIF_MESSAGE|NIF_ICON|NIF_TIP;
NotIconD.uCallbackMessage=MYWM_NOTIFY;
NotIconD.hIcon=LoadIcon(hInst,"MAINICON");
lstrcpyn(NotIconD.szTip,pszTip,sizeof(NotIconD.szTip));
Shell_NotifyIcon(NIM_ADD,&NotIconD);
}
//---------------------------------------------------------------------------
void vfResetTrayIcon()
{ // Удаляем значок
Shell_NotifyIcon(NIM_DELETE,&NotIconD);
}
dll
#include <conio.h>
#pragma argsused
//---------------------------------------------------------------------------
bool bSCRSAVEACTIVE; // Установлен ли ScreenSaver
MOUSEHOOKSTRUCT* psMouseHook; // Для анализа сообшений от мыши
HHOOK hHook=NULL;
HINSTANCE hMod=NULL;
//---------------------------------------------------------------------------
extern "C" __declspec(dllexport) LRESULT CALLBACK ScreenSaverHook(UINT,WPARAM,LPARAM);
extern "C" __declspec(dllexport) LRESULT CALLBACK MouseHook(UINT,WPARAM,LPARAM);
void (*callBack)(bool)=0;
extern "C" __declspec(dllexport) bool InstallHook(void (*foo)(bool))
{
hHook=SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)ScreenSaverHook,(HINSTANCE) hMod, 0);
callBack=foo;
return hHook ? true:false;
}
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
if(reason==DLL_PROCESS_ATTACH) // Проецируем на адр. простр.
{
if(!SystemParametersInfo(SPI_GETSCREENSAVEACTIVE,0, &bSCRSAVEACTIVE,0))
MessageBox(0,"Не могу получить данные об установленном"
"хранителе экрана",
"Внимание!",MB_ICONERROR);
}
return 1;
}
LRESULT CALLBACK MouseHook(UINT nCode,WPARAM wParam,LPARAM lParam)
{ // Ловушка мыши - включает хранитель когда в углу
if(wParam==WM_MOUSEMOVE || wParam==WM_NCMOUSEMOVE)
{
psMouseHook=(MOUSEHOOKSTRUCT*)(lParam);
if(psMouseHook->pt.x==0 && psMouseHook->pt.y==0)
if(bSCRSAVEACTIVE)
{
PostMessage(psMouseHook->hwnd,WM_SYSCOMMAND,
SC_SCREENSAVE,0);
}
}
return 0;
}
LRESULT CALLBACK ScreenSaverHook(UINT nCode , WPARAM wParam, LPARAM lParam)
{
MSG *msg = (MSG *)lParam;
if ( msg->message == WM_SYSCOMMAND && msg->wParam == SC_SCREENSAVE)
{
(*callBack)(true);
}
return CallNextHookEx(ScreenSaverHook, nCode, wParam, lParam);
}
Это первое.
Второе: если уж так охота позаморачиваться с ДЛЛ, то конструкция может быть такая (уж очень упрощенно):
1. В DllMain делайте создание окна (возьмите туже STATIC, зачем Вам регистрировать еще один класс) и повесьте на него свою оконную функцию (SetWindowLong).
2. Длл подгружена в процесс (ваша, следящая ехе, неважно как, но DllMain сработала), экспортируйте из нее какую-нибудь функцию, принимающую адрес для уведомления (адрес функции, которую надо будет вызвать) и сохраните его к примеру как свойство окна...
3. В функции созданного Вами окна проверяйте нужные данные и вызывайте сохраненный адрес....
Я описывал в самом начале:
а именно со службой написанной на c#.
На сколько мне известно, на c#-пе нельзя установить ловушку на сообщение от системы об активации хранителя экрана. Именно по этому я решил написать dll-ку, которая будет отслеживать данное событие и уведомлять об активации основной код.
Сейчас exe на с++ с целью тестирования и исключения ошибок при импорте в c#.
По поводу предложения, связанного с описанием окна внутри dll (если я все правильно понял):
я где-то читал о том, что если окно создавать прямо в dll, сообщение не будет отправятся если фокус будет на другом окне. Равно как и при инициализации ловушки в коде exe. Если я здесь не прав, то это даже лучше, так-как моя служба не имеет окна и мне не придется его создавать.