一,
HINSTANCE g_hinstDll = NULL;
HHOOK g_hhook = NULL;
HWND g_hwndPost = NULL;
UINT g_uMsgNotify = WM_USER;
HOOKPROC KeyboardHook_HookProc ( int nCode, WPARAM wParam, LPARAM lParam)
{
LRESULT lResult = CallNextHookEx(g_hhook, nCode, wParam, lParam);
if (nCode == HC_ACTION)
{
PostMessage(g_hwndPost, g_uMsgNotify, wParam, lParam);
}
return((HOOKPROC)lResult);
}
///////////
BOOL WINAPI SetKeyboardHook (HWND hWndPost, UINT Msg)
{
HHOOK hhook;
if (g_hhook != NULL) return(FALSE);
g_hwndPost = hWndPost;
g_uMsgNotify = Msg;
Sleep(0);
if (g_hLogHook==NULL)
hhook = SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)KeyboardHook_HookProc,g_hinstDll, 0);
InterlockedExchange((PLONG) &g_hhook, (LONG) hhook);
return(g_hhook != NULL);
}
///
BOOL WINAPI ReleaseKeyboardHook()
{
BOOL fOK = TRUE;
if (g_hhook != NULL)
{
fOK = UnhookWindowsHookEx(g_hhook);
g_hhook = NULL;
}
return(fOK);
}
BOOL WINAPI DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
g_hinstDll = hinstDll;
break;
}
return(TRUE);
}
二,
在Borland的Community上找到了這篇文章,可以解決這個問題了。如下:
http://community.borland.com/article/0,1410,20008,00.html
///
C++Builder 4.0 is the first C++Builder compiler that supports shared memory segments. This document explains how to use this feature in windows DLL.
To change the data segment and the class name, you need to add #pragma option -zR[SEGMENT NAME] and #pragma option -zT[CLASS NAME] to the file you want the data shared from. Below is the source file I am going to export the integer named 'data':
File: SharedData.cpp
//---------------------------------------------------------------------------
// Borland C++Builder
// Copyright (c) 1987, 1999 Inprise Corporation. All Rights Reserved.
//---------------------------------------------------------------------------
#pragma option -zRSHSEG // change default data segment name
#pragma option -zTSHCLASS // change default data class name
// Here is the initialized data that will be shared.
int data = 0;
Notice that the segment name for this file is: SHSEGSHCLASS. A .def file is required for the linker to create the shared segement. Below is what the .def file looks like:
File: Shared.def
LIBRARY SHAREDDLL
SEGMENTS
SHSEG CLASS 'SHCLASS' SHARED
三
當你的DLL程序被其它各個程序調用時,每調用一次,將產生一個DLL的實例,其實代碼在內存中僅有一套,但DLL中的變量即數據段將 產生多個,這若干個數據段是互不干擾、是不能共享的,但在一些特殊情況下,就不能滿足我們的要求了,比如,用戶的全局鉤子程序就 是一個.DLL,這個.DLL會被內存所有的進程調用, 如果它的數據段不能共享,就變成了多個局部鉤子了,好在API已替你想好了一個間接 辦法,你可用一個“共享名”申請一塊共享內存塊,進行讀寫:
HANDLE GetShare(char * &ShareP,int size,char *ShareName)
{ ShareP申請的內存塊地址,size字節數,ShareName共享名
HANDLE fh=CreateFileMapping((HANDLE)-1,0,
PAGE_READWRITE,0,
Size,
ShareName);
ShareP=(char *)MapViewOfFile(fh,
FILE_MAP_ALL_ACCESS,
0,0,0);
if (GetLastError()!=ERROR_ALREADY_EXISTS)
ZeroMemory(ShareP,size); // 共享區初始化
return(fh);
}
char * ShareP=NULL;
void test() // 申請一塊128個字節的字符數組
{
HANDLE fh=GetShare(ShareP,128,"ShareForMyProg");
for (int i=0;i<128;i++)
ShareP[i]=i;
CloseHandle(fh);
}
如果你的多個程序之間或同一個程序多次同時運行,也可借助這個辦法進
變量通訊;
在VC++中,若要為DLL定義一個共享內存段更簡單,這是一種直接定義的
辦法:
#pragma data_seg("Shared")
int x,y;
char s[128];
#pragma data_seg
#pragma comment(linker,"/section:Shared,rws")
真簡單,可惜在C++BUILDER5.0中經試驗好象不能接受這種方法;
對於BCB,能不能實現DLL中直接定義共享內存塊內,請看下列一段文字:
http://community.borland.com/article/0,1410,20008,00.html
///
C++Builder 4.0 is the first C++Builder compiler that supports shared memory segments.
This document explains how to use this feature in windows DLL.
To change the data segment and the class name, you need to add
#pragma option -zR[SEGMENT NAME] and
#pragma option -zT[CLASS NAME] to the file you want the data shared from.
Below is the source file I am going to export the integer named 'data':
File: SharedData.cpp
//---------------------------------------------------------------------------
// Borland C++Builder
// Copyright (c) 1987, 1999 Inprise Corporation. All Rights Reserved.
//---------------------------------------------------------------------------
#pragma option -zRSHSEG // change default data segment name
#pragma option -zTSHCLASS // change default data class name
// Here is the initialized data that will be shared.
int data = 0;
Notice that the segment name for this file is: SHSEGSHCLASS. A .def file
is required for the linker to create the shared segement. Below is what the
.def file looks like:
File: Shared.def
LIBRARY SHAREDDLL
SEGMENTS
SHSEG CLASS 'SHCLASS' SHARED
可見C++BUILDER4.0與DELPHI已能提供直接實現DLL內存段共享問題,請高手邦忙一起
試一試:在BCB或DELPHI具體應怎樣做?
四
// 下面的程序將產生有三個導出函數的MouseHook.DLL
#include <windows.h>
#pragma argsused
typedef // 為共享區定義結構
struct
{
POINT MouseLoc; // 存放鼠標位置
HHOOK NewHook; // 存放新鉤子句柄
int LoadCount; // DLL裝入次數計數
} TShareMem;
TShareMem *ShareMem=NULL;
HINSTANCE DllHinst;
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
DllHinst=hinst;
static HANDLE fh; // DLL共享區句柄
if (reason==DLL_PROCESS_ATTACH) // DLL入口
{ // 為共享區申請共享單元
fh=CreateFileMapping((HANDLE)-1,0,
PAGE_READWRITE,0,
sizeof(TShareMem),
"ShareForMouseHook");
ShareMem=(TShareMem *)MapViewOfFile(fh,
FILE_MAP_ALL_ACCESS,
0,0,0);
if (GetLastError()!=ERROR_ALREADY_EXISTS)
ZeroMemory(ShareMem,sizeof(TShareMem));
// 共享區初始化
ShareMem->LoadCount+=1; // 裝入計數
}
if (reason==DLL_PROCESS_DETACH) // DLL出口處理
{
ShareMem->LoadCount-=1;
CloseHandle(fh);
}
return 1;
}
extern "C" __declspec(dllexport)
void GetMouse(int &mx,int &my,int &loadcount) // DLL導出函數GetMouse()
{
if (ShareMem!=NULL)
{
mx=ShareMem->MouseLoc.x;
my=ShareMem->MouseLoc.y;
loadcount=ShareMem->LoadCount;
}
}
LRESULT CALLBACK MouseHook(int nCode,
WPARAM wParam,LPARAM lParam)
{
if (nCode==HC_ACTION)
{
MOUSEHOOKSTRUCT *l=(MOUSEHOOKSTRUCT *)lParam;
ShareMem->MouseLoc=l->pt; //送鼠標位置
}
return(CallNextHookEx(ShareMem->NewHook,nCode,wParam,lParam));
}
extern "C" __declspec(dllexport)
void EnableHook() // 導出函數EnableHook()
{
if (ShareMem!=NULL)
if (ShareMem->NewHook==NULL) // 安裝新鉤子
ShareMem->NewHook=SetWindowsHookEx(WH_MOUSE,
(HOOKPROC)MouseHook,
DllHinst,0);
}
extern "C" __declspec(dllexport)
void DisableHook() // 導出函數DisableHook()
{
if (ShareMem!=NULL)
if (ShareMem->NewHook!=NULL)
{
UnhookWindowsHookEx(ShareMem->NewHook);
ShareMem->NewHook=NULL; // 卸掉新鉤子
}
}
//=======================================================================
#include <vcl.h>
#pragma hdrstop
#include "CallUnit1.h"
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
extern "C" __declspec(dllimport)
void EnableHook(); // DLL導入函數1
extern "C" __declspec(dllimport)
void DisableHook(); // DLL導入函數2
extern "C" __declspec(dllimport)
void GetMouse(int &mx,int &my,int &loadcount); // DLL導入函數3
void __fastcall TForm1::Button1Click(TObject *Sender)
{
EnableHook();
int x,y,loadcount;
while (!Application->Terminated)
{ // 不停在從DLL中取回鼠標位置
GetMouse(x,y,loadcount);
Edit1->Text=String(x)+","+String(y)+":"+String(loadcount);
Application->ProcessMessages();
}
}
void __fastcall TForm1::Button2Click(TObject *Sender)
{
DisableHook();
}
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
DisableHook();
}
//---------------------------------------------------------------------------
五
步驟如下:
在DLL中的工程中,假設為MouseHook.bpr(產生MouseHook.DLL)
1.在Unit1.cpp的最前面(#include <windows.h>之前)加上
#pragma option -zRSHSEG // 改變缺省數據段名
#pragma option -zTSHCLASS // 改變缺省數據類名
2.新建一工程同名的純文本文件MouseHook.def,其內容只要
一行:
SEGMENTS SHSEG CLASS 'SHCLASS' SHARED
並將此文件用Project->Add Project增加到工程中;
3.在你的程序代碼的前面定義的全局變量都將是DLL共享的,
在Unit1.cpp中,例如:
// 下面的程序將產生有三個導出函數的MouseHook.DLL
// 純文本文件 MouseHook.def的內容如下:
// SEGMENTS SHSEG CLASS 'SHCLASS' SHARED
#pragma option -zRSHSEG // 改變缺省數據段名
#pragma option -zTSHCLASS // 改變缺省數據類名
#include <windows.h>
#pragma argsused
// 以下都將是共享區內存變量
POINT MouseLoc={0,0}; // 存放鼠標位置
HHOOK NewHook=NULL; // 存放新鉤子句柄
int LoadCount=0; // DLL裝入次數計數
HINSTANCE DllHinst;
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
DllHinst=hinst;
if (reason==DLL_PROCESS_ATTACH) // DLL入口
LoadCount+=1; // 裝入計數
else
if (reason==DLL_PROCESS_DETACH) // DLL出口處理
LoadCount-=1;
return 1;
}
extern "C" __declspec(dllexport)
void GetMouse(int &mx,int &my,int &js) // DLL導出函數GetMouse()
{
mx=MouseLoc.x; // 送出鼠標位置
my=MouseLoc.y;
js=LoadCount; // 送出DLL裝入次數
}
LRESULT CALLBACK MouseHook(int nCode,
WPARAM wParam,LPARAM lParam)
{
if (nCode==HC_ACTION)
{
MOUSEHOOKSTRUCT *l=(MOUSEHOOKSTRUCT *)lParam;
MouseLoc=l->pt; //送鼠標位置
}
return(CallNextHookEx(NewHook,nCode,wParam,lParam));
}
extern "C" __declspec(dllexport)
void EnableHook() // 導出函數EnableHook()
{
if (NewHook==NULL) // 安裝新鉤子
NewHook=SetWindowsHookEx(WH_MOUSE,
(HOOKPROC)MouseHook,
DllHinst,0);
}
extern "C" __declspec(dllexport)
void DisableHook() // 導出函數DisableHook()
{
if (NewHook!=NULL)
{
UnhookWindowsHookEx(NewHook);
NewHook=NULL; // 卸掉新鉤子
}
}
//==========================================================
// CallHook.EXE,將調用全局鼠標全局鉤子MouseHook.DLL
// 靜態裝入MouseHook.DLL,工程中須用 MouseGook.Lib
#include <vcl.h>
#pragma hdrstop
#include "CallUnit1.h"
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
extern "C" __declspec(dllimport)
void EnableHook(); // DLL導入函數1
extern "C" __declspec(dllimport)
void DisableHook(); // DLL導入函數2
extern "C" __declspec(dllimport)
void GetMouse(int &mx,int &my,int &loadcount); // DLL導入函數3
void __fastcall TForm1::Button1Click(TObject *Sender)
{
EnableHook();
int x,y,loadcount;
while (!Application->Terminated)
{ // 不停在從DLL中取回鼠標位置
GetMouse(x,y,loadcount);
Edit1->Text=String(x)+","+String(y);
Edit2->Text=loadcount; // 顯示DLL裝入次數
Application->ProcessMessages();
}
}
void __fastcall TForm1::Button2Click(TObject *Sender)
{
DisableHook();
}
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
DisableHook();
}
// ok,已經深夜1點了,別忘了給俺加點分!!!!!!!!!!!!!!!!
六
VC的程序
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
HINSTANCE g_hinstDll = NULL;
#pragma data_seg(".drectve")
static char szLinkDirectiveShared[] = "-section:Shared,rws";
#pragma data_seg()
#pragma data_seg("Shared")
HHOOK g_hhook = NULL;
HWND g_hwndPost = NULL;
UINT g_uMsgNotify = WM_USER;
#pragma data_seg()
static LRESULT WINAPI KeyboardHook_HookProc (
int nCode,
WPARAM wParam,
LPARAM lParam)
{
LRESULT lResult = CallNextHookEx(g_hhook, nCode, wParam, lParam);
if (nCode == HC_ACTION)
{
PostMessage(g_hwndPost, g_uMsgNotify, wParam, lParam);
}
return(lResult);
}
BOOL WINAPI SetKeyboardHook (HWND hWndPost, UINT Msg)
{
HHOOK hhook;
if (g_hhook != NULL) return(FALSE);
g_hwndPost = hWndPost;
g_uMsgNotify = Msg;
Sleep(0);
hhook = SetWindowsHookEx(WH_KEYBOARD, KeyboardHook_HookProc, g_hinstDll, 0);
InterlockedExchange((PLONG) &g_hhook, (LONG) hhook);
return(g_hhook != NULL);
}
BOOL WINAPI ReleaseKeyboardHook()
{
BOOL fOK = TRUE;
if (g_hhook != NULL)
{
fOK = UnhookWindowsHookEx(g_hhook);
g_hhook = NULL;
}
return(fOK);
}
BOOL WINAPI DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
g_hinstDll = hinstDll;
break;
}
return(TRUE);
}