如何实现抓取屏幕变化的部分,以实现快速远程控制的目的?(200分)

  • 主题发起人 主题发起人 wanggongqin
  • 开始时间 开始时间
W

wanggongqin

Unregistered / Unconfirmed
GUEST, unregistred user!
像 Radmin 远程控制软件,控制的速度相当快,它的实现原理是什么?
我想远程控制屏幕软件的原理无非是先抓图再发送键盘鼠标消息。
要实现快速抓屏并快速传送到网络另一端,除了压缩图像外,只有抓取屏幕变化部分,
以尽量减少数据量。
 
VNC有源码的, 也有控件可以使用;
 
什么控件啊?
 
VNC的Server端有免费的程序;
VNC的Viewer端有OCX控件, 免费的, 你自己找啊
 
Up....
学习中....
 
讨论几年都没有结果。属于机密技术。
 
有抓取画面的颜色越少,处理越快
 
呵呵,VNC 的代码我还改过,确实不错。
但是速度,还是不如微软的快。
 
呵呵, 微软的是远程终端,不是桌面共享, 实现的方式不一样的, 没有可比性;
因为操作系统是他自己的, 远程终端是以内部显示数据流的方式实现的, 自然快;
而一般远程桌面共享是以显示后的图片数据方式传送的, 没法比
 
VNC 的源码在哪下载?我没找到!
 
把屏幕分成 4 * 4 的16个分区.每次把上一屏的内容保存下来.

分区比较有没有变化. CompareMem .有变化就表示可传,没变化就不传.

数据压缩不要用 zlib 之类的.太慢了.一般都用 RLE ,压缩比小,但速度快.
 
有没有示例代码
 
不知道为什么还在谈16个分区,其实这个太慢了,而且16个线程也是不小的开销.
直接抓屏,CompareMem,有变化的不变,无变化的用0字节填充,然后再随便一个压缩算法就可以把这些0字节压在一起了.

开两个线程.
 
怎样将无变化的用零填充?
 
http://www.vnc.com/
downdload里面随便填一下,然后就可以下载源码啦。
看了一下VNC,里面有一种方法。
是用钩子钩住好几种消息,然后得到区域。
发份VNC的钩子代码.
 
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/

// -=- wm_hooks.cxx
//
// Window Message Hooks Dynamic Link library

#include <tchar.h>

#include <wm_hooks/wm_hooks.h>

UINT WM_HK_PingThread = RegisterWindowMessage(_T(&quot;RFB.WM_Hooks.PingThread&quot;));

UINT WM_HK_WindowChanged = RegisterWindowMessage(_T(&quot;RFB.WM_Hooks.WindowChanged&quot;));
UINT WM_Hooks_WindowChanged() {
return WM_HK_WindowChanged;
}

UINT WM_HK_WindowClientAreaChanged = RegisterWindowMessage(_T(&quot;RFB.WM_Hooks.WindowClientAreaChanged&quot;));
UINT WM_Hooks_WindowClientAreaChanged() {
return WM_HK_WindowClientAreaChanged;
}

UINT WM_HK_WindowBorderChanged = RegisterWindowMessage(_T(&quot;RFB.WM_Hooks.WindowBorderChanged&quot;));
UINT WM_Hooks_WindowBorderChanged() {
return WM_HK_WindowBorderChanged;
}

UINT WM_HK_RectangleChanged = RegisterWindowMessage(_T(&quot;RFB.WM_Hooks.RectangleChanged&quot;));
UINT WM_Hooks_RectangleChanged() {
return WM_HK_RectangleChanged;
}

UINT WM_HK_CursorChanged = RegisterWindowMessage(_T(&quot;RFB.WM_Hooks.CursorChanged&quot;));
UINT WM_Hooks_CursorChanged() {
return WM_HK_CursorChanged;
}

#ifdef _DEBUG
UINT WM_HK_Diagnostic = RegisterWindowMessage(_T(&quot;RFB.WM_Hooks.Diagnostic&quot;));
UINT WM_Hooks_Diagnostic() {
return WM_HK_Diagnostic;
}
#endif

ATOM ATOM_Popup_Selection = GlobalAddAtom(_T(&quot;RFB.WM_Hooks.PopupSelectionAtom&quot;));

//
// -=- DLL entry point
//

HINSTANCE dll_instance = 0;

BOOL WINAPI DllMain(HANDLE instance, ULONG reason, LPVOID reserved) {
switch (reason) {
case DLL_PROCESS_ATTACH:
dll_instance = (HINSTANCE)instance;
return TRUE;
case DLL_PROCESS_DETACH:
return TRUE;
case DLL_THREAD_DETACH:
WM_Hooks_Remove(GetCurrentThreadId());
return TRUE;
default:
return TRUE;
};
}

//
// -=- Display update hooks
//

#pragma data_seg(&quot;.WM_Hooks_Shared&quot;)
DWORD hook_owner = 0;
DWORD hook_target = 0;
HHOOK hook_CallWndProc = 0;
HHOOK hook_CallWndProcRet = 0;
HHOOK hook_GetMessage = 0;
HHOOK hook_DialogMessage = 0;
BOOL enable_cursor_shape = FALSE;
HCURSOR cursor = 0;
#ifdef _DEBUG
UINT diagnostic_min=1;
UINT diagnostic_max=0;
#endif
#pragma data_seg()

#ifdef _DEBUG
DLLEXPORT void WM_Hooks_SetDiagnosticRange(UINT min, UINT max) {
diagnostic_min = min; diagnostic_max=max;
}
#endif

bool NotifyHookOwner(UINT event, WPARAM wParam, LPARAM lParam) {
if (hook_owner) {
return PostThreadMessage(hook_owner, event, wParam, lParam)!=0;
/*
if (last_event)
return PostThreadMessage(hook_owner, last_event, last_wParam, last_lParam);
last_event = event;
last_wParam = wParam;
last_lParam = lParam;
return true;
*/
}
return false;
}

bool NotifyWindow(HWND hwnd, UINT msg) {
return NotifyHookOwner(WM_HK_WindowChanged, msg, (LPARAM)hwnd);
}
bool NotifyWindowBorder(HWND hwnd, UINT msg) {
return NotifyHookOwner(WM_HK_WindowBorderChanged, msg, (LPARAM)hwnd);
}
bool NotifyWindowClientArea(HWND hwnd, UINT msg) {
return NotifyHookOwner(WM_HK_WindowClientAreaChanged, msg, (LPARAM)hwnd);
}
bool NotifyRectangle(RECT* rect) {
WPARAM w = MAKELONG((SHORT)rect->left, (SHORT)rect->top);
LPARAM l = MAKELONG((SHORT)rect->right, (SHORT)rect->bottom);
return NotifyHookOwner(WM_HK_RectangleChanged, w, l);
}
bool NotifyCursor(HCURSOR cursor) {
return NotifyHookOwner(WM_HK_CursorChanged, 0, (LPARAM)cursor);
}

void ProcessWindowMessage(UINT msg, HWND wnd, WPARAM wParam, LPARAM lParam) {
#ifdef _DEBUG
if ((msg >= diagnostic_min) && (msg <= diagnostic_max))
PostThreadMessage(hook_owner, WM_HK_Diagnostic, msg, (LPARAM)wnd);
#endif
if (!IsWindowVisible(wnd)) return;
switch (msg) {

// -=- Border update events
case WM_NCPAINT:
case WM_NCACTIVATE:
NotifyWindowBorder(wnd, msg);
break;

// -=- Client area update events
case BM_SETCHECK:
case BM_SETSTATE:
case EM_SETSEL:
case WM_CHAR:
case WM_ENABLE:
case WM_KEYUP:
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_PALETTECHANGED:
case WM_RBUTTONUP:
case WM_SYSCOLORCHANGE:
case WM_SETTEXT:
case WM_SETFOCUS:
//case WM_TIMER:
NotifyWindowClientArea(wnd, msg);
break;
case WM_HSCROLL:
case WM_VSCROLL:
if (((int) LOWORD(wParam) == SB_THUMBTRACK) || ((int) LOWORD(wParam) == SB_ENDSCROLL))
NotifyWindow(wnd, msg);
break;

case WM_WINDOWPOSCHANGING:
case WM_DESTROY:
{
RECT wrect;
if (GetWindowRect(wnd, &wrect)) {
NotifyRectangle(&wrect);
}
}
break;

case WM_WINDOWPOSCHANGED:
NotifyWindow(wnd, msg);
break;

case WM_PAINT:
// *** could improve this
NotifyWindowClientArea(wnd, msg);
break;

// Handle pop-up menus appearing
case 482:
NotifyWindow(wnd, 482);
break;

// Handle pop-up menus having items selected
case 485:
{
HANDLE prop = GetProp(wnd, (LPCTSTR) MAKELONG(ATOM_Popup_Selection, 0));
if (prop != (HANDLE) wParam) {
NotifyWindow(wnd, 485);
SetProp(wnd,
(LPCTSTR) MAKELONG(ATOM_Popup_Selection, 0),
(HANDLE) wParam);
}
}
break;

case WM_NCMOUSEMOVE:
case WM_MOUSEMOVE:
if (enable_cursor_shape) {
HCURSOR new_cursor = GetCursor();
if (new_cursor != cursor) {
cursor = new_cursor;
NotifyCursor(cursor);
}
}
break;

/* ***
if (prf_use_GetUpdateRect)
{
HRGN region;
region = CreateRectRgn(0, 0, 0, 0);

// Get the affected region
if (GetUpdateRgn(hWnd, region, FALSE) != ERROR)
{
int buffsize;
UINT x;
RGNDATA *buff;
POINT TopLeft;

// Get the top-left point of the client area
TopLeft.x = 0;
TopLeft.y = 0;
if (!ClientToScreen(hWnd, &TopLeft))
break;

// Get the size of buffer required
buffsize = GetRegionData(region, 0, 0);
if (buffsize != 0)
{
buff = (RGNDATA *) new BYTE [buffsize];
if (buff == NULL)
break;

// Now get the region data
if(GetRegionData(region, buffsize, buff))
{
for (x=0; x<(buff->rdh.nCount); x++)
{
// Obtain the rectangles from the list
RECT *urect = (RECT *) (((BYTE *) buff) + sizeof(RGNDATAHEADER) + (x * sizeof(RECT)));
SendDeferredUpdateRect(
hWnd,
(SHORT) (TopLeft.x + urect->left),
(SHORT) (TopLeft.y + urect->top),
(SHORT) (TopLeft.x + urect->right),
(SHORT) (TopLeft.y + urect->bottom)
);
}
}

delete [] buff;
}
}

// Now free the region
if (region != NULL)
DeleteObject(region);
}
*/
};
}

LRESULT CALLBACK HookCallWndProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == HC_ACTION) {
CWPSTRUCT* info = (CWPSTRUCT*) lParam;
ProcessWindowMessage(info->message, info->hwnd, info->wParam, info->lParam);
}
return CallNextHookEx(hook_CallWndProc, nCode, wParam, lParam);
}

LRESULT CALLBACK HookCallWndProcRet(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == HC_ACTION) {
CWPRETSTRUCT* info = (CWPRETSTRUCT*) lParam;
ProcessWindowMessage(info->message, info->hwnd, info->wParam, info->lParam);
}
return CallNextHookEx(hook_CallWndProcRet, nCode, wParam, lParam);
}

LRESULT CALLBACK HookGetMessage(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == HC_ACTION) {
if (wParam & PM_REMOVE) {
MSG* msg = (MSG*) lParam;
ProcessWindowMessage(msg->message, msg->hwnd, msg->wParam, msg->lParam);
}
}
return CallNextHookEx(hook_GetMessage, nCode, wParam, lParam);
}

LRESULT CALLBACK HookDialogMessage(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == HC_ACTION) {
MSG* msg = (MSG*) lParam;
ProcessWindowMessage(msg->message, msg->hwnd, msg->wParam, msg->lParam);
}
return CallNextHookEx(hook_DialogMessage, nCode, wParam, lParam);
}

// - WM_Hooks_Install

BOOL WM_Hooks_Install(DWORD owner, DWORD thread) {
// - Are there already hooks set?
if (hook_owner) {
if (!PostThreadMessage(hook_owner, WM_HK_PingThread, 0, 0)) {
WM_Hooks_Remove(hook_owner);
} else {
return FALSE;
}
}

// - Initialise the hooks
hook_owner = owner;
hook_target = thread;

hook_CallWndProc = SetWindowsHookEx(WH_CALLWNDPROC, HookCallWndProc, dll_instance, thread);
hook_CallWndProcRet = SetWindowsHookEx(WH_CALLWNDPROCRET, HookCallWndProcRet, dll_instance, thread);
hook_GetMessage = SetWindowsHookEx(WH_GETMESSAGE, HookGetMessage, dll_instance, thread);
hook_DialogMessage = SetWindowsHookEx(WH_SYSMSGFILTER, HookDialogMessage, dll_instance, thread);

if (!hook_CallWndProc /*|| !hook_CallWndProcRet*/ || !hook_GetMessage || !hook_DialogMessage) {
WM_Hooks_Remove(owner);
return FALSE;
}

return TRUE;
}

// - WM_Hooks_Remove

BOOL WM_Hooks_Remove(DWORD owner) {
if (owner != hook_owner) return FALSE;
if (hook_CallWndProc) {
UnhookWindowsHookEx(hook_CallWndProc);
hook_CallWndProc = 0;
}
if (hook_CallWndProcRet) {
UnhookWindowsHookEx(hook_CallWndProcRet);
hook_CallWndProcRet = 0;
}
if (hook_GetMessage) {
UnhookWindowsHookEx(hook_GetMessage);
hook_GetMessage = 0;
}
if (hook_DialogMessage) {
UnhookWindowsHookEx(hook_DialogMessage);
hook_DialogMessage = 0;
}
hook_owner = 0;
hook_target = 0;
return TRUE;
}

//
// -=- User input hooks
//

#pragma data_seg(&quot;.WM_Hooks_Shared&quot;)
HHOOK hook_keyboard = 0;
HHOOK hook_pointer = 0;
bool enable_real_ptr = true;
bool enable_synth_ptr = true;
bool enable_real_kbd = true;
bool enable_synth_kbd = true;
#pragma data_seg()

#ifdef WH_KEYBOARD_LL
LRESULT CALLBACK HookKeyboardHook(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode >= 0) {
KBDLLHOOKSTRUCT* info = (KBDLLHOOKSTRUCT*) lParam;
bool real_event = (info->flags & LLKHF_INJECTED) == 0;
if ((real_event && !enable_real_kbd) ||
(!real_event && !enable_synth_kbd)) {
return 1;
}
}
return CallNextHookEx(hook_keyboard, nCode, wParam, lParam);
}

LRESULT CALLBACK HookPointerHook(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode >= 0) {
MSLLHOOKSTRUCT* info = (MSLLHOOKSTRUCT*) lParam;
bool real_event = (info->flags & LLMHF_INJECTED) == 0;
if ((real_event && !enable_real_ptr) ||
(!real_event && !enable_synth_ptr)) {
return 1;
}
}
return CallNextHookEx(hook_keyboard, nCode, wParam, lParam);
}

bool RefreshInputHooks() {
bool success = true;
bool set_ptr_hook = !enable_real_ptr || !enable_synth_ptr;
bool set_kbd_hook = !enable_real_kbd || !enable_synth_kbd;
if (hook_keyboard && !set_kbd_hook) {
UnhookWindowsHookEx(hook_keyboard);
hook_keyboard = 0;
}
if (hook_pointer && !set_ptr_hook) {
UnhookWindowsHookEx(hook_pointer);
hook_pointer = 0;
}
if (!hook_keyboard && set_kbd_hook) {
hook_keyboard = SetWindowsHookEx(WH_KEYBOARD_LL, HookKeyboardHook, dll_instance, 0);
if (!hook_keyboard) success = false;
}
if (!hook_pointer && set_ptr_hook) {
hook_pointer = SetWindowsHookEx(WH_MOUSE_LL, HookPointerHook, dll_instance, 0);
if (!hook_pointer) success = false;
}
return success;
}
#else
#pragma message(&quot; NOTE: low-level mouse and keyboard hooks not supported&quot;)
#endif

// - WM_Hooks_EnableRealInputs

BOOL WM_Hooks_EnableRealInputs(BOOL pointer, BOOL keyboard) {
#ifdef WH_KEYBOARD_LL
enable_real_ptr = pointer!=0;
enable_real_kbd = keyboard!=0;
return RefreshInputHooks();
#else
return FALSE;
#endif
}

// - WM_Hooks_EnableSynthInputs

BOOL WM_Hooks_EnableSynthInputs(BOOL pointer, BOOL keyboard) {
#ifdef WH_KEYBOARD_LL
enable_synth_ptr = pointer!=0;
enable_synth_kbd = keyboard!=0;
return RefreshInputHooks();
#else
return FALSE;
#endif
}

// - WM_Hooks_EnableCursorShape

BOOL WM_Hooks_EnableCursorShape(BOOL enable) {
enable_cursor_shape = enable;
return TRUE;
}
 
很遗憾 C++ 代码我看不懂
 
看不懂就去学习C++
 
vnc是公认的比较好的
实际上你说的那种方法是这样的:
将当前图片与前一图片异或,因为异或后如果相同的部分将会变成0,不同的部分变成1,而正如大家所知,压缩时0越多压缩比越高

你最好还是看一下vnc
另外有人用直接使用显卡驱动程序的办法也取得了不错的效果
 
我试过屏幕分块传输,感觉速度上不是很理想,变化很小的时候确时很快,但变化大的时候就会感觉到慢了,由其在INTENET上,第1块与最后1块有明显的时差,VNC的方法还行,但应该还有优化的余地,希望用DELPHI改时过VNC的能把源码贴出来大家讨论,我发份VNC勾子的delphi源码吧(转来的)
unit UCallBacks;


interface


uses Windows, Messages, SysUtils,
Graphics,Classes;


///////////////////////////////////////////////////////////////////////////-/
// Storage for the global data in the DLL
var
hVeneto: HWND = 0;
UpdateRectMessage: UINT = 0;
CopyRectMessage: UINT = 0;
MouseMoveMessage: UINT = 0;
hCallWndHook: HHOOK = 0; // Handle to the CallWnd hook
hGetMsgHook: HHOOK = 0; // Handle to the GetMsg hook
hDialogMsgHook: HHOOK = 0; // Handle to the DialogMsg hook
hLLKeyboardHook: HHOOK = 0; // Handle to LowLevel kbd hook
hLLMouseHook: HHOOK = 0; // Handle to LowLevel mouse hook


///////////////////////////////////////////////////////////////////////////-/
// Per-instance DLL variables
// const
// char sPrefSegment[] = &quot;Application_Prefs//&quot;;
var
sModulePrefs: PChar = nil; // Name of the module that created us
prf_use_GetUpdateRect: Boolean = False; // Use the GetUpdateRect paint mode
prf_use_Timer: Boolean = False; // Use Timer events to trigger updates
prf_use_KeyPress: Boolean = False; // Use keyboard events
prf_use_LButtonUp: Boolean = True; // Use left mouse button up events
prf_use_MButtonUp: Boolean = False; // Use middle mouse button up events
prf_use_RButtonUp: Boolean = False; // Use right mouse button up events
prf_use_Deferral: Boolean = False; // Use deferred updates


hModuleKey: HKEY = 0; // Key used to save settings
// hInstance: HINSTANCE = NULL; // This instance of the DLL
HookMaster: Boolean = False; // Is this instance veneto itself?


appHookedOK: Boolean = False; // Did InitInstance succeed?


///////////////////////////////////////////////////////////////////////////-/

// Registered messages & atoms to be used by VNCHooks.DLL


// Messages
var
VNC_DEFERRED_UPDATE: UINT = 0;


// Atoms
VNC_WINDOWPOS_ATOMNAME: TAtom = 0;
VNC_POPUPSELN_ATOMNAME: TAtom = 0;
VNC_WINDOWPOS_ATOM: TAtom = 0;
VNC_POPUPSELN_ATOM: TAtom = 0;


// Forward definition of hook procedures


function HookHandle(Msg: LongWord; Wnd: HWND; wParam: Longint; lParam:
Longint): BOOL; stdcall;
function CallWndProc(nCode: Integer; wParam: Longint; lParam: Longint):
LRESULT; stdcall;
function GetMessageProc(nCode: Integer; wParam: Longint; lParam: Longint):
LRESULT; stdcall;
function DialogMessageProc(nCode: Integer; wParam: Longint; lParam:
Longint): LRESULT; stdcall;
function LowLevelKeyboardFilterProc(nCode: Integer; wParam: Longint; lParam:
Longint): LRESULT; stdcall;
function LowLevelMouseFilterProc(nCode: Integer; wParam: Longint; lParam:
Longint): LRESULT; stdcall;


function SetHook(Wnd: HWND; UpdateMsg: LongWord; CopyMsg: LongWord;
MouseMsg: LongWord): BOOL; stdcall; export;
function UnSetHook(Wnd: HWND): BOOL; stdcall; export;
function SetKeyboardFilterHook(Activate: BOOL): BOOL; stdcall; export;
function SetMouseFilterHook(Activate: BOOL): BOOL; stdcall; export;


// Forward definition of setup and shutdown procedures
function InitInstance(): BOOL;
function ExitInstance(): BOOL;


implementation
var
rr:trect;
na:integer;

procedure ToBmp(R: TRect);
var
Mybmp:Tbitmap;
dc: hdc;
Mycan: Tcanvas;

begin
Mybmp := Tbitmap.Create; {建立BMPMAP }
Mycan := TCanvas.Create; {屏幕截取}
dc := GetWindowDC(0);
try
Mycan.Handle := dc;
Mybmp.Width :=r.Right-r.Left;
Mybmp.Height :=r.Bottom-r.Top;
Mybmp.Canvas.CopyRect(R, Mycan, R);
finally
releaseDC(0, DC);
end;
Mycan.Handle := 0;
Mycan.Free;
Mybmp.SaveToFile('d:/w/'+inttostr(na)+'.bmp');
inc(na);
Mybmp.Free;
end;

function DllMain(hInst: HWND; ul_reason_for_call: ULONG; lpReserved:
Integer): BOOL; stdcall;
begin
// Find out why we're being called
case (ul_reason_for_call) of
DLL_PROCESS_ATTACH:
begin
// Call the initialisation function
appHookedOK := InitInstance();
// ALWAYS return TRUE to avoid breaking unhookable applications!!!
Result := True;
end;
DLL_PROCESS_DETACH:
begin
// Call the exit function
// If the app failed to hook OK, ExitInstance will still operate OK (hopefully...)
ExitInstance();
Result := TRUE;
end;
else
Result := TRUE;
end;
end;


// Routine to start and stop local keyboard message filtering


function SetKeyboardFilterHook(Activate: BOOL): BOOL; stdcall;
begin
if (Activate) then
begin
if (hLLKeyboardHook = 0) then
begin
// Start up the hook...
hLLKeyboardHook := SetWindowsHookEx(
WH_KEYBOARD, // Hook in before msg reaches app
LowLevelKeyboardFilterProc, // Hook procedure
hInstance, // This DLL instance
0 // Hook in to all apps
);
if (hLLKeyboardHook = 0) then
Result := False
else
Result := TRUE;
end
else
Result := true;
end
else
begin
if (hLLKeyboardHook <> 0) then
begin
// Stop the hook...
Result := (UnhookWindowsHookEx(hLLKeyboardHook));
hLLKeyboardHook := 0;
end
else
Result := True;
end;
end;


// Routine to start and stop local mouse message filtering


function SetMouseFilterHook(Activate: BOOL): BOOL; stdcall;
begin
if (Activate) then
begin
Result := (hLLMouseHook = 0);
if Result then
begin
// Start up the hook...
hLLMouseHook := SetWindowsHookEx(
WH_MOUSE, // Hook in before msg reaches app
LowLevelMouseFilterProc, // Hook procedure
hInstance, // This DLL instance
0 // Hook in to all apps
);
if (hLLMouseHook = 0) then Result := False;
end;
end
else
begin
if (hLLMouseHook <> 0) then
Result := (UnhookWindowsHookEx(hLLMouseHook)) // Stop the hook...
else
Result := True;
hLLMouseHook := 0;
end;
end;


// Add the new hook


function SetHook(Wnd: HWND; UpdateMsg: LongWord; CopyMsg: LongWord;
MouseMsg: LongWord): BOOL stdcall;
begin
// InitInstance;

// Don't add the hook if the window ID is NULL
if (Wnd = 0) then
begin
Result := False;
exit;
end;


// Don't add a hook if there is already one added
if (hVeneto <> 0) then
begin
Result := False;
exit;
end;


// Add the CallWnd hook
hCallWndHook := SetWindowsHookEx(
WH_CALLWNDPROC, // Hook in before msg reaches app
CallWndProc, // Hook procedure
hInstance, // This DLL instance
0 // Hook in to all apps
// GetWindowThreadProcessId(Wnd, nil) // DEBUG : HOOK ONLY WinVNC
);


// Add the GetMessage hook
hGetMsgHook := SetWindowsHookEx(
WH_GETMESSAGE, // Hook in before msg reaches app
GetMessageProc, // Hook procedure
hInstance, // This DLL instance
0 // Hook in to all apps
// GetWindowThreadProcessId(Wnd, nil) // DEBUG : HOOK ONLY WinVNC
);


// Add the GetMessage hook
hDialogMsgHook := SetWindowsHookEx(
WH_SYSMSGFILTER, // Hook in dialogs, menus and scrollbars
DialogMessageProc, // Hook procedure
hInstance, // This DLL instance
0 // Hook in to all apps
);


// Check that it worked
if ((hCallWndHook <> 0) and (hGetMsgHook <> 0) and (hDialogMsgHook <> 0))
then
begin
hVeneto := Wnd; // Save the WinRFB window handle
UpdateRectMessage := UpdateMsg; // Save the message ID to use for rectangle updates
CopyRectMessage := CopyMsg; // Save the message ID to use for copyrect
MouseMoveMessage := MouseMsg; // Save the message ID to send when mouse moves
HookMaster := TRUE; // Set the HookMaster flag for this instance


Result := True;
end
else
begin
// Stop the keyboard hook
SetKeyboardFilterHook(FALSE);
SetMouseFilterHook(FALSE);


// Kill the main hooks
if (hCallWndHook <> 0) then
UnhookWindowsHookEx(hCallWndHook);
if (hGetMsgHook <> 0) then
UnhookWindowsHookEx(hGetMsgHook);
if (hDialogMsgHook <> 0) then
UnhookWindowsHookEx(hDialogMsgHook);
hCallWndHook := 0;
hGetMsgHook := 0;
hDialogMsgHook := 0;


// The hook failed, so return an error code
Result := True;
end;
end;


// Remove the hook from the system


function UnSetHook(Wnd: HWND): BOOL; stdcall;


// EnumWindows procedure to remove the extra property we added


function KillPropsProc(Wnd: HWND; lParam: Longint): BOOL; stdcall;
begin
// Remove our custom property...
RemoveProp(Wnd, PChar(MAKEWORD(VNC_WINDOWPOS_ATOM, 0)));
RemoveProp(Wnd, PChar(MAKEWORD(VNC_POPUPSELN_ATOM, 0)));
Result := True;
end;


var
unHooked: BOOL;
begin
unHooked := True;


// Remove the extra property value from all local windows
EnumWindows(@KillPropsProc, 0);


// Stop the keyboard & mouse hooks
unHooked := unHooked and SetKeyboardFilterHook(FALSE);
unHooked := unHooked and SetMouseFilterHook(FALSE);


// Is the window handle valid?
if (Wnd = 0) then
MessageBox(GetDesktopWindow, 'Window pointer is null', nil, MB_OK);


// Is the correct application calling UnSetHook?
if (Wnd <> hVeneto) then
Result := False;


// Unhook the procs
if (hCallWndHook <> 0) then
begin
unHooked := unHooked and UnhookWindowsHookEx(hCallWndHook);
hCallWndHook := 0;
end;


if (hGetMsgHook <> 0) then
begin
unHooked := unHooked and UnhookWindowsHookEx(hGetMsgHook);
hGetMsgHook := 0;
end;


if (hDialogMsgHook <> 0) then
begin
unHooked := unHooked and UnhookWindowsHookEx(hDialogMsgHook);
hDialogMsgHook := 0;
end;


// If we managed to unhook then reset
if (unHooked) then
begin
hVeneto := 0;
HookMaster := False;
end;


Result := unHooked;
end;


// Routine to get the window's client rectangle, in screen coordinates


function GetAbsoluteClientRect(Wnd: HWnd; var Rect: TRect): BOOL;
var
topleft: TPoint;
begin
topleft.x := 0;
topleft.y := 0;


Result := (GetClientRect(Wnd, Rect)); // Get the client rectangle size
if Result then
Result := (ClientToScreen(Wnd, topleft)); // Get the client rectangle position
if Result then
begin
// Now adjust the window rectangle
rect.Left := rect.Left + topleft.x;
rect.Top := rect.Top + topleft.y;
rect.Right := rect.Right + topleft.x;
rect.Bottom := rect.Bottom + topleft.y;
end;
end;


(******************************************************************
// Routine to send a CopyRect message to WinVNC
inline void SendCopyWindowRect(HWND hWnd)
{
WPARAM vwParam;


// All we send back is the handle of the window to be moved
vwParam = (LPARAM) hWnd;


// Send the update to Veneto
PostMessage(
hVeneto,
CopyRectMessage,
vwParam,
0
);


}


**********************************************)

// Routine to send an UpdateRect message to Veneto


//procedure SendUpdateRect(x, y, x2, y2: ShortInt);

procedure SendUpdateRect(x, y, x2, y2: Smallint);
var
vwParam: Longint;
vlParam: Longint;
begin

OutputDebugString(PChar(IntToStr(x) + ',' + IntToStr(y) + ',' + IntToStr(x2) + ',' + IntToStr(y2)));
vwParam := MAKELONG(x, y);
vlParam := MAKELONG(x2, y2);


// Send the update to Veneto
PostMessage(
hVeneto,
UpdateRectMessage,
vwParam,
vlParam
);


end;


// Send a window's position to Veneto


procedure SendWindowRect(Wnd: HWND);
var
wrect: TRect;
begin
// Get the rectangle position
if (GetWindowRect(Wnd, wrect) and IsWindowVisible(Wnd)) then
// Send the position
{SendUpdateRect(
wrect.Left,
wrect.Top,
wrect.Right,
wrect.Bottom
); {}
// tobmp(wrect);
end;


// Send a deferred message into this Window's message queue, so that
// we'll intercept it again only after the message that triggered it hasbeen
// handled


//procedure SendDeferredUpdateRect(Wnd: HWND; x, y, x2, y2: ShortInt);

procedure SendDeferredUpdateRect(Wnd: HWND; x, y, x2, y2: Smallint);
var
vwParam: Longint;
vlParam: Longint;
begin

OutputDebugString(PChar(IntToStr(x) + ',' + IntToStr(y) + ',' + IntToStr(x2) + ',' + IntToStr(y2)));
rr:=rect(x,y,x2,y2);
vwParam := MAKELONG(x, y);
vlParam := MAKELONG(x2, y2);


if (prf_use_Deferral) then
// Send the update back to the window
PostMessage(
Wnd,
VNC_DEFERRED_UPDATE,
vwParam,
vlParam
)
else
// Send the update to WinRFB
PostMessage(
hVeneto,
UpdateRectMessage,
vwParam,
vlParam
);
end;


procedure SendDeferredWindowRect(Wnd: HWND);
var
wrect: TRect;
begin
// Get the rectangle position
if (GetWindowRect(Wnd, wrect) and IsWindowVisible(Wnd)) then
// Send the position

SendDeferredUpdateRect(
Wnd,
wrect.left,
wrect.top,
wrect.right,
wrect.bottom
);
end;


procedure SendDeferredBorderRect(Wnd: HWND);
var
wrect: TRect;
crect: TRect;
begin
// Get the rectangle position
if (GetWindowRect(Wnd, wrect) and IsWindowVisible(Wnd)) then
// Get the client rectangle position
if (GetAbsoluteClientRect(Wnd, crect)) then
begin
// Send the four border rectangles
SendDeferredUpdateRect(Wnd, wrect.left, wrect.top, wrect.right,
crect.top);
SendDeferredUpdateRect(Wnd, wrect.left, wrect.top, crect.left,
wrect.bottom);
SendDeferredUpdateRect(Wnd, wrect.left, crect.bottom, wrect.right,
wrect.bottom);
SendDeferredUpdateRect(Wnd, crect.right, wrect.top, wrect.right,
wrect.bottom);
end;
end;


// Generic hook-handler


function HookHandle(Msg: LongWord; Wnd: HWND; wParam: Longint; lParam:
Longint): BOOL; stdcall;
var
Prop: HWnd;
region: HRGN;
buffsize: Integer;
x: Longint;
buff: PRgnData;
TopLeft: Tpoint;
uRect: PRect;
begin
Result := True;
////////////////////////////////////////////////////////////////
// *** HANDLE DEFERRED UPDATES ***


// Is this a deferred-update message?
if (Msg = VNC_DEFERRED_UPDATE) then
begin
// NOTE : NEVER use the SendDeferred- routines to send updates
// from here, or you'll get an infinite loop....!


// NB : The format of DEFERRED_UPDATE matches that of UpdateRectMessage,
// so just send the exact same message data to WinRFB:
PostMessage(
hVeneto,
UpdateRectMessage,
wParam,
lParam
);
Result := False;
end;


// *** Could use WM_COPYDATA to send data to WinVNC


(**********************************************
if (GetClassLong(hWnd, GCW_ATOM) = = 32768)
{
_RPT4(_CRT_WARN, &quot;DBG : popup menu message (hwnd=%d, msg=%d, l=%d,
w=%d)/n&quot;,
hWnd, MessageId, lParam, wParam);


}


* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * )
**********************************************)

////////////////////////////////////////////////////////////////
// *** UPDATE-TRIGGERING MESSAGES ***
// Do something dependent upon message type
case Msg of
////////////////////////////////////////////////////////////////
// Messages indicating only a border repaint.
WM_NCPAINT: Result := True;
WM_NCACTIVATE:
begin
SendDeferredBorderRect(Wnd);
Exit;
end;
////////////////////////////////////////////////////////////////
// Messages indicating a client area repaint
WM_CHAR: Result := True;
WM_KEYUP: // Handle key-presses
begin
if (prf_use_KeyPress) then
SendDeferredWindowRect(Wnd);
Exit;
end;


WM_LBUTTONUP: // Handle LMB clicks
begin
if (prf_use_LButtonUp) then
SendDeferredWindowRect(Wnd);
Exit;
end;


WM_MBUTTONUP: // Handle MMB clicks
begin
if (prf_use_MButtonUp) then
SendDeferredWindowRect(Wnd);
Exit;
end;


WM_RBUTTONUP: // Handle RMB clicks
begin
if (prf_use_RButtonUp) then
SendDeferredWindowRect(Wnd);
Exit;
end;


WM_TIMER:
begin
if (prf_use_Timer) then
SendDeferredWindowRect(Wnd);
Exit;
end;


WM_HSCROLL: Result := True;
WM_VSCROLL:
begin
if ((LOWORD(wParam) = SB_THUMBTRACK) and not (LOWORD(wParam) =
SB_ENDSCROLL)) then
SendDeferredWindowRect(Wnd);
Exit;
end;


485: // HACK to handle popup menus
begin
// Get the old popup menu selection value
Prop := GetProp(Wnd, PChar(MAKELONG(VNC_POPUPSELN_ATOM, 0)));
if (prop <> Cardinal(wParam)) then
begin
// It did, so update the menu & the selection value
SendDeferredWindowRect(Wnd);
SetProp(Wnd,
PChar(MAKELONG(VNC_POPUPSELN_ATOM, 0)),
wParam);
end;
Exit;
end;


////////////////////////////////////////////////////////////////
// Messages indicating a full window update
WM_SYSCOLORCHANGE: Result := True;
WM_PALETTECHANGED: Result := True;
WM_SETTEXT: Result := True;
WM_ENABLE: Result := True;
BM_SETCHECK: Result := True;
BM_SETSTATE: Result := True;
EM_SETSEL:
begin
//case WM_MENUSELECT:
SendDeferredWindowRect(Wnd);
Exit;
end;
////////////////////////////////////////////////////////////////
// Messages indicating that an area of the window needs updating
// Uses GetUpdateRect to find out which
WM_PAINT:
begin
if (prf_use_GetUpdateRect) then
begin
region := CreateRectRgn(0, 0, 0, 0);
// Get the affected region
if (GetUpdateRgn(Wnd, region, FALSE) <> ERROR) then
begin
// Get the top-left point of the client area
TopLeft.x := 0;
TopLeft.y := 0;
if (ClientToScreen(Wnd, TopLeft)) then
begin
// Get the size of buffer required
buffsize := GetRegionData(region, 0, nil);
if (buffsize <> 0) then
begin
// Now get the region data
GetMem(buff, buffsize);
if (GetRegionData(region, buffsize, buff) <> ERROR) then
begin
for x := 0 to buff.rdh.nCount do
begin
// Obtain the rectangles from the list
uRect := PRect(Integer(buff) + SizeOf(TRgnDataHeader) +
(x * SizeOf(TRect)));
SendDeferredUpdateRect(
Wnd,
(TopLeft.x + urect.Left),
(TopLeft.y + urect.Top),
(TopLeft.x + urect.Right),
(TopLeft.y + urect.Bottom)
);
end;
end;
FreeMem(buff);
end;
end;
end;


// Now free the region
if (region <> 0) then DeleteObject(region);
end
else
SendDeferredWindowRect(Wnd);
Exit;
end;
////////////////////////////////////////////////////////////////
// Messages indicating full repaint of this and a different window
// Send the new position of the window
WM_WINDOWPOSCHANGING:
begin
if IsWindowVisible(Wnd) then
SendWindowRect(Wnd);
Exit;
end;


WM_WINDOWPOSCHANGED:
begin
if IsWindowVisible(Wnd) then
SendDeferredWindowRect(Wnd);
Exit;
end;


////////////////////////////////////////////////////////////////
// WinRFB also wants to know about mouse movement
WM_NCMOUSEMOVE: Result := True;
WM_MOUSEMOVE:
begin
// Inform WinRFB that the mouse has moved and pass it the current cursor handle
PostMessage(
hVeneto,
MouseMoveMessage,
GetCursor(),
0
);
Exit;
end;


////////////////////////////////////////////////////////////////
// VNCHOOKS PROPERTIES HANDLING WINDOWS
WM_DESTROY:
begin
RemoveProp(Wnd, PChar(MAKEWORD(VNC_WINDOWPOS_ATOM, 0)));
RemoveProp(Wnd, PChar(MAKEWORD(VNC_POPUPSELN_ATOM, 0)));
Exit;
end;
end;
end;

//钩子回调函数
// Hook procedure for CallWindow hook

function CallWndProc(nCode: Integer; wParam: Longint; lParam: Longint):
LRESULT ;stdcall;
var
cwpStruct: PCwpStruct;
begin
// Do we have to handle this message?
if (nCode = HC_ACTION) then
if (hVeneto <> 0) then // Process the hook if the Veneto window handle is valid
begin
cwpStruct := PCwpStruct(lParam);
HookHandle(cwpStruct.message, cwpStruct.hwnd, cwpStruct.wParam,
cwpStruct.lParam);
end;


// Call the next handler in the chain
Result := CallNextHookEx(hCallWndHook, nCode, wParam, lParam);
end;


// Hook procedure for GetMessageProc hook


function GetMessageProc(nCode: Integer; wParam: Longint; lParam: Longint):
LRESULT ;stdcall;
var
Msg: PMsg;
begin
// Do we have to handle this message?
if (nCode = HC_ACTION) then
if (hVeneto <> 0) then // Process the hook only if the Veneto window is valid
begin
Msg := PMsg(lParam);
if (wParam = PM_REMOVE) then // Only handle application messages if they're being removed:
HookHandle(Msg.message, Msg.hwnd, Msg.wParam, Msg.lParam); // Handle the message
end;


// Call the next handler in the chain
Result := CallNextHookEx(hGetMsgHook, nCode, wParam, lParam);
end;


// Hook procedure for DialogMessageProc hook


function DialogMessageProc(nCode: Integer; wParam: Longint; lParam:
Longint): LRESULT ;stdcall;
var
Msg: PMsg;
begin
// Do we have to handle this message?
if (nCode >= 0) then
if (hVeneto <> 0) then // Process the hook only if the Veneto window is valid
begin
Msg := PMsg(lParam);
HookHandle(Msg.message, Msg.hwnd, Msg.wParam, Msg.lParam); // Handle the message
end;


// Call the next handler in the chain
Result := CallNextHookEx(hGetMsgHook, nCode, wParam, lParam);
end;


// Hook procedure for LowLevel Keyboard filtering


function LowLevelKeyboardFilterProc(nCode: Integer; wParam: Longint; lParam:
Longint): LRESULT ;stdcall;
var
Msg: PMsg;
begin
// Are we expected to handle this callback?
if (nCode = HC_ACTION) then
begin
Msg := PMsg(lParam);
HookHandle(Msg.message, Msg.hwnd, Msg.wParam, Msg.lParam); // Handle the message
end;


// Otherwise, pass on the message
Result := CallNextHookEx(hLLKeyboardHook, nCode, wParam, lParam);
end;


// Hook procedure for LowLevel Mouse filtering


function LowLevelMouseFilterProc(nCode: Integer; wParam: Longint; lParam:
Longint): LRESULT ;stdcall;
var
Msg: PMsg;
begin
// Are we expected to handle this callback?
if (nCode = HC_ACTION) then
begin
Msg := PMsg(lParam);
HookHandle(Msg.message, Msg.hwnd, Msg.wParam, Msg.lParam); // Handle the message
end;


// Otherwise, pass on the message
Result := CallNextHookEx(hLLMouseHook, nCode, wParam, lParam);
end;


function StrLen(const Str: PChar): Cardinal; assembler;
asm
MOV EDX,EDI
MOV EDI,EAX
MOV ECX,0FFFFFFFFH
XOR AL,AL
REPNE SCASB
MOV EAX,0FFFFFFFEH
SUB EAX,ECX
MOV EDI,EDX
end;


function NameFromPath(const path: PChar): PChar;
var
x: Integer;
l: Integer;
begin
l := strlen(path);
Result := nil;
// Find the file part of a filename
for x := (l - 1) downto 0 do
if (path[x] = '/') then
begin
Result := PChar(Copy(string(path), x + 1, l));
Break;
end;


// If we didn't fine a / then just return a copy of the original
if (Result = nil) then
Result := path;
end;


const
szSoftware = 'Software';
szCompany = 'Levin';
szProfile = 'HTHooks';


function GetRegistryKey(): HKEY;
var
hAppKey: HKEY;
hSoftKey: HKEY;
hCompanyKey: HKEY;
dw: PDWORD;
begin
hAppKey := 0;
hSoftKey := 0;
hCompanyKey := 0;


GetMem(dw, SizeOf(DWORD));


if (RegOpenKeyEx(HKEY_CURRENT_USER, szSoftware, 0, KEY_WRITE or KEY_READ,
hSoftKey) = ERROR_SUCCESS) then
begin
if (RegCreateKeyEx(hSoftKey, szCompany, 0, nil,
REG_OPTION_NON_VOLATILE, KEY_WRITE or KEY_READ, nil,
hCompanyKey, dw) = ERROR_SUCCESS) then
RegCreateKeyEx(hCompanyKey, szProfile, 0, nil,
REG_OPTION_NON_VOLATILE, KEY_WRITE or KEY_READ, nil,
hAppKey, dw);
end;
if (hSoftKey <> 0) then
RegCloseKey(hSoftKey);
if (hCompanyKey <> 0) then
RegCloseKey(hCompanyKey);


FreeMem(dw);


Result := hAppKey;
end;


function GetModuleKey(const proc_name: PChar): HKEY;
var
hModule: HKEY;
hAppKey: HKEY;
FileName: PChar;
dw: PDWORD;
begin
hModule := 0;

// Work out the registry key to save this under
// sModulePrefs := malloc(strlen(sPrefSegment) + strlen(proc_name) + 1);
sModulePrefs := PChar('Software/HowTo/HookUsage/' + proc_name);
// if (sModulePrefs = nil) then Result := 0;
// sprintf(sModulePrefs, &quot;%s%s&quot;, sPrefSegment, proc_name);


// Check whether the library's entry exists!
hAppKey := GetRegistryKey();
// if (hAppKey = 0) then Result := 0;


// Attempt to open the section for this application
if (RegOpenKeyEx(hAppKey,
sModulePrefs,
0, KEY_WRITE or KEY_READ,
hModule
) <> ERROR_SUCCESS) then
begin
// Cut off the app directory and just use the name
FileName := NameFromPath(proc_name);


if (FileName = nil) then
RegCloseKey(hAppKey);


// Adjust the moduleprefs name
// sprintf(sModulePrefs, &quot;%s%s&quot;, sPrefSegment, file_name);
sModulePrefs := PChar('Software/HowTo/HookUsage/' + FileName);

{ if FileName <> nil then
begin
Dec(FileName, SizeOf(Cardinal));
FreeMem(FileName, Cardinal(Pointer(FileName)^));
end;
}
GetMem(dw, SizeOf(DWORD));


// Now get the module key again
if (RegCreateKeyEx(hAppKey,
sModulePrefs,
0, nil, REG_OPTION_NON_VOLATILE,
KEY_WRITE or KEY_READ,
nil,
hModule,
dw) <> ERROR_SUCCESS) then
RegCloseKey(hAppKey); // Couldn't find/create the key - fail!


FreeMem(dw);
end;


// Close the application registry key
RegCloseKey(hAppKey);


Result := hModule;
end;


procedure WriteProfileInt(key: PChar; Value: Integer);
begin
RegSetValueEx(
hModuleKey,
key,
0,
REG_DWORD,
@Value,
sizeof(Value));
end;


function InitInstance(): BOOL;
var
proc_name: array[0..MAX_PATH] of Char;
Size: DWORD;
begin
// Create the global atoms
VNC_WINDOWPOS_ATOM := GlobalAddAtom(PChar(VNC_WINDOWPOS_ATOMNAME));
if (VNC_WINDOWPOS_ATOM = 0) then Result := False;


VNC_POPUPSELN_ATOM := GlobalAddAtom(PChar(VNC_POPUPSELN_ATOMNAME));
if (VNC_POPUPSELN_ATOM = 0) then Result := False;


// Attempt to get the program/module name
size := GetModuleFileName(
HInstance,
@proc_name,
MAX_PATH);
if Size = 0 then Result := False;


// Get the key for the module
hModuleKey := GetModuleKey(proc_name);
// if (hModuleKey = 0) then Result := False;


// Read in the prefs
prf_use_GetUpdateRect := BOOL(GetProfileInt(proc_name,
'use_GetUpdateRect',
Integer(True)));


prf_use_Timer := BOOL(GetProfileInt(proc_name,
'use_Timer',
Integer(FALSE)));
prf_use_KeyPress := BOOL(GetProfileInt(proc_name,
'use_KeyPress',
Integer(TRUE)));


prf_use_LButtonUp := BOOL(GetProfileInt(proc_name,
'use_LButtonUp',
Integer(TRUE)));


prf_use_MButtonUp := BOOL(GetProfileInt(proc_name,
'use_MButtonUp',
Integer(TRUE)));


prf_use_RButtonUp := BOOL(GetProfileInt(proc_name,
'use_RButtonUp',
Integer(TRUE)));


prf_use_Deferral := BOOL(GetProfileInt(proc_name,
'use_Deferral',
Integer(TRUE)));


Result := True;
end;


function ExitInstance(): BOOL;
begin


// Free the created atoms
if (VNC_WINDOWPOS_ATOM <> 0) then
begin
GlobalDeleteAtom(VNC_WINDOWPOS_ATOM);
VNC_WINDOWPOS_ATOM := 0;
end;


if (VNC_POPUPSELN_ATOM <> 0) then
begin
GlobalDeleteAtom(VNC_POPUPSELN_ATOM);
VNC_POPUPSELN_ATOM := 0;
end;


// Write the module settings to disk
if (sModulePrefs <> nil) then
begin


WriteProfileInt(
'use_GetUpdateRect',
Integer(prf_use_GetUpdateRect)
);


WriteProfileInt(
'use_Timer',
Integer(prf_use_Timer)
);


WriteProfileInt(
'use_KeyPress',
Integer(prf_use_KeyPress)
);


WriteProfileInt(
'use_LButtonUp',
Integer(prf_use_LButtonUp)
);


WriteProfileInt(
'use_MButtonUp',
Integer(prf_use_MButtonUp)
);


WriteProfileInt(
'use_RButtonUp',
Integer(prf_use_RButtonUp)
);


WriteProfileInt(
'use_Deferral',
Integer(prf_use_Deferral)
);

{
if sModulePrefs <> nil then
begin
Dec(sModulePrefs, SizeOf(Cardinal));
FreeMem(sModulePrefs, Cardinal(Pointer(sModulePrefs)^));
end;
}
sModulePrefs := nil;
end;


// Close the registry key for this module
if (hModuleKey <> 0) then
RegCloseKey(hModuleKey);


Result := True;
end;


initialization
DisableThreadLibraryCalls(HInstance);
VNC_DEFERRED_UPDATE :=
RegisterWindowMessage('HTHooks.Deferred.UpdateMessage');
VNC_WINDOWPOS_ATOMNAME :=
GlobalAddAtom(PChar('HTHooks.CopyRect.WindowPos'));
VNC_POPUPSELN_ATOMNAME :=
GlobalAddAtom(PChar('HTHooks.PopUpMenu.Selected'));


finalization
// Just saw this now, upsssss...
// GlobalDeleteAtom(VNC_DEFERRED_UPDATE);


end.

这个代码还有些问题希望能人,能候正一下,比如不能勾住所有程序
 
后退
顶部