OSDN Git Service

ab3a2d1a8f753a34594c356589d2a531f4f3c022
[dokopop/dokopop.git] / DCHook / DCHook.cpp
1 //---------------------------------------------------------------------------
2 //
3 // \96â\91è\93_\81F
4 // Ver0.50
5 //
6 // \8dÅ\93K\89»\82Ì\89Û\91è\81F
7 // standard library\82ð\8eg\82í\82È\82¢\82æ\82¤\82É\82·\82é
8 // \8b¤\97L\97Ì\88æ\82ð\91\9d\82â\82·
9 //
10 // Tips:
11 // \93Ë\91RDetach\82³\82ê\82é\8c»\8fÛ
12 // --> Hook Function\82Å\97á\8aO\82ª\94­\90\82µ\82Ä\82¢\82é\89Â\94\\90«\82ª\8d\82\82¢
13 //     \82à\82µ\82­\82Í\81A\83A\83v\83\8a\83P\81[\83V\83\87\83\93\82Å\97á\8aO\94­\90\82µ\82Ä\82¢\82é
14 // \8b¤\97L\83\81\83\82\83\8a\82É\82Â\82¢\82Ä
15 // \95¨\97\9d\83\81\83\82\83\8a\82ª\93¯\88ê\82¾\82¯\82Å\82 \82Á\82Ä\81A\98_\97\9d\83A\83h\83\8c\83X\82Í\93¯\88ê\82Æ\82Í\8cÀ\82ç\82È\82¢\81I\81I
16 // \8f]\82Á\82Ä\81A\8b¤\97L\83\81\83\82\83\8a\8fã\82Épointer\82ð\94z\92u\82·\82é\82±\82Æ\82Í\8aî\96{\93I\82É\8aë\8c¯\81I\81I
17 #define STRICT
18 #include <windows.h>
19 #include <tchar.h>
20 #pragma hdrstop
21 #ifndef GWL_WNDPROC
22 #define GWL_WNDPROC         (-4)        // \82±\82Ì\92è\8b`\82ª\82È\82¢\82Æerror\82É\82È\82Á\82½ 2014.11.19
23 #endif
24 #include <tlhelp32.h>
25 #include <imagehlp.h>
26 #pragma comment(lib, "ImageHlp")
27 #include "DCHook.h"
28 #ifndef UNICODE
29 #include "..\VxD\hk95d.h"
30 #endif
31 #include "MonitorScale.h"
32
33 // Compiler //
34 #pragma warning( disable : 4710 )       // \82Ç\82¤\82µ\82Ä\82±\82¤\82¢\82¤warning\82ª\8fo\82Ä\82­\82é\82Ì\82©\81H
35
36 // Configuration //
37 #define USE_SCALING             1       // Uses DPI scaling
38
39 #define USE_DBW                 0       // DBW\82ð\8eg\97p\82·\82é
40 #define USE_SHARE0              1       // share\82µ\82Ä\82à\96â\91è\82È\82¢\95Ï\90\94
41
42 #define METAEXTTEXTOUT  1       // MetaMethod\82ÅExtTextOutx\82ðhook\82·\82é
43 #define HOOK_GETDC              0       // GetDC(),ReleaseDC()\82ðhook\82·\82é
44 #define HOOK_TEXT               0       // DrawText(Ex),TextOut,TabbedTextOut\82Ìhooking
45 #define USE_REDRAW              1
46 #define HOOK_BITBLT             0       // 2016.1.15 \8aO\82µ\82Ä\82Ý\82½
47 #define HOOK_PAINT              0
48 #define GUARD                   0       // \8b¤\97L\83\81\83\82\83\8a\82ðVirtualProtect\82Åguard\82·\82é
49                                                         // \97L\8cø\82É\82·\82é\82ÆApplication\8fI\97¹\8e\9e\82É\88Ù\8fí\8fI\97¹\82ª\94­\90\82·\82é
50                             // Application close ->
51                             // \8c´\88ö\81FDettach\82·\82é\91O\82É\81AOS or Application\82ª
52                             // Protected code\97Ì\88æ\82É\8f\91\82«\8d\9e\82Ý\82ð\8ds\82Á\82Ä\82¢\82é\82æ\82¤\82¾
53
54 #define USE_INVALIDATE          0       // \95`\89æ\91O\82ÉInvalidate\82ð\91\97\82é(IE5@Win98\82Í\95K\97v)
55 #define INVALIDATE_TRUE         0       // InvalidateRect\82Årepaint\82ð\8ds\82¤
56 #define ORG_OFFSET                      1       // ViewPort\82Ìorg offset\8f\88\97\9d\82ð\8ds\82¤
57
58 #define USE_OPTIMALINVALID      1       // \8dÄ\95`\89æ\97Ì\88æ\82ð\82È\82é\82×\82­\8f¬\82³\82­\82·\82é
59 #define USE_VXD                         0       // no longer support (Win9x)
60 #define EXC_WOW64                       0       // do not attach on WOW64
61
62 #define MAX_KEYS                        8       // \83L\81[\83t\83\89\83O\82Ì\8dÅ\91å\92è\8b`\90\94
63
64 #define DEBUG_HITTEXT           0       // for debug hit text
65
66 // ExtTextOut hooking\82ÅMetafile\82à\8eg\97p\82·\82é
67 // \92P\93Æ\82Å\8ds\82¤\8fê\8d\87\82Í\81ARETRYMETA
68 #if HOOK_PAINT || HOOK_GETDC || !USE_REDRAW
69 #define USE_META        1
70 #else
71 #define USE_META        0
72 #endif
73
74 #define RETRYMETA       1
75
76 #if USE_DBW
77 #include <stdio.h>
78 #else   // !USE_DBW
79 #undef DEBUG_HITTEXT
80 #define DEBUG_HITTEXT   0
81 #endif  // !USE_DBW
82
83 #define MOVESEND_POST   1
84
85 // Type Definitions //
86
87 // Macros //
88 #if GUARD
89 #define PROTECT_SHARE()         ShareProtect( true )
90 #define UNPROTECT_SHARE()       ShareProtect( false )
91 #else
92 #define PROTECT_SHARE()
93 #define UNPROTECT_SHARE()
94 #endif
95
96 #if USE_DBW
97 #define DBW             dbw
98 #else
99 #define DBW             (void)
100 #endif
101 void dbw(const char *format, ...);
102
103 #define WM_AMODI                                (WM_APP+0x400)  // app communication message with AMODI
104 #define WM_MOVESEND                             (WM_APP+0x208)  // DCH_MOVESEND\82Ì\91ã\82í\82è\82ÉPostMessage\82Å\91\97\82é
105 #define AMODI_CMD_QUERY                 0
106 #define AMODI_CMD_PAGE_CAPTURE  1
107
108 #define tsizeof(type)   sizeof(type)
109 #define int_bool(v)             ((v)!=0)
110
111 #pragma warning (disable : 4996)
112
113 //==============================================//
114 // TString template class                                               //
115 //==============================================//
116 template <class T>
117 class TString {
118 protected:
119         T *Buffer;
120         int Size;       // Buffer size in character
121         int Length;     // String length in character
122 public:
123         TString();
124         ~TString();
125         void Clear()
126                 { Buffer[0] = '\0'; Length = 0; }
127         void Set( const T *str, int len );
128         void Set( TString *obj )
129                 { Set( obj->c_str(), obj->Length ); }
130         void Cat( const T *str, int len );
131         operator const T *() const
132                 { return Buffer; }
133         T operator [] ( int index )
134                 { return Buffer[index]; }
135         const T *c_str()
136                 { return Buffer; }
137         int GetLength() const { return Length; }
138         int GetByte() const { return Length * sizeof(T); }
139 //      int GetSize() const { return Size; }
140 };
141 template <class T>
142 TString<T>::TString()
143 {
144         Size = 256;             // initial size
145         Buffer = new T[ Size + 1 ];
146         if (!Buffer)
147                 Size = 0;
148         Length = 0;
149 }
150 template <class T>
151 TString<T>::~TString()
152 {
153         if (Buffer)
154                 delete[] Buffer;
155 }
156 template <class T>
157 void TString<T>::Set( const T *str, int len )
158 {
159         if (Buffer){
160                 if ( Size < len ){
161                         // not enough space to store
162                         delete[] Buffer;
163                 } else goto j1;
164         }
165         Buffer = new T[ len + 1 ];
166         Size = len;
167         if (Buffer){
168 j1:;
169                 CopyMemory( Buffer, str, len*sizeof(T) );
170                 Buffer[len] = '\0';
171                 Length = len;
172         } else {
173                 Size = 0;
174                 Length = 0;
175         }
176 }
177 template <class T>
178 void TString<T>::Cat( const T *str, int len )
179 {
180         if (!Buffer){
181                 Set( str, len );
182                 return;
183         }
184         int newlen = Length + len;
185         if (Size < newlen){
186                 T *p = new T[ newlen + 1 ];
187                 if (p)
188                         CopyMemory( p, Buffer, newlen*sizeof(T) );
189                 delete[] Buffer;
190                 Buffer = p;
191                 Size = newlen;
192         }
193         if (Buffer){
194                 CopyMemory( Buffer+Length, str, len * sizeof(T) );
195                 Buffer[newlen] = '\0';
196                 Length = newlen;
197         } else {
198                 Size = 0;
199                 Length = 0;
200                 Set( str, len );
201         }
202 }
203
204 int GetTextFromPoint( HDC hdc, const char *text, int len, int pos, int pos_y, const int *dx=NULL );
205 int GetTextFromPoint( HDC hdc, const wchar_t *text, int len, int pos, int pos_y, const int *dx=NULL );
206
207 bool CaptureImage(HWND hwnd, bool movesend, bool non_block);
208 bool WaitAndGetResult(const TCHAR *text_path, unsigned waittime);
209 HANDLE WaitForResult(const TCHAR *text_path, unsigned waittime);
210 HWND FindAMODI();
211 int SendAMODI(int cmd, const char *data, int len);
212 void CheckAMODIAlive();
213 void SendMoveMessage();
214 void SendCancelMove();
215 DWORD WINAPI SendMoveThread(LPVOID vdParam);
216 void CheckWOW64();
217
218 extern "C" {
219 //==============================================//
220 // Prototypes                                                                   //
221 //==============================================//
222 typedef HDC (WINAPI *FNBeginPaint)( HWND, LPPAINTSTRUCT );
223 typedef BOOL (WINAPI *FNEndPaint)( HWND, CONST PAINTSTRUCT * );
224 typedef HDC (WINAPI *FNGetDC)( HWND );
225 typedef int (WINAPI *FNReleaseDC)( HWND, HDC );
226 typedef BOOL (WINAPI *FNExtTextOutW)(HDC hdc, int x, int y, UINT option, CONST RECT *rc, LPCWSTR str, UINT count, CONST INT *dx );
227 typedef BOOL (WINAPI *FNExtTextOutA)(HDC hdc, int x, int y, UINT option, CONST RECT *rc, LPCSTR str, UINT count, CONST INT *dx );
228 typedef BOOL (WINAPI *FNBitBlt)(HDC hdcdest, int xdest, int ydest, int width, int height, HDC hdcsrc, int xsrc, int ysrc, DWORD rop );
229
230 typedef LONG (WINAPI *FNTabbedTextOutA)( HDC hdc, int x, int y, LPCSTR str, int count, int ntabs, LPINT tabs, int origin );
231 typedef LONG (WINAPI *FNTabbedTextOutW)( HDC hdc, int x, int y, LPCWSTR str, int count, int ntabs, LPINT tabs, int origin );
232 typedef BOOL (WINAPI *FNTextOutA)( HDC hdc, int x, int y, LPCSTR str, int count );
233 typedef BOOL (WINAPI *FNTextOutW)( HDC hdc, int x, int y, LPCWSTR str, int count );
234 typedef int (WINAPI *FNDrawTextA)( HDC hdc, LPCSTR str, int count, LPRECT rc, UINT format );
235 typedef int (WINAPI *FNDrawTextW)( HDC hdc, LPCWSTR str, int count, LPRECT rc, UINT format );
236 typedef int (WINAPI *FNDrawTextExA)( HDC hdc, LPCSTR str, int count, LPRECT rc, UINT format, LPDRAWTEXTPARAMS params );
237 typedef int (WINAPI *FNDrawTextExW)( HDC hdc, LPCWSTR str, int count, LPRECT rc, UINT format, LPDRAWTEXTPARAMS params );
238
239 typedef BOOL (WINAPI *FNMoveToEx)(HDC hdc, int x, int y, LPPOINT pt );
240
241
242 HDC WINAPI _BeginPaint( HWND hwnd, LPPAINTSTRUCT ps );
243 BOOL WINAPI _EndPaint( HWND hwnd, CONST PAINTSTRUCT *ps );
244 HDC WINAPI _GetDC( HWND hwnd );
245 int WINAPI _ReleaseDC( HWND hwnd, HDC hdc );
246 BOOL  WINAPI _ExtTextOutA(HDC hdc, int x, int y, UINT option, CONST RECT *rc, LPCSTR str, UINT count, CONST INT *dx );
247 BOOL  WINAPI _ExtTextOutW(HDC hdc, int x, int y, UINT option, CONST RECT *rc, LPCWSTR str, UINT count, CONST INT *dx );
248 BOOL WINAPI _BitBlt(HDC hdcdest, int xdest, int ydest, int width, int height, HDC hdcsrc, int xsrc, int ysrc, DWORD rop );
249
250 LONG WINAPI _TabbedTextOutA( HDC hdc, int x, int y, LPCSTR str, int count, int ntabs, LPINT tabs, int origin );
251 LONG WINAPI _TabbedTextOutW( HDC hdc, int x, int y, LPCWSTR str, int count, int ntabs, LPINT tabs, int origin );
252 BOOL WINAPI _TextOutA( HDC hdc, int x, int y, LPCSTR str, int count );
253 BOOL WINAPI _TextOutW( HDC hdc, int x, int y, LPCWSTR str, int count );
254 int WINAPI _DrawTextA( HDC hdc, LPCSTR str, int count, LPRECT rc, UINT format );
255 int WINAPI _DrawTextW( HDC hdc, LPCWSTR str, int count, LPRECT rc, UINT format );
256 int WINAPI _DrawTextExA( HDC hdc, LPCSTR str, int count, LPRECT rc, UINT format, LPDRAWTEXTPARAMS params );
257 int WINAPI _DrawTextExW( HDC hdc, LPCWSTR str, int count, LPRECT rc, UINT format, LPDRAWTEXTPARAMS params );
258
259 BOOL WINAPI _MoveToEx( HDC hdc, int x, int y, LPPOINT pt );
260
261 void ShareProtect( bool f );
262 DWORD SetWriteProtect( LPVOID addr, bool f );
263 bool ChangeMemory( void *dst, const void *src, unsigned size );
264 bool LoadVxD();
265 void UnloadVxD();
266
267 static HMODULE ModuleFromAddress(PVOID pv);
268
269 // Prototypes for PSAPI.DLL //
270 typedef BOOL (WINAPI *FNEnumProcessModules)( HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded );
271 typedef DWORD (WINAPI *FNGetModuleFileNameExA)( HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize );
272 typedef HANDLE (WINAPI *FNCreateToolhelp32Snapshot)( DWORD dwFlags, DWORD th32ProcessID );
273 typedef BOOL (WINAPI *FNModule32First)( HANDLE hSnapshot, LPMODULEENTRY32 lpme );
274 typedef BOOL (WINAPI *FNModule32Next)( HANDLE hSnapshot, LPMODULEENTRY32 lpme );
275
276
277 LRESULT CALLBACK MouseProc( int code, WPARAM wParam, LPARAM lParam );
278 LRESULT CALLBACK KeyboardProc( int code, WPARAM wParam, LPARAM lParam );
279 bool CaptureText( HWND hwnd, bool movesend );
280 bool DoCapture(HWND hwnd, POINT pt, bool movesend, bool image_only=false, bool runOnLaunchedProc=false, bool nonBlock=false);
281 void DokoPopMenu( HWND hwnd );
282 void ToggleClick( HWND hwnd );
283 int CALLBACK EnumMetaFileProc( HDC hdc, HANDLETABLE *, CONST ENHMETARECORD *mfr, int nobj, LPARAM user );
284
285 //__declspec(dllexport)
286 BOOL  WINAPI _ExtTextOutA(HDC hdc, int x, int y, UINT option, CONST RECT *rc, LPCSTR str, UINT count, CONST INT *dx );
287
288 #if METAEXTTEXTOUT
289 void ExtTextOutHit();
290 #endif
291
292 void DoScale(HDC hdc, POINT *pts, int num);
293
294 // Prototypes for High DPI //
295 typedef enum _PROCESS_DPI_AWARENESS { 
296   Process_DPI_Unaware            = 0,
297   Process_System_DPI_Aware       = 1,
298   Process_Per_Monitor_DPI_Aware  = 2
299 } PROCESS_DPI_AWARENESS;
300
301 typedef HRESULT (WINAPI *FNGetProcessDPIAwareness)(HANDLE hprocess, PROCESS_DPI_AWARENESS *value);
302 typedef HRESULT (WINAPI *FNSetProcessDPIAwareness)(PROCESS_DPI_AWARENESS value);
303
304 //==============================================//
305 // Shared Section                                                               //
306 //==============================================//
307 #pragma data_seg(".sdata")
308 #pragma bss_seg( ".sbss" )
309 HWND hwndCallback = NULL;
310 #if USE_VXD
311 char VxDpathName[256];  // HK95.vxd path
312 #endif
313 DWORD siPageSize = 0;
314 HWND hwndOrg = NULL;
315 HWND hwndAMODI = NULL;
316 bool RequireHwndAMODI = false;
317 bool OnlyAMODI = false;
318 bool tryAMODI = false;
319 bool MoveSend = false;
320 #if USE_DBW
321 int attach = 0;
322 #endif
323 #if USE_VXD
324 bool WindowsNT;
325 #else
326 const bool WindowsNT = true;
327 #endif
328 bool Initialized = false;       // Whether this module initialized or not
329 DWORD idDokopopProcess;         // DKPP.EXE process ID
330 HHOOK hMouseHook;       // Windows Hook Handle for mouse
331 bool ClickOnlyEnabled = false;
332
333 struct TKeyConfig {
334         unsigned char Action;
335         int Flag;
336 };
337
338 TKeyConfig KeyConfig[MAX_KEYS] = {
339         { KA_POPUP, KF_CONTROL },                       // Ctrl+click
340         { KA_POPUP_NC, KF_CLICKONLY },                  // click\82¾\82¯\82Åpopup(DO NOT CHANGE)
341 //      { KA_MENU, KF_CONTROL | KF_MENU },      // dokopop menu
342 //      { KA_MENU, KF_CONTROL | KF_MENU | KF_CLICKONLY },       // dokopop menu
343         { KA_TOGGLE, KF_CONTROL | KF_MENU },    // dokopop menu
344         { 0, 0 }
345 };
346
347 bool fWow64 = false;
348
349 POINT CursorPoint;      // Client area coordinate //
350 POINT ScreenPoint;      // Screen coordinate //
351 POINT PrevCursorPoint;
352 HWND hwndLast = NULL;
353 DWORD PrevMoveTime = 0;
354 bool MoveSent = true;
355 bool OnlyImage = false;
356
357 bool MouseMoving;
358
359 RECT rcClient;
360 RECT rcInvalid;
361 RECT rcOrgInvalid;      // \8dÄ\95`\89æ\91O\82Éinvalid\82¾\82Á\82½\97Ì\88æ
362 bool HitFound;
363 bool RButtonUpCancel = false;   // \8e\9f\82ÌRButtonUp\82Í\94j\8aü\82·\82é
364 bool LButtonUpCancel = false;   // \8e\9f\82ÌLButtonUp\82Í\94j\8aü\82·\82é
365 bool MButtonUpCancel = false;   // \8e\9f\82ÌMButtonUp\82Í\94j\8aü\82·\82é
366 bool LButtonDown = false;
367 bool MButtonDown = false;
368
369 HINSTANCE hPSAPI;               // handle of PSAPI.DLL(NT only)
370 FNEnumProcessModules fnEnumProcessModules;
371 FNGetModuleFileNameExA fnGetModuleFileNameExA;
372 FNCreateToolhelp32Snapshot fnCreateToolhelp32Snapshot;
373 FNModule32First fnModule32First;
374 FNModule32Next fnModule32Next;
375
376 #if USE_META || RETRYMETA
377 HDC OrgHDC;
378 HDC hdcMeta;
379 #endif
380 HDC hdcExtTextOut;
381 #if HOOK_GETDC
382 HDC OrgGetDC;
383 #endif
384
385 int BitBltCount;                // \8c»\8dÝ\82ÌBitBlt\89ñ\90\94
386 int ExtTextOutCount;    // \8c»\8dÝ\82ÌBand\93à\82ÌExtTextOut\89ñ\90\94(A/W\82Æ\82à)
387 int TargetBitBltCount;  // \8c\9f\8d¸\91Î\8fÛ\82ÌBitBlt(\8f\89\89ñ\95`\89æ\8cã\82É\94»\92è) 
388 POINT TargetOffset;             // \8c\9f\8d¸\91Î\8fÛ\82ÌBitBlt\82Ì\95`\89æ\83I\83t\83Z\83b\83g(\8f\89\89ñ\95`\89æ\8cã\82É\94»\92è)
389 bool RetryPhase;
390
391 #if METAEXTTEXTOUT
392 // hit text information
393 TString<char> *FoundTextA;
394 TString<wchar_t> *FoundTextW;
395 int FoundLocA;
396 int FoundLocW;
397
398 // \8dÅ\8cã\82É\95`\89æ\82µ\82½\83e\83L\83X\83g\82Ì\8fî\95ñ
399 // for text merge
400 int LastX;      // \8dÅ\8cã\82É\95`\89æ\82µ\82½\83e\83L\83X\83g\82Ì\89E\8fã\8dÀ\95W
401 int LastY;
402 TString<char> *LastTextA;
403 TString<wchar_t> *LastTextW;
404 #endif  // METAEXTTEXTOUT
405
406 bool MoveSendMode;
407
408 TCHAR AMODIPath[256];
409 bool ExtAMODI = false;
410 int ScaleX = 0; // 96\82ð1\82Æ\82µ\82½\89æ\96Ê\82Ì\8ag\91å\97¦
411 int ScaleY = 0;
412 int generation = 0;
413 int NumPrevWords = 1;   // \89½\8cÂ\82Ü\82Å\91O\82Ì\92P\8cê\82ð\8fE\82¤\82©\81H
414
415 TCHAR ImageTextPath[256+40];    // OCR\97pimage filename or text filename
416 DWORD SaveImageTime;
417 bool CaptureImageBlocking = false;
418
419 const char STR_USER32[] = "user32.dll";
420 const char STR_GDI32[] = "gdi32.dll";
421 const char STR_KERNEL32[] = "kernel32.dll";
422 const TCHAR STR_PSAPI[] = _T("psapi.dll");
423
424 // KERNEL32.DLL //
425 const char STR_CreateToolhelp32Snapshot[] = "CreateToolhelp32Snapshot";
426 const char STR_Module32First[] = "Module32First";
427 const char STR_Module32Next[] = "Module32Next";
428
429 // PSAPI.DLL //
430 const char STR_EnumProcessModules[] = "EnumProcessModules";
431 const char STR_GetModuleFileNameExA[] = "GetModuleFileNameExA";
432
433 const char STR_BeginPaint[] = "BeginPaint";
434 const char STR_EndPaint[] = "EndPaint";
435 const char STR_BitBlt[] = "BitBlt";
436 const char STR_GetDC[] = "GetDC";
437 const char STR_ReleaseDC[] = "ReleaseDC";
438
439 const char STR_ExtTextOutA[] = "ExtTextOutA";
440 const char STR_ExtTextOutW[] = "ExtTextOutW";
441 const char STR_TabbedTextOutA[] = "TabbedTextOutA";
442 const char STR_TabbedTextOutW[] = "TabbedTextOutW";
443 const char STR_TextOutA[] = "TextOutA";
444 const char STR_TextOutW[] = "TextOutW";
445 const char STR_DrawTextA[] = "DrawTextA";
446 const char STR_DrawTextW[] = "DrawTextW";
447 const char STR_DrawTextExA[] = "DrawTextExA";
448 const char STR_DrawTextExW[] = "DrawTextExW";
449
450 #if USE_SHARE0
451 #pragma data_seg()
452 #pragma bss_seg()
453 #endif
454
455 //==============================================//
456 // Module depend values                                                 //
457 //==============================================//
458 HINSTANCE hInstance;    // attached instance
459 DWORD idProcess;                // attached process
460 HANDLE hProcess;        // Hook\8e\9eGetCurrentProcess()\82Í\8eg\82¦\82È\82¢
461                                         // Hook\8e\9e\82Ìcurrent process\82ª\8f\91\82«\8a·\82¦\82½\82¢thunk\82Ìprocess\82Æ\88ê\92v\82·\82é\82Æ\82Í\8cÀ\82ç\82È\82¢\82½\82ß
462                                         // \82»\82Ì\82½\82ß\81ADLL\82Ìattach\8e\9e\82ÉWriteProcessMemory()\97p\82Éprocess handle\82ð\8eæ\93¾\82·\82é
463 DWORD curProcess;       // hooking process
464 #if USE_VXD
465 HANDLE vxd_Handle = INVALID_HANDLE_VALUE;       // Not shared
466 #endif
467
468 #if !MOVESEND_POST
469 HANDLE SendMoveEvent = NULL;
470 DWORD SendMoveThreadId;
471 #endif
472
473 HINSTANCE hInstSHCore = NULL;
474 FNGetProcessDPIAwareness GetProcessDPIAwareness = NULL;
475
476 //==============================================//
477 // APIHOOK                                                                              //
478 //==============================================//
479 class APIHOOK {
480 public:
481         const char *ModName;
482         const char *FuncName;
483 protected:
484         bool ExcludeMe;
485         bool Hooked;
486 public:
487         PROC OrgFunc;   // not shared@NT
488 protected:
489         PROC HookFunc;  // not shared
490         // Process dedicated values //
491 public:
492         static void *MaxAppAddr;        // Maximum private memory address
493 protected:
494         static APIHOOK *LinkTop;        // top of APIHOOK link
495         APIHOOK *LinkNext;                      // next pointer of API HOOK link
496 public:
497         APIHOOK( const char *modname, const char *name, void *hookfunc, bool excme = true );
498         ~APIHOOK();
499         bool GetProcOrgFunc( HINSTANCE hInst );
500         bool GetProcOrgFunc();
501         bool HookAgain();
502         void Finish();
503 protected:
504         bool StoreCode( );
505         void RestoreCode( );
506 protected:
507         static void ReplaceIATEntryInAllMods( APIHOOK *obj, PROC pfnCurrent, PROC pfnNew );
508         static bool ReplaceIATEntryInOneMod( APIHOOK *obj, PROC pfnCurrent, PROC pfnNew, HMODULE hmodCaller);
509 };
510
511 const BYTE cPushOpCode = 0x68;   // The PUSH opcode on x86 platforms
512 APIHOOK* APIHOOK::LinkTop = NULL;
513 PVOID APIHOOK::MaxAppAddr = NULL;
514
515 APIHOOK::APIHOOK( const char *modname, const char *funcname, void *hookfunc, bool excme )
516 {
517 //      DBW("APIHOOK constructor:%08X %s %s",this, modname, funcname);
518         Hooked = false;
519         ModName = modname;
520         FuncName = funcname;
521         HookFunc = (PROC)hookfunc;
522         ExcludeMe = excme;
523         LinkNext  = LinkTop;
524         LinkTop = this;
525         if (!MaxAppAddr){
526                 // Functions with address above lpMaximumApplicationAddress require
527                 // special processing (Windows 98 only)
528                 SYSTEM_INFO si;
529                 GetSystemInfo(&si);
530                 MaxAppAddr = si.lpMaximumApplicationAddress;
531         }
532 }
533
534 APIHOOK::~APIHOOK()
535 {
536         Finish();
537         // Remove this object from the linked list
538         APIHOOK* p = LinkTop;
539         if (p == this) {     // Removing the head node
540                 LinkTop = p->LinkNext;
541         } else {
542                 // Walk list from head and fix pointers
543                 for (; p->LinkNext; p = p->LinkNext){
544                         if (p->LinkNext == this) {
545                                 // Make the node that points to us point to the our next node
546                                 p->LinkNext = p->LinkNext->LinkNext;
547                                 break;
548                         }
549                 }
550         }
551 }
552 bool APIHOOK::GetProcOrgFunc()
553 {
554         return GetProcOrgFunc( GetModuleHandleA( ModName ) );
555 }
556 bool APIHOOK::GetProcOrgFunc( HINSTANCE hInst )
557 {
558         if (Hooked) return true;
559
560         // Save information about this hooked function
561         OrgFunc = ::GetProcAddress( hInst, FuncName);
562         if (!OrgFunc){
563                 DBW("Function doesn't exist =%s:%s", ModName, FuncName);
564                 return false;
565         }
566
567         if (OrgFunc > MaxAppAddr) {
568 //              DBW("The address is in a shared DLL; the address needs fixing up");
569                 PBYTE pb = (PBYTE)OrgFunc;
570                 if (pb[0] == cPushOpCode){
571                         // Skip over the PUSH op code and grab the real address
572                         PVOID pv = * (PVOID*) &pb[1];
573                         OrgFunc = (PROC) pv;
574                 }
575         }
576
577         // Set assembler code for hooking at the org entry
578         if ( !StoreCode() ){
579                 DBW("Cannot write process memory");
580                 return false;
581         }
582
583         Hooked = true;
584         return true;
585 }
586 bool APIHOOK::StoreCode( )
587 {
588         DBW("StoreCode:%s %s", ModName, FuncName);
589         // Hook this function in all currently loaded modules
590         ReplaceIATEntryInAllMods( this, OrgFunc, HookFunc );
591         return true;
592 }
593 void APIHOOK::RestoreCode()
594 {
595         DBW("RestoreCode:%s %s", ModName, FuncName);
596         ReplaceIATEntryInAllMods( this, HookFunc, OrgFunc );
597 }
598 void APIHOOK::ReplaceIATEntryInAllMods( APIHOOK *obj, PROC pfnCurrent, PROC pfnNew )
599 {
600         HMODULE hmodThisMod = obj->ExcludeMe
601                 ? ModuleFromAddress(ReplaceIATEntryInAllMods) : NULL;
602
603         DWORD cbNeeded;
604         HMODULE hMods[1024];
605         unsigned i;
606         if (fnCreateToolhelp32Snapshot){
607                 // Toolhelp\82ª\8eg\97p\82Å\82«\82é\8fê\8d\87\82Í\8eg\97p\82·\82é
608                 // Get the list of modules in this process
609                 HANDLE hSnapshot = fnCreateToolhelp32Snapshot(TH32CS_SNAPMODULE, idProcess);
610
611                 MODULEENTRY32 me = { sizeof(me) };
612                 for (BOOL fOk = fnModule32First(hSnapshot,&me); fOk; fOk = fnModule32Next(hSnapshot,&me)){
613                         // NOTE: We don't hook functions in our own module
614                         if (me.hModule != hmodThisMod){
615         //                      DBW("Module : %s %s", me.szModule,FuncName);
616                                 // Hook this function in this module
617                                 ReplaceIATEntryInOneMod( obj, pfnCurrent, pfnNew, me.hModule);
618                         }
619                 }
620                 CloseHandle( hSnapshot );
621         } else {
622                 if( fnEnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
623                 {
624                         for ( i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ )
625                         {
626                                 if (hMods[i] != hmodThisMod){
627                                         char szModName[MAX_PATH];
628                                         // Get the full path to the module's file.
629                                         if ( fnGetModuleFileNameExA( hProcess, hMods[i], szModName,
630                                                                                 sizeof(szModName))){
631         //                                      DBW("Module : %s %s", szModName, FuncName );
632                                                 ReplaceIATEntryInOneMod( obj, pfnCurrent, pfnNew, hMods[i]);
633                                         }
634                                 }
635                         }
636                 }
637 #if USE_DBW
638                 else DBW("EnumProcessModules failed");
639 #endif
640         }
641 }
642
643 // This functions is almost taken from Jeffrey Richter's sample, thank you.
644 bool APIHOOK::ReplaceIATEntryInOneMod( APIHOOK *obj, PROC pfnCurrent, PROC pfnNew, HMODULE hmodCaller)
645 {
646         if (!hProcess) return false;
647
648         // Get the address of the module's import section
649         ULONG ulSize;
650         PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)
651                 ImageDirectoryEntryToData(hmodCaller, TRUE,
652                         IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize);
653
654         if (!pImportDesc){
655 //              DBW("No import section : %s", obj->ModName);
656                 return false;
657         }
658
659         // Find the import descriptor containing references to callee's functions
660         for (; pImportDesc->Name; pImportDesc++){
661                 PSTR pszModName = (PSTR) ((PBYTE) hmodCaller + pImportDesc->Name);
662                 if (lstrcmpiA(pszModName, obj->ModName) == 0) 
663                         break;   // Found
664         }
665
666         if (pImportDesc->Name == 0){
667 //              DBW("This module doesn't import any functions from this callee");
668                 return false;  // This module doesn't import any functions from this callee
669         }
670
671    // Get caller's import address table (IAT) for the callee's functions
672         PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA) 
673                 ((PBYTE) hmodCaller + pImportDesc->FirstThunk);
674
675         // Replace current function address with new function address
676         for (; pThunk->u1.Function; pThunk++){
677                 // Get the address of the function address
678                 PROC* ppfn = (PROC*) &pThunk->u1.Function;
679                 // Is this the function we're looking for?
680                 BOOL fFound = (*ppfn == pfnCurrent);
681                 if (!fFound && (*ppfn > MaxAppAddr)){
682                         // If this is not the function and the address is in a shared DLL, 
683                         // then maybe we're running under a debugger on Windows 98. In this 
684                         // case, this address points to an instruction that may have the 
685                         // correct address.
686                         PBYTE pbInFunc = (PBYTE) *ppfn;
687                         if (pbInFunc[0] == cPushOpCode){
688                                 // We see the PUSH instruction, the real function address follows
689                                 ppfn = (PROC*) &pbInFunc[1];
690
691                                 // Is this the function we're looking for?
692                                 fFound = (*ppfn == pfnCurrent);
693                         }
694                 }
695
696                 if (fFound){
697                         // The addresses match, change the import section address
698                         if (!WriteProcessMemory(hProcess, ppfn, &pfnNew, sizeof(pfnNew), NULL)){
699                                 if (SetWriteProtect( (LPVOID)ppfn, false )==~0){        // write protection release
700                                         DBW("SetWriteProtect failed: %08X %s %s", ppfn, obj->ModName, obj->FuncName);
701                                         return false;
702                                 }
703 #if USE_VXD
704                                 if (!WindowsNT && IsBadWritePtr(ppfn,sizeof(pfnNew))){
705                                         // Windows9x shared DLL section
706                                         // change memory attribte using VxD
707                                         if (!ChangeMemory( ppfn, &pfnNew, sizeof(pfnNew) )){
708                                                 DBW("ChangeMemory failed");
709                                         }
710                                 } else
711 #endif
712                                 {
713                                         if (!WriteProcessMemory(hProcess, ppfn, &pfnNew, sizeof(pfnNew), NULL)){
714                                                 //SetWriteProtect( ppfn, true );        // restore protection
715                                                 DBW("%08X %08X %08X %08X %s %s", hProcess, ppfn, &pfnNew, sizeof(pfnNew), obj->ModName, obj->FuncName );
716                                                 DBW("WriteProcessMemory failed : %d",GetLastError());
717                                                 return false;
718                                         }
719                                 }
720                         }
721                         return true;  // We did it, get out
722                 }
723         }
724
725         //DBW("Not found");
726
727         // If we get to here, the function is not in the caller's import section
728         return false;
729 }
730 bool APIHOOK::HookAgain()
731 {
732         if ( Hooked ) return true;
733
734         // Set assembler code for hooking at the org entry
735         if ( !StoreCode() ){
736                 DBW("Cannot write process memory@rehook");
737                 return false;
738         }
739
740         Hooked = true;
741         return true;
742 }
743 void APIHOOK::Finish()
744 {
745         if ( !Hooked ) return;
746         RestoreCode();
747         Hooked = false;
748 }
749 // Returns the HMODULE that contains the specified memory address
750 static HMODULE ModuleFromAddress(PVOID pv)
751 {
752         MEMORY_BASIC_INFORMATION mbi;
753         return((VirtualQuery(pv, &mbi, sizeof(mbi)) != 0) 
754                 ? (HMODULE) mbi.AllocationBase : NULL);
755 }
756
757 #if HOOK_PAINT || RETRYMETA
758 APIHOOK BeginPaintHook( STR_USER32, STR_BeginPaint, _BeginPaint );
759 APIHOOK EndPaintHook( STR_USER32, STR_EndPaint, _EndPaint );
760 #endif
761
762 #if HOOK_BITBLT
763 APIHOOK BitBltHook( STR_GDI32, STR_BitBlt, _BitBlt );
764 #endif
765
766 #if HOOK_GETDC
767 APIHOOK GetDCHook( STR_USER32, STR_GetDC, _GetDC );
768 APIHOOK ReleaseDCHook( STR_USER32, STR_ReleaseDC, _ReleaseDC );
769 #endif
770
771 #if METAEXTTEXTOUT
772 APIHOOK ExtTextOutAHook( STR_GDI32, STR_ExtTextOutA, _ExtTextOutA );
773 APIHOOK ExtTextOutWHook( STR_GDI32, STR_ExtTextOutW, _ExtTextOutW );
774 #if HOOK_TEXT
775 APIHOOK TabbedTextOutAHook( STR_USER32, STR_TabbedTextOutA, _TabbedTextOutA );
776 APIHOOK TabbedTextOutWHook( STR_USER32, STR_TabbedTextOutW, _TabbedTextOutW );
777 APIHOOK TextOutAHook( STR_GDI32, STR_TextOutA, _TextOutA );
778 APIHOOK TextOutWHook( STR_GDI32, STR_TextOutW, _TextOutW );
779 APIHOOK DrawTextAHook( STR_USER32, STR_DrawTextA, _DrawTextA );
780 APIHOOK DrawTextWHook( STR_USER32, STR_DrawTextW, _DrawTextW );
781 APIHOOK DrawTextExAHook( STR_USER32, STR_DrawTextExA, _DrawTextExA );
782 APIHOOK DrawTextExWHook( STR_USER32, STR_DrawTextExW, _DrawTextExW );
783 #endif
784 #endif  // METAEXTTEXTOUT
785
786 __declspec(dllexport)
787 bool WINAPI Init( HWND _hwnd, const char * /*module_name*/, bool windowsnt, const char *vxd_path )
788 {
789         DBW("Init:%08X %d", _hwnd, windowsnt);
790         hwndCallback = _hwnd;
791         if ( Initialized ){
792                 return true;
793         }
794 #if USE_VXD
795         WindowsNT = windowsnt;
796         if (vxd_path){
797 //              DBW("vxd_path=%s",vxd_path);
798                 lstrcpy( VxDpathName, "\\\\.\\" );
799                 lstrcat( VxDpathName, vxd_path );
800                 if (!LoadVxD()){
801                         DBW("Cannot open VxD:%s:%d", VxDpathName,GetLastError() );
802                         return false;
803                 }
804         }
805 #endif
806
807 //      HINSTANCE hDll = GetModuleHandle( module_name );
808         hMouseHook = SetWindowsHookEx( WH_MOUSE, (HOOKPROC)MouseProc, hInstance, NULL );
809         if (!hMouseHook){
810                 DBW("SetWindowsHookEx error: %d", GetLastError());
811                 return false;
812         }
813
814 //      hKeyHook = SetWindowsHookEx( WH_KEYBOARD, (HOOKPROC)KeyboardProc, hDll, NULL );
815
816         Initialized = true;
817
818 #if GUARD
819         PROTECT_SHARE();
820         DBW("%08X(%08X) Protected", (((INT_PTR)&ExtTextOutAHook) / siPageSize) * siPageSize,&ExtTextOutAHook);
821 #endif
822
823         idDokopopProcess = GetCurrentProcessId();
824
825         // get AMODI infomation.
826         if (!tryAMODI){
827                 tryAMODI = true;
828                 hwndAMODI = FindAMODI();
829 #if 0
830                 if (hwndAMODI){
831                         DWORD procId;
832                         if (GetWindowThreadProcessId(hwnd, &procId)){
833                                 HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, FALSE, procId);
834                                 if (hProc){
835                                         memset(AMODIPath, 0, sizeof(AMODIPath));
836                                         if (GetModuleFileNameEx(hProc, NULL, AMODIPath, sizeof(AMODIPath))>0){
837                                                 // OK
838                                         }
839                                         CloseHandle(hProc);
840                                 }
841                         }
842                 }
843 #endif
844         }
845
846         return true;
847 }
848
849 __declspec(dllexport)
850 void WINAPI Uninit()
851 {
852         UNPROTECT_SHARE();
853         if ( !Initialized ) return;
854
855         DBW("Uninit");
856         UnhookWindowsHookEx( hMouseHook );
857
858 //      UnhookWindowsHookEx( hKeyHook );
859
860 #if USE_VXD
861         UnloadVxD();
862 #endif
863
864         Initialized = false;
865 }
866 __declspec(dllexport)
867 int WINAPI Config( int clickonly, int keyaction, int keyflag )
868 {
869         DBW("Config:%d %d %d", clickonly, keyaction, keyflag);
870         if (clickonly!=-1)
871                 ClickOnlyEnabled = int_bool(clickonly);
872         if ( keyflag != 0 ){
873                 for ( int i=0;KeyConfig[i].Action;i++ ){
874                         if (KeyConfig[i].Action == keyaction){
875                                 KeyConfig[i].Flag = keyflag;
876                                 break;
877                         }
878                 }
879         }
880         return 0;
881 }
882 __declspec(dllexport)
883 int WINAPI Config2( const struct TDCHConfig *cfg )
884 {
885         DBW("Config2: %d %d %d %d %d", (int)cfg->ScaleX, (int)cfg->ScaleY, (int)cfg->UseAMODI, (int)ExtAMODI, cfg->UseNumPrev ? cfg->NumPrevWords : 1);
886
887         MoveSend = cfg->MoveSend ? true : false;
888         MoveSent = false;
889         OnlyImage = cfg->OnlyImage;
890         ScaleX = cfg->ScaleX;
891         ScaleY = cfg->ScaleY;
892         NumPrevWords = cfg->UseNumPrev ? cfg->NumPrevWords : 1;
893
894         RequireHwndAMODI = false;
895
896         if (cfg->UseAMODI){
897                 if (!ExtAMODI){
898                         RequireHwndAMODI = true;
899                         if (!hwndAMODI)
900                                 hwndAMODI = FindAMODI();
901                 }
902         } else {
903                 hwndAMODI = NULL;
904                 ExtAMODI = false;
905                 return 0;
906         }
907
908         OnlyAMODI = int_bool(cfg->OnlyAMODI);
909         AMODIPath[0] = '\0';
910         ExtAMODI = false;
911         if (cfg->AMODIPath[0]){
912                 size_t len = strlen(cfg->AMODIPath);
913                 if (len<sizeof(AMODIPath)-2){
914                         memcpy(AMODIPath, cfg->AMODIPath, len);
915                         if (AMODIPath[len-1]!='\\'){
916                                 AMODIPath[len] = '\\';
917                                 len++;
918                         }
919                         AMODIPath[len] = '\0';
920                         ExtAMODI = true;
921                 }
922         }
923         dbw("Config2[%d]: %d %d %s", ++generation, cfg->ScaleX, cfg->ScaleY, AMODIPath);
924         return 0;
925 }
926 //Note:
927 //      non_block = true\82Ì\8fê\8d\87
928 //              \81Ewait\8fó\91Ô\82É\82 \82é\82©\82Ç\82¤\82©\82Í\81AWaitForCaptureResult( false, 0 ) < 0 \82Å\82í\82©\82é\81B
929 //              \81E\95K\82¸\8dÅ\8cã\82É\82ÍWaitForCaptureResult(1,...)\82ð\8cÄ\82Ñ\8fo\82·\82±\82Æ\81B
930 __declspec(dllexport)
931 int WINAPI Capture( HWND hwnd, POINT *ppt, bool movesend, bool non_block )
932 {
933         DBW("Capture:%08X %d,%d %d %d", hwnd, ppt ? ppt->x : 0, ppt ? ppt->y : 0, movesend, non_block);
934         if (!hwnd)
935                 hwnd = hwndLast;
936         POINT pt;
937         if (ppt)
938                 pt = *ppt;
939         else
940                 pt = PrevCursorPoint;
941         const bool image_only = true;
942         const bool runOnLaunchedProc = false;
943         return int_bool(DoCapture(hwnd, pt, movesend, image_only, runOnLaunchedProc, non_block));
944 }
945 //Note:
946 // waittime\82ÍCapture()\8aJ\8en\82µ\82Ä\82©\82ç\82Ì\8co\89ß\8e\9e\8aÔ
947 // polling\82·\82é\8fê\8d\87\82Íwaittime\82ð\8f­\82µ\82¸\82Â\91\9d\82â\82·\95K\97v\82 \82è(\82»\82Ì\8fê\8d\87\82Ísend_text=0)
948 // CaptureImage\82ð\8ds\82Á\82½\8fê\8d\87\82Í\81A\81u\95K\82¸\81vWaitForCaptureResult( 1, ... )\82ð\8cÄ\82Ñ\8fo\82·\95K\97v\82ª\82 \82é\81B
949 // \82»\82¤\82µ\82È\82¢\82Æ\81ACaptureImageBlocking\82ª true \82É\82È\82Á\82½\82Ü\82Ü\81B
950 //
951 // return:
952 //      0 : wait\92\86\82Ì\82à\82Ì\82Í\82È\82µ
953 //      1 : OK(text ready)
954 //      -1: timeout
955 __declspec(dllexport)
956 int WINAPI WaitForCaptureResult( bool send_text, unsigned waittime )
957 {
958         DBW("WaitForCaptureResult: %d %d %d", send_text, waittime, CaptureImageBlocking);
959         if (!CaptureImageBlocking) return 0;
960
961         if (send_text){
962                 if (WaitAndGetResult(ImageTextPath, waittime)){
963                         return 1;
964                 }
965         } else {
966                 HANDLE hf = WaitForResult(ImageTextPath, waittime);
967                 if (hf){
968                         CloseHandle(hf);
969                         return 1;
970                 }
971         }
972         return -1;
973 }
974 #if GUARD
975 void ShareProtect( bool f )
976 {
977         LPVOID BaseAddress = (LPVOID)((((INT_PTR)&ExtTextOutAHook) / siPageSize) * siPageSize);
978
979         DWORD OldProtect;
980         if ( !VirtualProtect( BaseAddress, siPageSize, f ? PAGE_READONLY : PAGE_READWRITE, &OldProtect ) ){
981                 DBW("Cannot change protect:%08X@rehook",BaseAddress);
982         }
983 }
984 #endif
985 DWORD SetWriteProtect( LPVOID addr, bool f )
986 {
987         LPVOID BaseAddress = (LPVOID)((((INT_PTR)addr) / siPageSize) * siPageSize);
988
989         DWORD OldProtect;
990         if ( !VirtualProtect( BaseAddress, siPageSize, f ? PAGE_READONLY : PAGE_READWRITE, &OldProtect ) ){
991                 DBW("Cannot change protect:%08X-%08X@rehook %d", (INT_PTR)BaseAddress>>32, BaseAddress, GetLastError());
992                 return ~0;
993         }
994         return OldProtect;
995 }
996 #if USE_VXD
997 // change write protected memory for Windows9x
998 bool ChangeMemory( void *dst, const void *src, unsigned size )
999 {
1000         DWORD DIOC_count;
1001         if ( vxd_Handle == INVALID_HANDLE_VALUE ){
1002                 if (!LoadVxD())
1003                         return false;
1004         }
1005
1006         bool r = int_bool(DeviceIoControl( vxd_Handle, DIOC_CHANGE_MEMORY, (void*)src, size, dst, 0, &DIOC_count, NULL));
1007 #if USE_DBW
1008         if ( !r ){
1009                 DBW("DeviceIoControl failed");
1010         }
1011 #endif
1012         return r;
1013 }
1014 bool LoadVxD()
1015 {
1016         if (vxd_Handle!=INVALID_HANDLE_VALUE){
1017                 DBW("Already loaded VxD");
1018                 return true;
1019         }
1020         vxd_Handle=CreateFile(&VxDpathName[0],0,0,NULL,0,FILE_FLAG_DELETE_ON_CLOSE,NULL);
1021         return vxd_Handle != INVALID_HANDLE_VALUE;
1022 }
1023 void UnloadVxD()
1024 {
1025         if (vxd_Handle == INVALID_HANDLE_VALUE)
1026                 return;
1027         CloseHandle(vxd_Handle);
1028         vxd_Handle = INVALID_HANDLE_VALUE;
1029 }
1030 #endif
1031 int GetKeyFlag( )
1032 {
1033         int r = 0;
1034         if ( GetKeyState( VK_SHIFT ) & 0x8000 ) r |= KF_SHIFT;
1035         if ( GetKeyState( VK_CONTROL ) & 0x8000 ) r |= KF_CONTROL;
1036         if ( GetKeyState( VK_MENU ) & 0x8000 ) r |= KF_MENU;
1037         if ( GetKeyState( VK_LWIN ) & 0x8000 ) r |= KF_LWIN;
1038         if ( GetKeyState( VK_RWIN ) & 0x8000 ) r |= KF_RWIN;
1039         if ( ClickOnlyEnabled && r == 0 ) r = KF_CLICKONLY;
1040 //      if ( GetKeyState( VK_APPS ) & 0x8000 ) r |= KF_APPS;
1041         return r;
1042 }
1043 LRESULT CALLBACK MouseProc( int code, WPARAM wParam, LPARAM lParam )
1044 {
1045         if ( code < 0 || code != HC_ACTION )
1046                 return CallNextHookEx( hMouseHook, code, wParam, lParam );
1047
1048         MOUSEHOOKSTRUCT *mhs;
1049         HWND hwnd;
1050         int kf;
1051         int i;
1052
1053 #if 0
1054         if (wParam!=0x200 && wParam!=0xA0)
1055                 dbw("WParam:%08X", wParam);
1056 #endif
1057
1058         curProcess = GetCurrentProcessId();
1059         bool runOnLaunchedProc = false;
1060
1061         switch ( wParam ){
1062                 case WM_LBUTTONDOWN:
1063                 // case WM_NCLBUTTONDOWN:
1064                         LButtonDown = true;
1065                         LButtonUpCancel = false;
1066 //                      if (LButtonUpCancel)
1067 //                              goto j_end;
1068                         kf = KF_LEFTCLICK;
1069                         goto j_rbuttondown;
1070                 case WM_MBUTTONDOWN:
1071                 // case WM_NCMBUTTONDOWN:
1072                         MButtonDown = true;
1073                         MButtonUpCancel = false;
1074 //                      if (MButtonUpCancel)
1075 //                              goto j_end;
1076                         kf = KF_MIDCLICK;
1077                         goto j_rbuttondown;
1078                 case WM_RBUTTONDOWN:
1079                 //  case WM_NCRBUTTONDOWN:
1080                         DBW("RButtonDown");
1081                         RButtonUpCancel = false;
1082 //                      if (RButtonUpCancel)
1083 //                              goto j_end;
1084                         kf = 0;
1085                         if (LButtonDown){
1086                                 kf = KF_LRCLICK;
1087                         }
1088         j_rbuttondown:;
1089                         mhs = (MOUSEHOOKSTRUCT*)lParam;
1090                         hwnd = WindowFromPoint( mhs->pt );
1091                         //hwnd = mhs->hwnd;
1092 #if 0
1093                         HWND h = GetParent( hwnd );
1094                         if ( h )
1095                                 hwnd = h;
1096 #endif
1097                         kf |= GetKeyFlag();
1098
1099 #if 0
1100                         dbw("kf=%02X", kf);
1101 #endif
1102
1103                         if (curProcess == idDokopopProcess){
1104                                 // runs on launched process -> ignored.
1105                                 DBW("Runs on launched proc(%d)", curProcess);
1106                                 runOnLaunchedProc = true;
1107                         }
1108
1109                         for ( i=0;KeyConfig[i].Action;i++ ){
1110                                 //DBW("%d:%d %x", i, KeyConfig[i].Action, KeyConfig[i].Flag);
1111                                 if ( kf == KeyConfig[i].Flag ){
1112                                         switch ( KeyConfig[i].Action ){
1113                                                 case KA_POPUP:
1114                                                 case KA_POPUP_NC:
1115                                                         {
1116                                                         const bool move_send = false;
1117                                                         if (DoCapture(hwnd, mhs->pt, move_send, OnlyImage, runOnLaunchedProc)){
1118 j_discard:
1119                                                                 if (wParam == WM_LBUTTONDOWN)
1120                                                                         LButtonUpCancel = true;
1121                                                                 if (wParam == WM_MBUTTONDOWN)
1122                                                                         MButtonUpCancel = true;
1123                                                                 else
1124                                                                         RButtonUpCancel = true;
1125                                                                 return 1;       // discard this message
1126                                                         }
1127                                                         }
1128                                                         break;
1129                                                 case KA_MENU:
1130                                                         DokoPopMenu( hwnd );
1131                                                         goto j_discard;
1132                                                 case KA_TOGGLE:
1133                                                         DBW("KA_TOGGLE");
1134                                                         ToggleClick( hwnd );
1135                                                         goto j_discard;
1136                                         }
1137                                 }
1138                         }
1139                         break;
1140                 case WM_RBUTTONUP:
1141                         DBW("WM_RBUTTONUP:%d",RButtonUpCancel);
1142                         if ( RButtonUpCancel ){
1143                                 RButtonUpCancel = false;
1144                                 return 1;       // no longer process the message
1145                         }
1146                         break;
1147                 case WM_LBUTTONUP:
1148                         LButtonDown = false;
1149                         if ( LButtonUpCancel ){
1150                                 LButtonUpCancel = false;
1151                                 return 1;       // no longer process the message
1152                         }
1153                         break;
1154                 case WM_MBUTTONUP:
1155                         MButtonDown = false;
1156                         if ( MButtonUpCancel ){
1157                                 MButtonUpCancel = false;
1158                                 return 1;       // no longer process the message
1159                         }
1160                         break;
1161                 case WM_MOUSEMOVE:
1162                         if (MoveSend){
1163                                 mhs = (MOUSEHOOKSTRUCT*)lParam;
1164                                 hwnd = WindowFromPoint( mhs->pt );
1165                                 if (PrevCursorPoint.x!=mhs->pt.x || PrevCursorPoint.y!=mhs->pt.y){
1166                                         PrevMoveTime = GetTickCount();
1167                                         MoveSent = false;
1168                                         PrevCursorPoint = mhs->pt;
1169                                         hwndLast = hwnd;
1170                                         //DBW("Moving:%d %d", mhs->pt.x, mhs->pt.y);
1171                                         SendMoveMessage();
1172 #if 0
1173                                         //TODO: 5pixel\96¢\96\9e\82Å\82 \82ê\82ÎDoCapture\82·\82é
1174 #endif
1175                                 } else {
1176                                         if (!MoveSent){
1177 #if 0   // 2014.11.18 inc.srch\82Å\97\8e\82¿\82é\82Ì\82Å\82Æ\82è\82 \82¦\82¸comment out
1178                                                 const int MOVE_SEND_INTERVAL = 50;      // msec
1179                                                 if (GetTickCount()-PrevMoveTime > MOVE_SEND_INTERVAL){
1180                                                         MoveSent = true;
1181                                                         if (DoCapture(hwndLast, PrevCursorPoint, true)){
1182                                                                 // stop the capture from the main.
1183                                                                 SendCancelMove();
1184                                                         }
1185                                                 }
1186 #endif
1187                                         }
1188                                 }
1189                         }
1190                         break;
1191         }
1192
1193 //j_end:;
1194         return CallNextHookEx( hMouseHook, code, wParam, lParam );
1195 }
1196
1197 bool DoCapture(HWND hwnd, POINT pt, bool movesend, bool image_only, bool runOnLaunchedProc, bool non_block)
1198 {
1199         DBW("DoCapture: %d %d %d %d %d", image_only, runOnLaunchedProc, hwndAMODI, ExtAMODI, OnlyAMODI);
1200         CursorPoint = ScreenPoint = pt;
1201         ScreenToClient( hwnd, &CursorPoint );
1202
1203 #if 1   // acrobat reader\8fã\82Åclick\82·\82é\82ÆhwndAMODI\82ªnull\82É\82È\82Á\82Ä\82µ\82Ü\82¤\8fê\8d\87\82ª\82 \82é\82½\82ß\81i\8c´\88ö\95s\96¾\81j
1204                 // \81Ereader\8fã\82Å\82Ímouse event\82ª\83s\83^\83b\82Æ\8e~\82Ü\82é
1205                 // \81Ereader\8fã\82Åclick\82µ\82½\82¾\82¯\82Å\82Ínull\82É\82È\82ç\82È\82¢
1206                 // \81Ereader\8fã\82Åctrl+click\82·\82é\82Æ\81Areader\8fã\82©\82çmouse\82ð\8aO\82·\82Ænull\82É\82È\82Á\82Ä\82¢\82é
1207                 // \81Ereader\8fã\82Åshift+click, alt+click, ctrl+click\82Å\82Ínull\82É\82È\82ç\82È\82¢
1208                 // \81E\90Ý\92è\82ðAlt+click\82É\95Ï\8dX\82·\82é\82Æ\81AAlt+click\82Ånull\82É\82È\82è\81ACtrl+click\82Å\82Ínull\82É\82È\82ç\82È\82¢
1209                 // \82Ü\82é\82ÅDokoPop!\91Î\8dô\82ð\82µ\82Ä\82¢\82é\82©\82Ì\82æ\82¤\82¾\81B\82¢\82¸\82ê\82É\82¹\82æ\81Amouse event\82ª\82Ü\82Á\82½\82­\97\88\82È\82¢\81A
1210                 // \82¨\82»\82ç\82­reader\82Ì\82Ù\82¤\82Åmouse hook\82ð\8cÄ\82Î\82È\82¢\82æ\82¤\82É\82µ\82Ä\82¢\82é\82Ì\82¾\82ë\82¤\81A
1211                 // \82È\82Ì\82Å\81Anull\8c´\88ö\82ª\89¼\82É\82í\82©\82Á\82½\82Æ\82µ\82Ä\82à\81Areader\8fã\82Å\82Í\8c\9f\8dõ\82ª\82Å\82«\82È\82¢\82Í\82¸
1212         if (RequireHwndAMODI){
1213                 if (!hwndAMODI)
1214                         hwndAMODI = FindAMODI();
1215         }
1216 #endif
1217
1218         if (!image_only && !runOnLaunchedProc){
1219                 //DBW("hwnd:%08X %d %d", (int)hwnd, CursorPoint.x, CursorPoint.y);
1220                 if ((!hwndAMODI && !ExtAMODI) || !OnlyAMODI){
1221                         // Redraw Metafile //
1222                         UNPROTECT_SHARE();
1223                         DBW("Target : %08X %d", hwnd, curProcess);
1224                         bool r = CaptureText( hwnd, movesend );
1225                         PROTECT_SHARE();
1226                         if (r){
1227                                 return true;    // discard this message
1228                         }
1229                 }
1230         }
1231         if (image_only || hwndAMODI || ExtAMODI){
1232                 if (CaptureImage(hwnd, movesend, non_block))
1233                         return true;
1234         }
1235         return false;
1236 }
1237
1238 void CallbackMain(int msg, const void *data, int len, HWND wparam=0)
1239 {
1240         COPYDATASTRUCT cds;
1241         cds.dwData = msg;
1242         cds.cbData = len;
1243         cds.lpData = (LPSTR)data;
1244         SendMessage( hwndCallback, WM_COPYDATA, (WPARAM)wparam, (LPARAM)&cds );
1245 }
1246
1247 void DokoPopMenu( HWND hwnd )
1248 {
1249         CallbackMain(DCH_MENU, NULL, 0, hwnd);
1250 }
1251 void ToggleClick( HWND hwnd )
1252 {
1253         CallbackMain(DCH_TOGGLE, NULL, 0, hwnd);
1254 }
1255 #if 0
1256 LRESULT CALLBACK KeyboardProc( int code, WPARAM wParam, LPARAM lParam )
1257 {
1258         if ( code < 0 || code != HC_ACTION )
1259                 return CallNextHookEx( hKeyHook, code, wParam, lParam );
1260
1261         if ( wParam == VK_CONTROL ){
1262                 if ( lParam & (KF_UP<<16) ){
1263                         // control key up
1264                         // -> hold on time
1265                         goto j1;
1266                 } else
1267                 if ( !(lParam & (KF_REPEAT<<16)) ){
1268                         // control key down and not repeat
1269 //                      DBW("wparam=%08X lparam=%08X",wParam,lParam);
1270                         long nowt = GetTickCount();
1271                         if ( nowt - LastTypeTime < GetDoubleClickTime() ){
1272 //                              DBW("On/off!");
1273                                 ClickOnlyEnabled = !ClickOnlyEnabled;
1274                                 MessageBeep( MB_OK );
1275                                 // -> cancel time
1276                         } else {
1277                                 // -> hold on time
1278                                 LastTypeTime = nowt;
1279                                 goto j1;
1280                         }
1281                 } else {
1282                         // control key down and repeat
1283                         // -> cancel time
1284                 }
1285         }
1286         LastTypeTime -= 10000;
1287 j1:;
1288         return CallNextHookEx( hMouseHook, code, wParam, lParam );
1289 }
1290 #endif
1291
1292 //__declspec(dllexport)
1293 #if HOOK_PAINT || RETRYMETA
1294 HDC WINAPI _BeginPaint( HWND hwnd, LPPAINTSTRUCT ps )
1295 {
1296 //      DBW("BeginPaint");
1297         HDC hdc = ((FNBeginPaint)BeginPaintHook.OrgFunc)( hwnd, ps );
1298         OrgHDC = hdc;
1299         ps->hdc = hdcMeta;
1300 #if 1
1301         ps->rcPaint.left = 0;
1302         ps->rcPaint.top = 0;
1303         ps->rcPaint.right = rcInvalid.right;
1304         ps->rcPaint.bottom = rcInvalid.bottom;
1305 #endif
1306         return hdcMeta;
1307 }
1308 //__declspec(dllexport)
1309 BOOL WINAPI _EndPaint( HWND hwnd, CONST PAINTSTRUCT *ps )
1310 {
1311         ((PAINTSTRUCT*)ps)->hdc = OrgHDC;
1312         return ((FNEndPaint)EndPaintHook.OrgFunc)( hwnd, ps );
1313 }
1314 #endif
1315 #if HOOK_GETDC
1316 HDC WINAPI _GetDC( HWND hwnd )
1317 {
1318         DBW("GetDC");
1319         HDC hdc = ((FNGetDC)GetDCHook.OrgFunc)( hwnd );
1320         OrgHDC = hdc;
1321         if ( hwnd == hwndOrg ){
1322                 return hdcMeta;
1323         } else {
1324                 return OrgHDC;
1325         }
1326 }
1327 int WINAPI _ReleaseDC( HWND hwnd, HDC hdc )
1328 {
1329         DBW("ReleaseDC");
1330         if ( hdc == hdcMeta ){
1331                 hdc = OrgHDC;
1332         }
1333         int r = ((FNReleaseDC)ReleaseDCHook.OrgFunc)( hwnd, hdc );
1334         return r;
1335 }
1336 #endif
1337
1338 #if METAEXTTEXTOUT
1339 //__declspec(dllexport)
1340 BOOL  WINAPI _ExtTextOutA(HDC hdc, int x, int y, UINT option, CONST RECT *rc, LPCSTR str, UINT count, CONST INT *dx )
1341 {
1342         DBW("_ExtTextOutA");
1343         POINT pt;
1344         GetCurrentPositionEx(hdc,&pt);
1345
1346         BOOL r = ((FNExtTextOutA)ExtTextOutAHook.OrgFunc)( hdc, x, y, option, rc, str, count, dx );
1347
1348         hdcExtTextOut = hdc;
1349
1350         if ( r
1351 #if USE_META
1352                 && hdcMeta != hdc
1353 #endif
1354                 && count > 0 ){
1355                 RECT _rc;
1356                 if ( rc ){
1357                         _rc.right = rc->right;
1358                         _rc.bottom = rc->bottom;
1359                 } else {
1360                         _rc.right = rcClient.right;
1361                         _rc.bottom = rcClient.bottom;
1362                 }
1363                 if ( GetTextAlign( hdc ) & TA_UPDATECP ){
1364                         _rc.left = pt.x;
1365                         _rc.top = pt.y;
1366                 } else {
1367                         _rc.left = x;
1368                         _rc.top = y;
1369                 }
1370                 if ( RetryPhase ){
1371                         if ( TargetBitBltCount == BitBltCount ){
1372                                 _rc.right += CursorPoint.x;     //*+++ bug \82±\82¤\82µ\82È\82¢\82Æ\95\9d\82ª\82¹\82Ü\82­\82Ähit\82µ\82È\82¢
1373                                 OffsetRect( &_rc, TargetOffset.x, TargetOffset.y );
1374                         } else {
1375                                 return r;
1376                         }
1377                 } else {
1378                         ExtTextOutCount++;
1379                 }
1380 #if ORG_OFFSET  /* fixed 2001.1.14 for IE@win2k */
1381                 POINT vpt;
1382                 POINT wpt;
1383                 GetViewportOrgEx( hdc, &vpt );
1384                 GetWindowOrgEx( hdc, &wpt );
1385                 OffsetRect( &_rc, vpt.x-wpt.x, vpt.y-wpt.y);
1386 #else
1387 #if USE_DBW
1388                 POINT vpt;
1389                 POINT wpt;
1390                 GetViewportOrgEx( hdc, &vpt );
1391                 GetWindowOrgEx( hdc, &wpt );
1392                 if (vpt.x != wpt.x || vpt.y != wpt.y)
1393                         DBW("!!!Org DIFF=%d %d",vpt.x-wpt.x, vpt.y-wpt.y);
1394 #endif
1395 #endif
1396
1397                 // \98A\91±\82µ\82½\83e\83L\83X\83g\82Ì\8fê\8d\87\82Í
1398                 // \98A\8c\8b\82·\82é
1399                 if (LastY == _rc.top && LastX == _rc.left ){
1400                         // \98A\91±\82µ\82½\83e\83L\83X\83g\95`\89æ\81¨\98A\8c\8b
1401                         LastTextA->Cat( str, count );
1402                 } else {
1403                         LastTextA->Set( str, count );
1404                 }
1405                 LastX = _rc.left;
1406                 LastY = _rc.top;
1407
1408                 if ( PtInRect( &_rc, CursorPoint ) )
1409                 {
1410 #if DEBUG_HITTEXT
1411                         char *buf = new char[ count + 1 ];
1412                         CopyMemory( buf, str, count );
1413                         buf[count] = '\0';
1414                         DBW("CheckA -- %d %d %d %d (%d,%d)", _rc.left, _rc.top, _rc.right, _rc.bottom, CursorPoint.x, CursorPoint.y, count);
1415                         DBW("%s", buf);
1416                         delete[] buf;
1417 #endif
1418                         int loc = GetTextFromPoint( hdc, str, count, CursorPoint.x - _rc.left, CursorPoint.y - _rc.top, dx );
1419                         if ( loc != -1 ){
1420                                 FoundLocA = loc + LastTextA->GetLength() - count;
1421                                 FoundTextA->Set( LastTextA );
1422 #if DEBUG_HITTEXT
1423                                 DBW("HitA loc=%d Len=%d Text=%ws", FoundLocA, FoundTextA->GetLength(), FoundTextA->c_str());
1424 #endif
1425                         }
1426                 }
1427         }
1428
1429         return r;
1430 }
1431 //__declspec(dllexport)
1432 BOOL  WINAPI _ExtTextOutW(HDC hdc, int x, int y, UINT option, CONST RECT *rc, LPCWSTR str, UINT count, CONST INT *dx )
1433 {
1434 //      DBW("_ExtTextOutW");
1435         POINT pt;
1436         GetCurrentPositionEx(hdc,&pt);
1437
1438         BOOL r = ((FNExtTextOutW)ExtTextOutWHook.OrgFunc)( hdc, x, y, option, rc, str, count, dx );
1439
1440         hdcExtTextOut = hdc;
1441
1442         if ( r
1443 #if USE_META
1444                 && hdcMeta != hdc
1445 #endif
1446                 && count > 0 ){
1447                 RECT _rc;
1448                 if ( rc ){
1449                         _rc.right = rc->right;
1450                         _rc.bottom = rc->bottom;
1451                 } else {
1452                         _rc.right = rcClient.right;
1453                         _rc.bottom = rcClient.bottom;
1454                 }
1455                 if ( GetTextAlign( hdc ) & TA_UPDATECP ){
1456                         _rc.left = pt.x;
1457                         _rc.top = pt.y;
1458                 } else {
1459                         _rc.left = x;
1460                         _rc.top = y;
1461                 }
1462                 if ( RetryPhase ){
1463                         if ( TargetBitBltCount == BitBltCount ){
1464                                 _rc.right += CursorPoint.x;     //*+++ bug \82±\82¤\82µ\82È\82¢\82Æ\95\9d\82ª\82¹\82Ü\82­\82Ähit\82µ\82È\82¢
1465                                 OffsetRect( &_rc, TargetOffset.x, TargetOffset.y );
1466                         } else {
1467                                 return r;
1468                         }
1469                 } else {
1470                         ExtTextOutCount++;
1471                 }
1472 #if ORG_OFFSET  /* fixed 2001.1.14 for IE@win2k */
1473                 POINT vpt;
1474                 POINT wpt;
1475                 GetViewportOrgEx( hdc, &vpt );
1476                 GetWindowOrgEx( hdc, &wpt );
1477                 OffsetRect( &_rc, vpt.x-wpt.x, vpt.y-wpt.y);
1478 #else   // !ORG_OFFSET
1479 #if USE_DBW
1480                 POINT vpt;
1481                 POINT wpt;
1482                 GetViewportOrgEx( hdc, &vpt );
1483                 GetWindowOrgEx( hdc, &wpt );
1484                 if (vpt.x != wpt.x || vpt.y != wpt.y)
1485                         DBW("!!!Org DIFF=%d %d",vpt.x-wpt.x, vpt.y-wpt.y);
1486 #endif  // USE_DBW
1487 #endif  // !ORG_OFFSET
1488
1489                 // \98A\91±\82µ\82½\83e\83L\83X\83g\82Ì\8fê\8d\87\82Í\98A\8c\8b\82·\82é
1490                 if (LastY == _rc.top && LastX == _rc.left ){
1491                         // \98A\91±\82µ\82½\83e\83L\83X\83g\95`\89æ\81¨\98A\8c\8b
1492                         LastTextW->Cat( str, count );
1493                 } else {
1494                         LastTextW->Set( str, count );
1495                 }
1496                 LastX = _rc.left;
1497                 LastY = _rc.top;
1498
1499                 if ( PtInRect( &_rc, CursorPoint ) )
1500                 {
1501                         DBW("%04X %04X %04X %04X",
1502                                 str[0],
1503                                 str[1],
1504                                 str[2],
1505                                 str[3]);
1506 #if DEBUG_HITTEXT
1507                         wchar_t *buf = new wchar_t[ count + 1 ];
1508                         CopyMemory( buf, str, count*sizeof(wchar_t) );
1509                         buf[count] = '\0';
1510                         DBW("CheckW -- %d %d %d %d (%d,%d)", _rc.left, _rc.top, _rc.right, _rc.bottom, CursorPoint.x, CursorPoint.y, count);
1511                         DBW("%ws", buf);
1512                         delete[] buf;
1513 #endif
1514                         int loc = GetTextFromPoint( hdc, str, count, CursorPoint.x - _rc.left, CursorPoint.y - _rc.top, dx );
1515                         if ( loc != -1 ){
1516                                 FoundLocW = loc + LastTextW->GetLength() - count;
1517                                 FoundTextW->Set( LastTextW );
1518 #if DEBUG_HITTEXT
1519                                 DBW("HitW loc=%d Len=%d Text=%ws", FoundLocW, FoundTextW->GetLength(), FoundTextW->c_str());
1520 #endif
1521                         }
1522                 }
1523         }
1524
1525         return r;
1526 }
1527 #endif  // !METAEXTTEXTOUT
1528
1529 #if HOOK_BITBLT
1530 BOOL WINAPI _BitBlt(HDC hdcdest, int xdest, int ydest, int width, int height, HDC hdcsrc, int xsrc, int ysrc, DWORD rop )
1531 {
1532         DBW("BitBlt:%08X %d %d %d %d <- %08X %d %d", hdcdest, xdest, ydest, width, height, hdcsrc, xsrc, ysrc );
1533         BOOL r = ((FNBitBlt)BitBltHook.OrgFunc)(hdcdest, xdest, ydest, width, height, hdcsrc, xsrc, ysrc, rop );
1534 //      DBW("BitBlt:%08X %d %d %d %d <- %08X %d %d", hdcdest, xdest, ydest, width, height, hdcsrc, xsrc, ysrc );
1535         if ( r && hdcExtTextOut == hdcsrc ){
1536                 if ( !RetryPhase ){
1537                         // \8d¡\89ñ\82ÌBitBlt\8e\9e\82ÉExtTextOut\82ª\82 \82Á\82½\82©\81H
1538                         if ( ExtTextOutCount > 0 ){
1539                                 // CursorPoint\82ª\8aÜ\82Ü\82ê\82é\82©\81H
1540                                 DBW("ExtTextOutCount=%d",ExtTextOutCount);
1541                                 if ( (xdest <= CursorPoint.x)
1542                                         && (xdest+width > CursorPoint.x)
1543                                         && (ydest <= CursorPoint.y)
1544                                         && (ydest+height > CursorPoint.y)
1545                                 ){
1546                                         TargetBitBltCount = BitBltCount;
1547                                         TargetOffset.x = xdest - xsrc;
1548                                         TargetOffset.y = ydest - ysrc;
1549                                         DBW("TargetOffset %d %d (%d,%d %dx%d)<-(%d,%d)",
1550                                                 TargetOffset.x, TargetOffset.y,xdest,ydest,width,height,xsrc,ysrc);
1551 #if USE_DBW
1552                                         {
1553                                         POINT vpt;
1554                                         POINT wpt;
1555                                         GetViewportOrgEx( hdcdest, &vpt );
1556                                         GetWindowOrgEx( hdcdest, &wpt );
1557                                         DBW("BitBlt OrgDIFF=%d %d",vpt.x-wpt.x, vpt.y-wpt.y);
1558                                         SIZE sz1;
1559                                         SIZE sz2;
1560                                         GetViewportExtEx( hdcdest, &sz1 );
1561                                         GetWindowExtEx( hdcdest, &sz2 );
1562                                         DBW("BitBlt Ext %d (%d,%d) (%d,%d)", GetMapMode(hdcdest), sz1.cx, sz1.cy, sz2.cx, sz2.cy );
1563 #if 1
1564                                         XFORM xform;
1565                                         GetWorldTransform( hdcdest, &xform );
1566                                         {
1567                                         char buf[100];
1568                                         sprintf(buf,"== [%d] %g %g %g %g %g %g", GetGraphicsMode(hdcdest), xform.eM11, xform.eM12, xform.eM21, xform.eM22, xform.eDx, xform.eDy);
1569                                         DBW(buf);
1570                                         }
1571 #endif
1572                                         }
1573 #endif
1574                                 }
1575 #if METAEXTTEXTOUT
1576                                 if ( TargetBitBltCount != -1 ){
1577                                         // \82·\82Å\82É\82Ù\82©\82Ìband\82Åhit\82µ\82Ä\82¢\82é\8fê\8d\87\81A
1578                                         // Cancel ExtTextOut
1579                                         FoundLocA = -1;
1580                                         FoundLocW = -1;
1581                                 }
1582 #endif
1583                         }
1584                 }
1585                 BitBltCount++;
1586                 DBW("BitBltCount=%d",BitBltCount);
1587                 ExtTextOutCount = 0;
1588                 return r;
1589         } else {
1590 //              DBW("Unknown destination BitBlt %08X(%d,%d %dx%d)<-%08X(%d,%d)",hdcdest,xdest,ydest,width,height,hdcsrc,xsrc,ysrc);
1591         }
1592         return r;
1593 }
1594 #endif
1595
1596 #if HOOK_TEXT
1597 #define HK1( name, ret_type, args ) \
1598         ret_type r = ((FN##name)name##Hook.OrgFunc) args; \
1599         return r
1600 LONG WINAPI _TabbedTextOutA( HDC hdc, int x, int y, LPCSTR str, int count, int ntabs, LPINT tabs, int origin )
1601 {
1602         DBW("_TabbedTextOutA");
1603         HK1( TabbedTextOutA, LONG, ( hdc, x, y, str, count, ntabs, tabs, origin ) );
1604 }
1605 LONG WINAPI _TabbedTextOutW( HDC hdc, int x, int y, LPCWSTR str, int count, int ntabs, LPINT tabs, int origin )
1606 {
1607         DBW("TabbedTextOutW");
1608         HK1( TabbedTextOutW, LONG, ( hdc, x, y, str, count, ntabs, tabs, origin ) );
1609 }
1610 BOOL WINAPI _TextOutA( HDC hdc, int x, int y, LPCSTR str, int count )
1611 {
1612         DBW("_TextOutA");
1613         HK1( TextOutA, BOOL, ( hdc, x, y, str, count ) );
1614 }
1615 BOOL WINAPI _TextOutW( HDC hdc, int x, int y, LPCWSTR str, int count )
1616 {
1617         DBW("_TextOutW");
1618         HK1( TextOutW, BOOL, ( hdc, x, y, str, count ) );
1619 }
1620 int WINAPI _DrawTextA( HDC hdc, LPCSTR str, int count, LPRECT rc, UINT format )
1621 {
1622         DBW("s5");
1623         HK1( DrawTextA, int, ( hdc, str, count, rc, format ) );
1624 }
1625 int WINAPI _DrawTextW( HDC hdc, LPCWSTR str, int count, LPRECT rc, UINT format )
1626 {
1627         DBW("s6");
1628         HK1( DrawTextW, int, ( hdc, str, count, rc, format ) );
1629 }
1630 int WINAPI _DrawTextExA( HDC hdc, LPCSTR str, int count, LPRECT rc, UINT format, LPDRAWTEXTPARAMS params )
1631 {
1632         DBW("s7");
1633         HK1( DrawTextExA, int, ( hdc, str, count, rc, format, params ) );
1634 }
1635 int WINAPI _DrawTextExW( HDC hdc, LPCWSTR str, int count, LPRECT rc, UINT format, LPDRAWTEXTPARAMS params )
1636 {
1637         DBW("s8");
1638         HK1( DrawTextExW, int, ( hdc, str, count, rc, format, params ) );
1639 }
1640 #endif  // HOOK_TEXT
1641
1642 bool CaptureText( HWND hwnd, bool movesend )
1643 {
1644         if ( !hwnd ){
1645                 return false;
1646         }
1647
1648         MoveSendMode = movesend;
1649
1650         //DoScale(NULL, &CursorPoint, 1);
1651
1652 #if METAEXTTEXTOUT
1653         FoundLocA = -1;
1654         FoundLocW = -1;
1655         FoundTextA = new TString<char>;
1656         FoundTextW = new TString<wchar_t>;
1657         LastTextA = new TString<char>;
1658         LastTextW = new TString<wchar_t>;
1659 #endif
1660
1661 #if !USE_REDRAW
1662         HRGN hRgn;
1663 #endif
1664
1665         GetClientRect( hwnd, &rcClient );
1666         GetUpdateRect( hwnd, &rcOrgInvalid, FALSE );
1667
1668 #if USE_OPTIMALINVALID
1669         SetRect( &rcInvalid, 0, max(CursorPoint.y - 64,0), rcClient.right, max(CursorPoint.y + 64,0) );
1670 #else
1671         rcInvalid = rcClient;
1672 #endif
1673
1674 #if !USE_REDRAW
1675         hRgn = CreateRectRgn( rcInvalid.left, rcInvalid.top, rcInvalid.right, rcInvalid.bottom );
1676
1677 #if USE_INVALIDATE
1678         InvalidateRect( hwnd, &rcInvalid, INVALIDATE_TRUE );
1679 #endif
1680
1681         SendMessage( hwnd, WM_PAINT, 0, 0 );
1682         SendMessage( hwnd, WM_NCPAINT, (WPARAM)hRgn, 0 );
1683 #endif
1684
1685         hwndOrg = hwnd;
1686
1687 #if USE_META
1688         HDC hdc;
1689 #endif
1690
1691         HINSTANCE hPSAPI = NULL;
1692         HMODULE hInst;
1693         HMODULE hInstGdi;
1694
1695         hInst = GetModuleHandleA( STR_KERNEL32 );
1696         fnCreateToolhelp32Snapshot = (FNCreateToolhelp32Snapshot)GetProcAddress( hInst, STR_CreateToolhelp32Snapshot );
1697         if (fnCreateToolhelp32Snapshot){
1698                 // Toolhelp\82É\82æ\82émodule enumration\82ª\8eg\97p\89Â\94\
1699                 fnModule32First = (FNModule32First)GetProcAddress( hInst, STR_Module32First );
1700                 fnModule32Next = (FNModule32Next)GetProcAddress( hInst, STR_Module32Next );
1701         } else {
1702                 // Toolhelp\82ª\91\8dÝ\82µ\82È\82¢\8fê\8d\87
1703                 hPSAPI = LoadLibrary( STR_PSAPI );
1704                 DBW("LoadLibrary : %08X",hPSAPI);
1705                 if (!hPSAPI){
1706                         DBW("Cannot load PSAPI.DLL!!");
1707                         return false;
1708                 }
1709                 fnEnumProcessModules = (FNEnumProcessModules)GetProcAddress( hPSAPI, STR_EnumProcessModules );
1710                 fnGetModuleFileNameExA = (FNGetModuleFileNameExA)GetProcAddress( hPSAPI, STR_GetModuleFileNameExA );
1711         }
1712
1713         hInst = GetModuleHandleA( STR_USER32 );
1714 #if USE_DBW
1715         if ( !hInst ){
1716                 DBW("Cannot load USER32.DLL");
1717                 return false;
1718         }
1719 #endif
1720         hInstGdi = GetModuleHandleA( STR_GDI32 );
1721 #if USE_DBW
1722         if ( !hInstGdi ){
1723                 DBW("Cannot load GDI32.DLL");
1724                 goto err9;
1725         }
1726 #endif
1727
1728 #if METAEXTTEXTOUT
1729         if ( !ExtTextOutAHook.GetProcOrgFunc( hInstGdi ) ){
1730                 DBW("Cannot find ExtTextOutA");
1731                 goto err8;
1732         }
1733         if ( !ExtTextOutWHook.GetProcOrgFunc( hInstGdi ) ){
1734                 DBW("Cannot find ExtTextOutW");
1735                 goto err7;
1736         }
1737 #endif
1738
1739 #if HOOK_BITBLT
1740         if ( !BitBltHook.GetProcOrgFunc( hInstGdi ) ){
1741                 DBW("Cannot find BitBlt");
1742                 goto err71;
1743         }
1744 #endif
1745         RetryPhase = false;
1746         TargetBitBltCount = -1;
1747         BitBltCount = 0;
1748         ExtTextOutCount = 0;
1749
1750 #if HOOK_PAINT
1751         if ( !BeginPaintHook.GetProcOrgFunc( hInst ) ){
1752                 DBW("Cannot hook BeginPaint");
1753                 goto err73;
1754         }
1755         if ( !EndPaintHook.GetProcOrgFunc( hInst ) ){
1756                 DBW("Cannot hook EndPaint");
1757                 goto err6;
1758         }
1759 #endif
1760
1761 #if HOOK_TEXT
1762         TabbedTextOutAHook.GetProcOrgFunc( hInst );
1763         TabbedTextOutWHook.GetProcOrgFunc( hInst );
1764         TextOutAHook.GetProcOrgFunc( hInstGdi );
1765         TextOutWHook.GetProcOrgFunc( hInstGdi );
1766         DrawTextAHook.GetProcOrgFunc( hInst );
1767         DrawTextWHook.GetProcOrgFunc( hInst );
1768         DrawTextExAHook.GetProcOrgFunc( hInst );
1769         DrawTextExWHook.GetProcOrgFunc( hInst );
1770 #endif
1771
1772 #if USE_META
1773         hdc = GetDC( hwnd );
1774         if ( !hdc ){
1775                 DBW("Cannot get DC");
1776                 goto err5;
1777         }
1778 #endif
1779
1780 #if HOOK_GETDC
1781         if ( !GetDCHook.GetProcOrgFunc( hInst ) ){
1782                 DBW("Cannot hook GetDC");
1783                 goto err4;
1784         }
1785         if ( !ReleaseDCHook.GetProcOrgFunc( hInst ) ){
1786                 DBW("Cannot hook ReleaseDC");
1787                 goto err3;
1788         }
1789 #endif
1790
1791         {
1792         DBW("Hooked successfully");
1793 //              rect.right = 9999;
1794 //              rect.bottom = 9999;
1795 #if 0
1796                 int iWidthMM = GetDeviceCaps(hdc, HORZSIZE);
1797                 int iHeightMM = GetDeviceCaps(hdc, VERTSIZE);
1798                 int iWidthPels = GetDeviceCaps(hdc, HORZRES);
1799                 int iHeightPels = GetDeviceCaps(hdc, VERTRES);
1800
1801                 // Use iWidthMM, iWidthPels, iHeightMM, and iHeightPels to determine the
1802                 // number of .01-millimeter units per pixel in the x and y directions.
1803
1804                 int iMMPerPelX = (iWidthMM * 100)/iWidthPels;
1805                 int iMMPerPelY = (iHeightMM * 100)/iHeightPels;
1806                 DBW("-%d %d-",iMMPerPelX, iMMPerPelY);
1807
1808                 // Convert client coordinates to .01-mm units.
1809
1810                 rcClient.left = rcClient.left * iMMPerPelX;
1811                 rcClient.top = rcClient.top * iMMPerPelY;
1812                 rcClient.right = rcClient.right * iMMPerPelX;
1813                 rcClient.bottom = rcClient.bottom * iMMPerPelY;
1814 #endif
1815
1816 #if USE_META
1817                 hdcMeta = CreateEnhMetaFile(hdc,
1818                                   NULL,
1819                                   &rcClient, "DCHook\0EnhMetaFile\0");
1820                 if ( !hdcMeta ){
1821                         DBW("Cannot create Meta file");
1822                         goto err3;
1823                 }
1824
1825                 DBW("hdcMeta=%08X", hdcMeta);
1826 #endif
1827
1828 #if USE_REDRAW
1829                 RedrawWindow( hwnd, &rcInvalid, NULL, RDW_UPDATENOW | RDW_NOERASE | RDW_NOFRAME | RDW_INVALIDATE );
1830 #else
1831                 WNDPROC PaintWndProc = (WNDPROC)GetWindowLong( hwnd, GWL_WNDPROC );
1832                 SendMessage( hwnd, WM_PAINT, (WPARAM)hdcMeta, 0 );
1833 #endif
1834 #if HOOK_GETDC
1835                 ReleaseDCHook.Finish();
1836                 GetDCHook.Finish();
1837 #endif
1838
1839 #if HOOK_TEXT
1840                 TabbedTextOutAHook.Finish( );
1841                 TabbedTextOutWHook.Finish( );
1842                 TextOutAHook.Finish( );
1843                 TextOutWHook.Finish( );
1844                 DrawTextAHook.Finish( );
1845                 DrawTextWHook.Finish( );
1846                 DrawTextExAHook.Finish( );
1847                 DrawTextExWHook.Finish( );
1848 #endif
1849
1850 #if HOOK_PAINT
1851                 EndPaintHook.Finish();
1852                 BeginPaintHook.Finish();
1853 #endif
1854
1855 #if HOOK_BITBLT
1856                 BitBltHook.Finish();
1857 #endif
1858
1859 #if METAEXTTEXTOUT
1860                 ExtTextOutAHook.Finish();
1861                 ExtTextOutWHook.Finish();
1862 #endif
1863
1864                 // Notify start enumrate meta-file
1865                 CallbackMain(DCH_START, &CursorPoint, sizeof(CursorPoint), hwnd);
1866
1867                 HitFound = false;
1868
1869 #if USE_META
1870                 HENHMETAFILE emf = CloseEnhMetaFile( hdcMeta );
1871
1872                 if ( emf )
1873 #endif
1874                 {
1875 #if METAEXTTEXTOUT
1876                         if ( FoundLocA != -1 || FoundLocW != -1 ){
1877 //                              DBW("Hit ExtText:%d %d",FoundLocA,FoundLocW);
1878                                 // ExtTextOutx hook\82Ì\82Ù\82¤\82ð\97D\90æ\82·\82é
1879                                 ExtTextOutHit( );
1880                                 HitFound = true;
1881                         } else
1882 #endif
1883                         {
1884 #if USE_META
1885                                 // Create compatible device-context for enumration
1886                                 HDC _hdc = CreateCompatibleDC( hdc );
1887                                 HBITMAP hbitmap = CreateCompatibleBitmap( hdc, rcClient.right, rcClient.bottom );
1888                                 HGDIOBJ gdiobj = SelectObject( _hdc, hbitmap );
1889
1890                                 DBW("Start meta");
1891                                 // Enumerate meta-file
1892                                 EnumEnhMetaFile( _hdc, emf, EnumMetaFileProc, NULL, &rcClient );
1893                                 DBW("End meta");
1894
1895                                 // Delete compatible device-context
1896                                 SelectObject( _hdc, gdiobj );
1897                                 DeleteObject( hbitmap );
1898                                 DeleteDC( _hdc );
1899 #endif
1900                         }
1901 #if USE_META
1902                         DeleteEnhMetaFile( emf );
1903 #endif
1904                 }
1905 #if USE_META
1906                 else {
1907                         DBW("emf is NULL");
1908                 }
1909 #endif
1910
1911 #if METAEXTTEXTOUT
1912                 if ( !HitFound && TargetBitBltCount != -1 ){
1913                         DBW("Search from band:%d",TargetBitBltCount);
1914 #if USE_META
1915                         // Band\82©\82ç\8c\9f\8dõ
1916                         hdcMeta = CreateCompatibleDC( hdc );
1917                         if ( !hdcMeta ){
1918                                 DBW("Cannot create HDC in retry");
1919                         } else
1920 #endif
1921                         {
1922 #if USE_META
1923                                 HBITMAP hbitmap = CreateCompatibleBitmap( hdc, rcClient.right, rcClient.bottom );
1924                                 HGDIOBJ gdiobj = SelectObject( hdcMeta, hbitmap );
1925                                 DBW("hdcMeata=%08X", hdcMeta);
1926 #endif
1927
1928                                 BitBltCount = 0;
1929                                 RetryPhase = true;
1930 #if METAEXTTEXOUT
1931                                 FoundLocA = -1;
1932                                 FoundLocW = -1;
1933 #endif
1934
1935 #if METAEXTTEXTOUT
1936                                 ExtTextOutAHook.HookAgain();
1937                                 ExtTextOutWHook.HookAgain();
1938 #endif
1939 #if HOOK_BITBLT
1940                                 BitBltHook.HookAgain();
1941 #endif
1942 #if HOOK_PAINT
1943                                 BeginPaintHook.HookAgain();
1944                                 EndPaintHook.HookAgain();
1945 #endif
1946
1947 //                              DBW("t1:%d %d %d %d",rcClient.left, rcClient.top,rcClient.right,rcClient.bottom);
1948
1949 #if USE_INVALIDATE
1950                                 InvalidateRect( hwnd, &rcInvalid, INVALIDATE_TRUE );
1951 #endif
1952
1953 #if USE_REDRAW
1954                                 RedrawWindow( hwnd, &rcInvalid, NULL, RDW_UPDATENOW | RDW_NOERASE | RDW_NOFRAME | RDW_INVALIDATE );
1955 #else
1956                                 CallWindowProc( (WNDPROC)PaintWndProc, hwnd, WM_PAINT, (WPARAM)hdcMeta, 0 );
1957 #endif
1958
1959 #if HOOK_PAINT
1960                                 EndPaintHook.Finish();
1961                                 BeginPaintHook.Finish();
1962 #endif
1963 #if HOOK_BITBLT
1964                                 BitBltHook.Finish();
1965 #endif
1966
1967 #if METAEXTTEXTOUT
1968                                 ExtTextOutAHook.Finish();
1969                                 ExtTextOutWHook.Finish();
1970 #endif
1971 #if USE_META
1972                                 SelectObject( hdcMeta, gdiobj );
1973                                 DeleteObject( hbitmap );
1974                                 DeleteDC( hdcMeta );
1975 #endif
1976                                 if ( FoundLocA != -1 || FoundLocW != -1 ){
1977                                         DBW("Found in BitBlt ExtText:%d %d",FoundLocA,FoundLocW);
1978                                         ExtTextOutHit( );
1979                                         HitFound = true;
1980                                 }
1981                         }
1982                 }
1983 #endif  // METAEXTTEXTOUT
1984
1985 #if RETRYMETA
1986                 if ( !HitFound ){
1987                         HENHMETAFILE emf;
1988 #if !USE_META
1989                         HDC hdc = GetDC( hwnd );
1990                         if ( !hdc ){
1991                                 DBW("Cannot get DC");
1992                                 goto err01;
1993                         }
1994 #endif
1995 #if HOOK_PAINT
1996                         if ( !BeginPaintHook.HookAgain( ) ){
1997                                 DBW("Cannot hook BeginPaint");
1998                                 goto err02;
1999                         }
2000                         if ( !EndPaintHook.HookAgain( ) ){
2001                                 DBW("Cannot hook EndPaint");
2002                                 goto err03;
2003                         }
2004 #else
2005                         if ( !BeginPaintHook.GetProcOrgFunc( hInst ) ){
2006                                 DBW("Cannot hook BeginPaint");
2007                                 goto err02;
2008                         }
2009                         if ( !EndPaintHook.GetProcOrgFunc( hInst ) ){
2010                                 DBW("Cannot hook EndPaint");
2011                                 goto err03;
2012                         }
2013 #endif
2014
2015                         hdcMeta = CreateEnhMetaFile(hdc,
2016                                           NULL,
2017                                           &rcClient, _T("DCHook\0EnhMetaFile\0"));
2018                         if ( !hdcMeta ){
2019                                 DBW("Cannot create Meta file");
2020                                 goto err04;
2021                         }
2022                         DBW("hdcMeta=%08X", hdcMeta);
2023 //                      InvalidateRect( hwnd, &rcInvalid, INVALIDATE_TRUE );
2024 #if 1           // 2000.7.15 NT\82Å\82à\82È\82º\82±\82Á\82¿\82É\82µ\82Ä\82¢\82È\82©\82Á\82½\82Ì\82©\82í\82©\82ç\82È\82¢\82ª\81E\81E\81E
2025                         SendMessage( hwnd, WM_PAINT, (WPARAM)hdcMeta, 0 );
2026 #else
2027                         // Notepad\82Å\82Í\88Ù\8fí\8fI\97¹\82·\82é\82½\82ß\8bp\89º
2028                         // \89½\82à\82È\82¢\82Æ\82±\82ë\82ÅCtrl+\89E\83N\83\8a\83b\83N
2029                         WNDPROC PaintWndProc = (WNDPROC)GetWindowLong( hwnd, GWL_WNDPROC );
2030                         if ( PaintWndProc ){
2031                                 PaintWndProc( hwnd, WM_PAINT, (WPARAM)hdcMeta, 0 );
2032                         }
2033 #endif
2034                         EndPaintHook.Finish();
2035                         BeginPaintHook.Finish();
2036
2037                         emf = CloseEnhMetaFile( hdcMeta );
2038
2039                         if ( emf ){
2040                                 HDC _hdc = CreateCompatibleDC( hdc );
2041                                 HBITMAP hbitmap = CreateCompatibleBitmap( hdc, rcClient.right, rcClient.bottom );
2042                                 HGDIOBJ gdiobj = SelectObject( _hdc, hbitmap );
2043
2044                                 DBW("Start meta-retry");
2045                                 // Enumerate meta-file
2046                                 EnumEnhMetaFile( _hdc, emf, EnumMetaFileProc, NULL, &rcClient );
2047                                 DBW("End meta-retry");
2048
2049                                 // Delete compatible device-context
2050                                 SelectObject( _hdc, gdiobj );
2051                                 DeleteObject( hbitmap );
2052                                 DeleteDC( _hdc );
2053                                 DeleteEnhMetaFile( emf );
2054                         }
2055                 err04:
2056                         EndPaintHook.Finish();
2057                 err03:
2058                         BeginPaintHook.Finish();
2059                 err02:
2060 #if !USE_META
2061                         ReleaseDC( hwnd, hdc );
2062 #endif
2063                 err01:;
2064                 }
2065 #endif
2066                 
2067                 // Notify end enumrate meta-file
2068                 CallbackMain(DCH_END | (MoveSendMode ? DCH_MOVESEND : 0), NULL, 0, hwnd);
2069         }
2070
2071 #if USE_META
2072         ReleaseDC( hwnd, hdc );
2073 #endif
2074
2075         if ( rcOrgInvalid.right != 0 ){
2076                 DBW("Update OrgInvalid--------");
2077                 InvalidateRect( hwnd, NULL, INVALIDATE_TRUE );
2078         }
2079
2080         goto jreturn;
2081
2082 #if HOOK_GETDC || USE_META
2083 err3:;
2084 #endif
2085 #if HOOK_GETDC
2086         GetDCHook.Finish();
2087 err4:;
2088 #if USE_META
2089         ReleaseDC( hwnd, hdc );
2090 #endif
2091 #endif
2092 #if USE_META
2093 err5:;
2094 #endif
2095 #if HOOK_PAINT
2096         EndPaintHook.Finish();
2097 err6:;
2098         BeginPaintHook.Finish();
2099 err73:;
2100 #endif
2101 #if HOOK_BITBLT
2102         BitBltHook.Finish();
2103 #endif
2104 #if HOOK_BITBLT
2105 err71:;
2106 #endif
2107 #if METAEXTTEXTOUT
2108         ExtTextOutWHook.Finish();
2109 err7:;
2110         ExtTextOutAHook.Finish();
2111 err8:
2112 #endif
2113         if (hPSAPI)
2114                 FreeLibrary( hPSAPI );
2115 #if USE_DBW
2116 err9:
2117 #endif
2118         HitFound = false;
2119 jreturn:;
2120 #if USE_VXD
2121         if (vxd_Handle!=INVALID_HANDLE_VALUE)
2122                 UnloadVxD();
2123 #endif
2124 #if METAEXTTEXTOUT
2125         delete FoundTextA;
2126         delete FoundTextW;
2127         delete LastTextA;
2128         delete LastTextW;
2129 #endif
2130
2131         return HitFound;
2132 }
2133 #if METAEXTTEXTOUT
2134 void ExtTextOutHit()
2135 {
2136         if ( FoundLocA != -1 ){
2137                 // Hit on ANSI
2138                 DBW("Hit on ANSI@ExtTextOut");
2139                 CallbackMain(DCH_HITTEXT1, FoundTextA->c_str(), FoundTextA->GetByte(), (HWND)FoundLocA);
2140         } else {
2141                 // Hit on UNICODE
2142                 DBW("Hit on UNICODE@ExtTextOut");
2143                 CallbackMain(DCH_HITTEXT2, FoundTextW->c_str(), FoundTextW->GetByte(), (HWND)FoundLocW);
2144         }
2145 }
2146 #endif  // METAEXTTEXTOUT
2147
2148 void DoScale(HDC hdc, POINT *pts, int num)
2149 {
2150         //TODO: hInst, proc\82Íglobal\82É\82µ\82½\82Ù\82¤\82ª\82¢\82¢\82Ì\82Å\82Í\81H
2151
2152         int scale = 0;
2153         if (ScaleX && ScaleY){
2154                 scale = ScaleX; // \8ew\92è\82µ\82½scaling parameter
2155         } else {
2156                 scale = GetMonitorScale();
2157                 if (scale == 96) return;
2158         }
2159
2160 #if 1
2161 #if 1
2162         PROCESS_DPI_AWARENESS value = Process_DPI_Unaware;
2163         if (hInstSHCore){
2164                 if (!GetProcessDPIAwareness){
2165                         GetProcessDPIAwareness = (FNGetProcessDPIAwareness)GetProcAddress(hInstSHCore, "GetProcessDpiAwareness");
2166                 }
2167                 if (GetProcessDPIAwareness){
2168                         GetProcessDPIAwareness(hProcess, &value);
2169                         DBW("DPIAware: value=%d", value);
2170                 }
2171         }
2172         if (value != Process_System_DPI_Aware){
2173                 int dpi_x = scale;
2174                 int dpi_y = scale;
2175                 DBW("dpi: %d,%d", dpi_x, dpi_y);
2176                 for (int i=0;i<num;i++){
2177                         pts[i].x = MulDiv(pts[i].x, dpi_x, 96);
2178                         pts[i].y = MulDiv(pts[i].y, dpi_y, 96);
2179                 }
2180         }
2181 #else
2182         HINSTANCE hInst = NULL;
2183         FNGetProcessDPIAwareness GetProcessDPIAwareness = NULL;
2184         //FNSetProcessDPIAwareness SetProcessDPIAwareness = NULL;
2185         //if (!GetProcessDPIAwareness)
2186         {
2187                 hInst = LoadLibrary("shcore.dll");
2188                 if (hInst){
2189                         GetProcessDPIAwareness = (FNGetProcessDPIAwareness)GetProcAddress(hInst, "GetProcessDpiAwareness");
2190                         //SetProcessDPIAwareness = (FNSetProcessDPIAwareness)GetProcAddress(hInst, "SetProcessDpiAwareness");
2191                         //DBW("DPI API:%08X %08X", GetProcessDPIAwareness, SetProcessDPIAwareness);
2192                         DBW("DPI API:%08X", GetProcessDPIAwareness);
2193                 }
2194         }
2195         if (GetProcessDPIAwareness || (ScaleX && ScaleY)){
2196                 int dpi_x, dpi_y;
2197                 PROCESS_DPI_AWARENESS value;
2198                 if (GetProcessDPIAwareness && hdc){
2199                         HRESULT hRes = GetProcessDPIAwareness(hProcess, &value);
2200                         DBW("DPIAware: value=%d", value);
2201                         //SetProcessDPIAwareness(Process_System_DPI_Aware);
2202                         dpi_x = GetDeviceCaps(hdc, LOGPIXELSX);
2203                         dpi_y = GetDeviceCaps(hdc, LOGPIXELSY);
2204                         DBW("dpi: %d, %d", dpi_x, dpi_y);
2205                 } else {
2206                         dpi_x = ScaleX;
2207                         dpi_y = ScaleY;
2208                 }
2209                 for (int i=0;i<num;i++){
2210                         pts[i].x = MulDiv(pts[i].x, dpi_x, 96);
2211                         pts[i].y = MulDiv(pts[i].y, dpi_y, 96);
2212                 }
2213 #if 0
2214                 if (SetProcessDPIAwareness){
2215                         SetProcessDPIAwareness(value);
2216                 }
2217 #endif
2218         }
2219         if (hInst){
2220                 FreeLibrary(hInst);
2221         }
2222 #endif
2223 #else   // \8b\8c\83R\81[\83h
2224         HINSTANCE hInst = NULL;
2225         if (!GetProcessDPIAwareness){
2226                 hInst = LoadLibrary("shcore.dll");
2227                 DBW("shcore=%08X", hInst);
2228                 if (hInst){
2229                         GetProcessDPIAwareness = (FNGetProcessDPIAwareness)GetProcAddress(hInst, "GetProcessDPIAwareness");
2230                         SetProcessDPIAwareness = (FNSetProcessDPIAwareness)GetProcAddress(hInst, "SetProcessDPIAwareness");
2231                         DBW("DPI API:%08X %08X", GetProcessDPIAwareness, SetProcessDPIAwareness);
2232                 }
2233         }
2234         if (GetProcessDPIAwareness || (ScaleX && ScaleY)){
2235                 int dpi_x, dpi_y;
2236                 PROCESS_DPI_AWARENESS value;
2237                 if (GetProcessDPIAwareness && hdc){
2238                         HRESULT hRes = GetProcessDPIAwareness(hProcess, &value);
2239                         SetProcessDPIAwareness(Process_System_DPI_Aware);
2240                         dpi_x = GetDeviceCaps(hdc, LOGPIXELSX);
2241                         dpi_y = GetDeviceCaps(hdc, LOGPIXELSY);
2242                 } else {
2243                         dpi_x = ScaleX;
2244                         dpi_y = ScaleY;
2245                 }
2246                 for (int i=0;i<num;i++){
2247                         pts[i].x = MulDiv(pts[i].x, dpi_x, 96);
2248                         pts[i].y = MulDiv(pts[i].y, dpi_y, 96);
2249                 }
2250                 if (SetProcessDPIAwareness){
2251                         SetProcessDPIAwareness(value);
2252                 }
2253                 if (hInst){
2254                         FreeLibrary(hInst);
2255                 }
2256         }
2257 #endif
2258 }
2259
2260 int CALLBACK EnumMetaFileProc( HDC hdc, HANDLETABLE *ht, CONST ENHMETARECORD *mfr, int nobj, LPARAM /* user */ )
2261 {
2262         PlayEnhMetaFileRecord( hdc, ht, mfr, nobj );
2263
2264         //DBW("iType=%d",mfr->iType);
2265
2266         switch ( mfr->iType ){
2267                 case EMR_EXTTEXTOUTA:
2268                 case EMR_EXTTEXTOUTW:
2269                 {
2270                         EMREXTTEXTOUTW *emr = (EMREXTTEXTOUTW*)mfr;
2271
2272                         //DBW("(%d,%d) <%d=%d=%d=%d>", CursorPoint.x, CursorPoint.y, emr->rclBounds.left, emr->rclBounds.top,emr->rclBounds.right, emr->rclBounds.bottom);
2273 #if 1
2274                         if ( PtInRect( (RECT*)&emr->rclBounds, CursorPoint ) ){
2275                                 DBW("(%d,%d) <%d=%d>", CursorPoint.x, CursorPoint.y, emr->rclBounds.left, emr->emrtext.ptlReference.x);
2276 #if 0
2277                                 {
2278                                 SIZE sz1, sz2;
2279                                 GetWindowExtEx( hdc, &sz1 );
2280                                 GetViewportExtEx( hdc, &sz2 );
2281                                 DBW("%d-%d %d-%d", sz1.cx, sz1.cy, sz2.cx, sz2.cy);
2282                                 }
2283 #endif
2284                                 int loc;
2285                                 if ( mfr->iType == EMR_EXTTEXTOUTW ){
2286                                         //DBW("offString=%d nChars=%d left=%d top=%d offDx=%d", emr->emrtext.offString, emr->emrtext.nChars, emr->rclBounds.left, emr->rclBounds.top, emr->emrtext.offDx);
2287                                         //DBW("text=%ws", (wchar_t*) ( ((char*)emr) + emr->emrtext.offString ));
2288                                         loc = GetTextFromPoint( hdc, (wchar_t*) ( ((char*)emr) + emr->emrtext.offString ),
2289                                                 emr->emrtext.nChars,
2290                                                 CursorPoint.x - emr->rclBounds.left /* + emr->emrtext.ptlReference.x */,
2291                                                 CursorPoint.y - emr->rclBounds.top  /* + emr->emrtext.ptlReference.y */,
2292                                                 ((int*)(((char*)emr) + emr->emrtext.offDx)) );
2293                                 } else {
2294                                         loc = GetTextFromPoint( hdc, ((char*)emr) + emr->emrtext.offString,
2295                                                 emr->emrtext.nChars,
2296                                                 CursorPoint.x - emr->rclBounds.left /* + emr->emrtext.ptlReference.x */,
2297                                                 CursorPoint.y - emr->rclBounds.top  /* + emr->emrtext.ptlReference.y */,
2298                                                 ((int*)(((char*)emr) + emr->emrtext.offDx)) );
2299                                 }
2300                                 if ( loc != -1 ){
2301 //                                      char *buf = NULL;
2302                                         const char *text = ((char*)emr) + emr->emrtext.offString;
2303                                         int len = emr->emrtext.nChars;
2304                                         if ( mfr->iType == EMR_EXTTEXTOUTW ){
2305                                                 // WIDE
2306                                                 //DBW("len=%d loc=%d text=%ws", len, loc, text);
2307                                                 CallbackMain(DCH_HITTEXT2, text, len * sizeof(wchar_t), (HWND)loc);
2308 #if 0
2309                                                 // UNICODE->ANSI
2310                                                 // ANSI\8fã\82Å\82Ìloc\82ð\8b\81\82ß\82é\82½\82ß\81A\91O\94¼\82Æ\8cã\94¼\82ð\95ª\82¯\82Ä\95Ï\8a·
2311                                                 wchar_t *wp = (wchar_t*) ( ((char*)emr) + emr->emrtext.offString );
2312                                                 buf = new char[ emr->emrtext.nChars * 2 ];
2313                                                 memset( buf, 0, emr->emrtext.nChars*2 );
2314                                                 // \91O\94¼\95\94\95ª
2315                                                 len = 0;
2316                                                 if ( loc > 0 ){
2317                                                         len = WideCharToMultiByte( CP_ACP, 0, wp, loc,
2318                                                                 buf, emr->emrtext.nChars * 2, NULL, NULL );
2319                                                 }
2320                                                 int newloc = len;
2321                                                 // \8cã\94¼\95\94\95ª
2322                                                 if ( emr->emrtext.nChars > (unsigned int)loc ){
2323                                                         len += WideCharToMultiByte( CP_ACP, 0, wp+loc, emr->emrtext.nChars - loc,
2324                                                                 buf+len, emr->emrtext.nChars * 2 - len, NULL, NULL );
2325                                                 }
2326                                                 loc = newloc;
2327                                                 text = buf;
2328 #endif
2329
2330                                         } else {
2331                                                 // ANSI
2332                                                 CallbackMain(DCH_HITTEXT1, text, len, (HWND)loc);
2333                                         }
2334
2335                                         DBW("Found@Enum");
2336 #if 0
2337                                         CallbackMain(DCH_HITTEXT1, text, len, (HWND)loc);
2338                                         if ( buf )
2339                                                 delete buf;
2340 #endif
2341 #if 0
2342                                         {
2343                                         char b[100];
2344                                         sprintf(b,"exScale=%f eyScale=%f ptlReference=(%d,%d)",emr->exScale, emr->eyScale, emr->emrtext.ptlReference.x, emr->emrtext.ptlReference.y );
2345                                         DBW(b);
2346                                         DBW("iGraphicsMode=%d", emr->iGraphicsMode);
2347                                         }
2348 #endif
2349 #if 0
2350                                         {
2351                                                 for ( int i=0;i<(int)emr->emrtext.nChars;i++ ){
2352                                                         DBW(">%d", ((int*)(((char*)emr) + emr->emrtext.offDx))[i] );
2353                                                 }
2354                                         }
2355 #endif
2356 //                                      DBW("[%d %d][%d %d]text=(%s)", emr->rclBounds.left, emr->rclBounds.top, CursorPoint.x, CursorPoint.y, text);
2357 //                                      result = false; // stop enumration      // \8d\82\91¬\89»\82Ì\82½\82ß\93r\92\86\82Å\8fI\82í\82è\82É\82µ\82½\82¢\82ª\81E\81E\81E\82Ç\82¤\82µ\82æ\82¤\81H
2358 #if METAEXTTEXTOUT
2359                                         // prevent to get from ExtTextOut hook
2360                                         FoundLocA = -1;
2361                                         FoundLocW = -1;
2362 #endif
2363                                         HitFound = true;
2364                                 }
2365                         }
2366 #else   // for debug
2367                         if ( mfr->iType == EMR_EXTTEXTOUTW ){
2368                                 CallbackMain(DCH_EXTTEXTOUTW, emr, sizeof(EMREXTTEXTOUTW) + emr->emrtext.nChars * sizeof(wchar_t), (HWND)hdc);
2369                         } else {
2370                                 CallbackMain(DCH_EXTTEXTOUTA, emr, sizeof(EMREXTTEXTOUTA) + emr->emrtext.nChars, (HWND)hdc);
2371                         }
2372 #endif
2373                 }
2374                         break;
2375         }
2376         return true;
2377 }
2378
2379 }       // extern "C"
2380
2381 // text\82Ì\90æ\93ª\82ð(0,0)\82Æ\82µ\82½\8dÀ\95W\82Å\81Apos\82Ì\88Ê\92u\82É\82 \82étext\82Ì\95\8e\9a\88Ê\92u\82ð\95Ô\82·
2382 int GetTextFromPoint( HDC hdc, const char *text, int len, int pos_x, int pos_y, const int *dx )
2383 {
2384         if ( pos_x < 0 || pos_y < 0 ) return -1;
2385
2386         int count = 0;
2387         SIZE sz;
2388         int *rdx = NULL;
2389         if ( dx ){
2390                 rdx = new int[len];
2391                 memset( rdx, 0, len*sizeof(int) );
2392         }
2393         if ( !GetTextExtentExPointA( hdc, text, len, pos_x, &count, rdx, &sz ) ){
2394                 DBW("GetTextExtentExPointA Failure!!");
2395                 if ( rdx )
2396                         delete rdx;
2397                 return -1;
2398         }
2399 #if METAEXTTEXTOUT
2400         LastX += sz.cx; // update
2401 #endif
2402         // size over check
2403         if ( pos_y > sz.cy
2404                 || pos_x > sz.cx
2405                 ){
2406                 if ( rdx ) delete rdx;
2407                 return -1;
2408         }
2409         DBW("A:len=%d pos_x=%d sz.cx=%d", len, pos_x, sz.cx);
2410         if ( dx && count > 0 ){
2411                 // ex.
2412                 // Win98,Notepad\82Ì\93ú\96{\8cê\8fã\82Å
2413                 //  dx = 0, 8, 0, 8, 0, 8, ...
2414                 // rdx = 9,10, 9,10, 9,10, ...
2415 #if 0
2416                 {
2417                         int i;
2418                         for ( i=0;i<len;i++ ){
2419                                 DBW(" dx[%2d]=%d",i,dx[i]);
2420                         }
2421                         for ( i=0;i<count;i++ ){
2422                                 DBW("rdx[%2d]=%d",i,rdx[i+1]-rdx[i]);
2423                         }
2424                 }
2425 #endif
2426                 // spacing\82Ì\8cë\8d·\82ð\8cv\8eZ
2427                 // Times New Roman\82È\82Ç\82Å\92²\82×\82é\82Æ\82©\82È\82è\82Ì\8cë\8d·\82ª\82 \82é\81B\82È\82º\81H
2428
2429                 int i = 0;
2430                 int j = 0;
2431                 int sumdx = 0;
2432 //              DBW("rd(x)[0]=%d,%d",dx[0],rdx[0]);
2433                 if ( rdx[0] ){
2434                         if ( dx[0] ){
2435                                 sumdx = dx[0] - rdx[0];
2436                         } else {
2437                                 sumdx = dx[1] - rdx[0];
2438                         }
2439                         i++;
2440                         j++;
2441                 }
2442                 for ( ;i<count;i++,j++ ){
2443 #if 0
2444                         if ( rdx[i] == rdx[i-1] ){ j--; continue;}      // for multi-bytes font
2445                                                                                                                 //*++ \82 \82Æ\82Å ExtTextOut API manual\82ð\8eQ\8fÆ
2446                         sumdx += dx[j] - (rdx[i]-rdx[i-1]);
2447 //                      DBW("%3d <> %3d", dx[j], rdx[i]-rdx[i-1]);
2448 #else   // Win98\82Å\82Í\81Amulti-byte\82Å\82à\95ª\8eU\82³\82¹\82Ä\82¢\82é\8fê\8d\87\82ª\82 \82é\82½\82ß\81Adx\82Å\94»\92f
2449                         sumdx += (dx[j]?dx[j]:dx[j+1]) - (rdx[i]-rdx[i-1]);
2450 #endif
2451                 }
2452 //              DBW("sumdx=%d",sumdx);
2453                 if ( !GetTextExtentExPointA( hdc, text, len, pos_x - sumdx, &count, rdx, &sz ) ){
2454                         if ( rdx )
2455                                 delete rdx;
2456                         return -1;
2457                 }
2458         }
2459         if ( rdx )
2460                 delete rdx;
2461         return count;
2462 }
2463 int GetTextFromPoint( HDC hdc, const wchar_t *text, int len, int pos_x, int pos_y, const int *dx )
2464 {
2465 #if USE_VXD
2466         if (WindowsNT)
2467 #endif
2468         {
2469                 if ( pos_x < 0 || pos_y < 0 ) return -1;
2470
2471                 int count = 0;
2472                 SIZE sz;
2473                 int *rdx = NULL;
2474                 if ( dx ){
2475                         rdx = new int[ len ];
2476                         memset( rdx, 0, len );
2477                 }
2478                 if ( !GetTextExtentExPointW( hdc, text, len, pos_x, &count, rdx, &sz ) )
2479                 {
2480                         DBW("GetTextExtentExPointW Failure!!");
2481                         if ( rdx )
2482                                 delete[] rdx;
2483                         return -1;
2484                 }
2485 #if METAEXTTEXTOUT
2486                 LastX += sz.cx;
2487 #endif
2488                 // size over check
2489                 if ( pos_y > sz.cy
2490                         || pos_x > sz.cx
2491                         ){
2492                         if ( rdx ) delete[] rdx;
2493                         return -1;
2494                 }
2495                 DBW("W:len=%d pos_x=%d sz.cx=%d", len, pos_x, sz.cx);
2496                 if ( dx && count > 0 ){
2497                         // spacing\82Ì\8cë\8d·\82ð\8cv\8eZ
2498                         // Times New Roman\82È\82Ç\82Å\92²\82×\82é\82Æ\82©\82È\82è\82Ì\8cë\8d·\82ª\82 \82é\81B\82È\82º\81H
2499                         int i = 0;
2500                         int j = 0;
2501                         int sumdx = 0;
2502         //              DBW("rd(x)[0]=%d,%d",dx[0],rdx[0]);
2503                         if ( rdx[0] ){
2504                                 sumdx = dx[0] - rdx[0];
2505                                 i++;
2506                                 j++;
2507                         }
2508                         for ( ;i<count-1;i++,j++ ){
2509 #if 0
2510                                 if ( rdx[i] == rdx[i-1] ){ j--; continue;}      // for multi-bytes font
2511                                                                                                                 //*++ \82 \82Æ\82Å ExtTextOut API manual\82ð\8eQ\8fÆ
2512                                 sumdx += dx[j] - (rdx[i]-rdx[i-1]);
2513         //                      DBW("%3d <> %3d", dx[j], rdx[i]-rdx[i-1]);
2514 #else
2515                                 sumdx += (dx[j]?dx[j]:dx[j+1]) - (rdx[i]-rdx[i-1]);
2516 #endif
2517                         }
2518         //              DBW("sumdx=%d",sumdx);
2519                         if ( !GetTextExtentExPointW( hdc, text, len, pos_x - sumdx, &count, rdx, &sz ) ){
2520                                 if ( rdx )
2521                                         delete rdx;
2522                                 return -1;
2523                         }
2524                 }
2525                 if ( rdx )
2526                         delete rdx;
2527                 return (count == len && sz.cx < pos_x) ? -1 : count;
2528         }
2529 #if USE_VXD
2530         else {
2531                 char *buf = new char[ len * sizeof(wchar_t) ];
2532                 memset( buf, 0, len * sizeof(wchar_t) );
2533                 int ansilen = WideCharToMultiByte( CP_ACP, 0, text, len, buf, len*sizeof(wchar_t), NULL, NULL );
2534                 int r = GetTextFromPoint( hdc, buf, ansilen, pos_x, pos_y, dx );
2535                 delete buf;
2536                 return r;
2537         }
2538 #endif
2539 }
2540
2541 #define WMCD_EXISTCHECK         0x4000
2542 #define WMCD_SETPOINT           0x4001
2543
2544 class TDC {
2545         HDC hdc;
2546         HWND hwnd;
2547 public:
2548         TDC()
2549         :hwnd(NULL)
2550         {
2551                 hdc = GetDC(NULL);
2552         }
2553         TDC(HWND _hwnd)
2554         :hwnd(_hwnd)
2555         {
2556                 hdc = GetWindowDC(hwnd);
2557         }
2558         ~TDC()
2559         {
2560                 reset();
2561         }
2562         void reset()
2563         {
2564                 if (hdc){
2565                         ReleaseDC(hwnd, hdc);
2566                         hdc = NULL;
2567                 }
2568         }
2569         operator HDC() { return hdc; }
2570         bool operator !() { return hdc==NULL; }
2571 };
2572
2573 bool CaptureImage(HWND hwnd, bool movesend, bool non_block)
2574 {
2575         MoveSendMode = movesend;
2576         CaptureImageBlocking = false;
2577
2578         bool capture_page = false;
2579         if (hwndAMODI){
2580                 capture_page = SendMessage(hwndAMODI, WM_AMODI, AMODI_CMD_PAGE_CAPTURE, 0) ? true : false;
2581         }
2582
2583         // Get the rect of the target window.
2584         RECT rcTarget;
2585         if (!GetWindowRect(hwnd, &rcTarget)){
2586                 // window died?
2587                 return false;
2588         }
2589         if (!ExtAMODI){
2590                 if (!IsWindowEnabled(hwndAMODI)){
2591                         // AMODI died?
2592                         hwndAMODI = FindAMODI();
2593                         if (!hwndAMODI)
2594                                 return false;
2595                 }
2596         }
2597         int w = rcTarget.right - rcTarget.left;
2598         int h = rcTarget.bottom - rcTarget.top;
2599         if (w==0 || h==0){
2600                 return false;   // no area in the target.
2601         }
2602
2603         POINT ptCursor; // \89æ\91\9c\8fã\82Ì\83J\81[\83\\83\8b\88Ê\92u
2604         int x, y;
2605         if (capture_page){
2606                 x = rcTarget.left;
2607                 y = rcTarget.top;
2608                 ptCursor.x = ScreenPoint.x - rcTarget.left;
2609                 ptCursor.y = ScreenPoint.y - rcTarget.top;
2610         } else {
2611                 // x\95û\8cü : target rect\82Ì\8d\92[\82©\82ç
2612                 // y\95û\8cü : cursor point\82Ì\8fã\89º100 pixel
2613                 x = rcTarget.left;
2614                 int offs = 100;
2615                 if (ScreenPoint.y - rcTarget.top < offs){
2616                         if (ScreenPoint.y < rcTarget.top) return false; // click on out of rect?
2617                         y = rcTarget.top;
2618                         h = ScreenPoint.y - rcTarget.top + offs;
2619                 } else {
2620                         y = ScreenPoint.y - offs;
2621                         h = offs * 2;
2622                 }
2623                 if (y+h>rcTarget.bottom){
2624                         h = rcTarget.bottom - y;
2625                 }
2626                 ptCursor.x = ScreenPoint.x - rcTarget.left;
2627                 ptCursor.y = ScreenPoint.y - y;
2628         }
2629
2630         if (0){
2631                 HWND hwnd = GetDesktopWindow();
2632                 RECT rc;
2633                 GetWindowRect(hwnd, &rc);
2634                 x = 0;
2635                 y = 0;
2636                 w = rc.right - rc.left;
2637                 h = rc.bottom - rc.top;
2638         }
2639
2640         if (!capture_page){
2641                 // Notify start enumrate
2642                 CallbackMain(DCH_START, &CursorPoint, sizeof(CursorPoint), hwnd);
2643         }
2644
2645         bool ok = false;
2646
2647         TDC hdc;
2648
2649         if (!hdc){
2650                 goto jend;
2651         }
2652
2653 #if USE_SCALING
2654         POINT pts[3];
2655         pts[0].x = x;
2656         pts[0].y = y;
2657         pts[1].x = w;
2658         pts[1].y = h;
2659         pts[2].x = ptCursor.x;
2660         pts[2].y = ptCursor.y;
2661         DoScale(hdc, pts, 3);
2662         //DBW("%d,%d %d,%d,%d,%d -> %d,%d %d,%d,%d,%d", ptCursor.x, ptCursor.y, x, y, w, h, pts[2].x, pts[2].y, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
2663         x = pts[0].x;
2664         y = pts[0].y;
2665         w = pts[1].x;
2666         h = pts[1].y;
2667         ptCursor.x = pts[2].x;
2668         ptCursor.y = pts[2].y;
2669 #endif
2670
2671         // capture image
2672
2673         int wlen = (w*3+3)&~3;
2674
2675         /* \8f\91\82«\8d\9e\82Ý\97p\83o\83b\83t\83@\82Ì\83T\83C\83Y\8cv\8eZ */
2676         DWORD dwFSize = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER) + wlen * h;
2677
2678         /* \83o\83b\83t\83@\8am\95Û\82Æ\83|\83C\83\93\83^\90Ý\92è */
2679         LPBYTE lpBuf = (LPBYTE)new char[dwFSize];
2680         if (!lpBuf){
2681                 goto jend;
2682         }
2683
2684         LPBITMAPFILEHEADER lpHead = (LPBITMAPFILEHEADER)lpBuf;
2685         LPBITMAPINFOHEADER lpInfo = (LPBITMAPINFOHEADER)(lpBuf+sizeof(BITMAPFILEHEADER));
2686         LPBYTE lpPixel = lpBuf+sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
2687
2688         /* 24\83r\83b\83gBMP\83t\83@\83C\83\8b\82Ì\83w\83b\83_\8dì\90¬ */
2689         lpHead->bfType = ('M'<<8) +'B';
2690         lpHead->bfSize = dwFSize;
2691         lpHead->bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
2692         lpInfo->biSize = sizeof(BITMAPINFOHEADER);
2693         lpInfo->biWidth = w;
2694         lpInfo->biHeight = h;
2695         lpInfo->biPlanes = 1;
2696         lpInfo->biBitCount = 24;
2697
2698         HBITMAP hBmp = CreateCompatibleBitmap(hdc, w, h);
2699         if (hBmp){
2700                 HDC hdcMem = CreateCompatibleDC(hdc);
2701                 if (hdcMem){
2702                         HDC hOld = (HDC)SelectObject(hdcMem, hBmp);
2703                         if (hOld!=(HDC)GDI_ERROR){
2704                                 BOOL r = BitBlt(hdcMem, 0, 0, w, h, hdc, x, y, SRCCOPY);
2705                                 SelectObject(hdcMem, hOld);
2706                                 if (r){
2707 //                                      int lines = GetDIBits(hdc, hBmp, 0, h, NULL, (LPBITMAPINFO)lpInfo, DIB_RGB_COLORS);
2708                                         int lines = GetDIBits(hdc, hBmp, 0, h, lpPixel, (LPBITMAPINFO)lpInfo, DIB_RGB_COLORS);
2709                                         if (lines!=0){
2710                                                 ok = true;
2711                                         } else {
2712                                                 dbw("GetDIBits error??? %d h=%d w=%d bfSize=%d", GetLastError(), h, w, dwFSize);
2713                                         }
2714                                 } else {
2715 //                                              dbw("BitBlt error??? %d", GetLastError());
2716                                 }
2717                         }
2718                         DeleteObject(hdcMem);
2719                 }
2720                 DeleteObject(hBmp);
2721         }
2722
2723         hdc.reset();
2724
2725         if (ok){
2726                 ok = false;
2727
2728                 //TCHAR path[sizeof(AMODIPath)+40];
2729                 TCHAR *path = ImageTextPath;
2730                 size_t path_size = sizeof(ImageTextPath);
2731                 size_t len;
2732                 if (ExtAMODI){
2733                         len = _tcslen(AMODIPath);
2734                         _tcscpy(path, AMODIPath);
2735                 } else {
2736                         memset(path, 0, path_size);
2737                         len = GetTempPath((DWORD)path_size, path);
2738                 }
2739                 if (len>0){
2740                         // send image to AMODI
2741                         SYSTEMTIME t;
2742                         GetLocalTime(&t);
2743                         if (ExtAMODI){
2744                                 wsprintf(path+len, /*path_size-len,*/ _T("\\%04d-%02d-%02d-%02d%02d%02d-(%d,%d)-n%d.bmp"),
2745                                         t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond, ptCursor.x, ptCursor.y, NumPrevWords );
2746                         } else {
2747                                 wsprintf(path+len, /*path_size-len,*/ _T("\\amodi\\%04d-%02d-%02d-%02d%02d%02d-n%d.bmp"),
2748                                         t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond, NumPrevWords );
2749                                 SendAMODI(WMCD_SETPOINT, (char*)&ptCursor, sizeof(ptCursor));
2750                         }
2751                         HANDLE fh = CreateFile(path,  GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2752                         if (fh!=INVALID_HANDLE_VALUE){
2753                                 DWORD dwSize;
2754                                 WriteFile(fh, lpBuf, dwFSize, &dwSize, NULL);
2755                                 CloseHandle(fh);
2756                                 SaveImageTime = GetTickCount();
2757
2758                                 if (capture_page){
2759                                         ok = true;
2760                                 } else {
2761                                         len = (int)_tcslen(path);
2762                                         _tcsncat(path+len, _T(".txt"), path_size-len);
2763                                         if (non_block){
2764                                                 CaptureImageBlocking = true;
2765                                         } else {
2766                                                 if (WaitAndGetResult(path, 3000))
2767                                                         ok = true;
2768                                         }
2769                                 }
2770                         }
2771                 }
2772         }
2773         delete[] lpBuf;
2774
2775 jend:
2776         if (!CaptureImageBlocking){
2777                 if (!capture_page){
2778                         CallbackMain(DCH_END | (MoveSendMode ? DCH_MOVESEND : 0), NULL, 0, hwnd );
2779                 }
2780         }
2781
2782         return ok;
2783 }
2784
2785 bool WaitAndGetResult(const TCHAR *path, unsigned waittime)
2786 {
2787         bool ok = false;
2788
2789         // wait and get text from AMODI
2790
2791         HANDLE fh = WaitForResult(path, waittime);
2792
2793         CaptureImageBlocking = false;
2794
2795         if (fh==INVALID_HANDLE_VALUE){
2796                 DBW("file open timeout");
2797                 CheckAMODIAlive();
2798         } else {
2799                 DWORD size = GetFileSize(fh, NULL);
2800                 if (size>0){
2801                         unsigned bufsize = size+sizeof(wchar_t);
2802                         char *text = new char[bufsize];
2803                         if (text){
2804                                 DWORD rbyte;
2805                                 if (ReadFile(fh, text, size, &rbyte, NULL)){
2806                                         if (rbyte==size){
2807                                                 *(wchar_t*)&text[size] = '\0';
2808                                                 // text\82Ì\82P\8ds\96Ú\82Í\89ð\90Í\8fî\95ñ
2809                                                 // format
2810                                                 // (\83}\83E\83X\83J\81[\83\\83\8b\82Ì\82 \82é\83e\83L\83X\83g\88Ê\92u[\95\8e\9a\96Ú zero-index])
2811                                                 int loc = 0;
2812                                                 int col = 0;
2813                                                 wchar_t *p = (wchar_t*)text;
2814                                                 while (*p){
2815                                                         wchar_t c = *p++;
2816                                                         if (c=='\n'){
2817                                                                 break;
2818                                                         }
2819                                                         if (col==0){
2820                                                                 loc = _wtoi(p);
2821                                                                 col++;
2822                                                                 while (iswdigit(*p)) p++;
2823                                                         }
2824                                                 }
2825
2826                                                 DBW("%d:%ws", loc, p);
2827                                                 CallbackMain(DCH_HITTEXT2, p, bufsize - (int)((char*)p-text), (HWND)loc);
2828
2829                                                 ok = true;
2830                                         }
2831                                 }
2832                                 delete[] text;
2833                         }
2834                 }
2835                 CloseHandle(fh);
2836                 DeleteFile(path);
2837         }
2838         CallbackMain(DCH_END | (MoveSendMode ? DCH_MOVESEND : 0), NULL, 0, NULL );
2839         return ok;
2840 }
2841
2842 HANDLE WaitForResult(const TCHAR *path, unsigned waittime)
2843 {
2844         HANDLE fh = INVALID_HANDLE_VALUE;
2845
2846         while (1){
2847                 fh = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
2848                 if (fh!=INVALID_HANDLE_VALUE)
2849                         break;
2850
2851                 DWORD now = GetTickCount();
2852                 if (now-SaveImageTime > waittime)
2853                         break;
2854
2855                 Sleep(10);
2856         }
2857
2858         return fh;
2859 }
2860
2861 #define APPNAME _T("Auto MODI")
2862
2863 static HWND hwndFind;
2864 static BOOL CALLBACK EnumWindowsProc( HWND hwnd, LPARAM lParam )
2865 {
2866         TCHAR wndname[80];
2867         if (GetWindowText(hwnd, wndname, tsizeof(wndname))<0){
2868                 return TRUE;
2869         }
2870         if (_tcscmp(wndname, APPNAME)){ return TRUE; }
2871
2872         COPYDATASTRUCT cd;
2873         cd.dwData = WMCD_EXISTCHECK;
2874         cd.lpData = (void*)APPNAME;
2875         cd.cbData = (DWORD)(_tcslen(APPNAME)+1)*sizeof(TCHAR);
2876         if ( SendMessage( hwnd, WM_COPYDATA, 0, (LPARAM)&cd ) )
2877         {
2878                 // found
2879                 hwndFind = hwnd;
2880                 return FALSE;
2881         }
2882         return TRUE;
2883 }
2884
2885 HWND FindAMODI()
2886 {
2887         hwndFind = NULL;
2888         EnumWindows(EnumWindowsProc, 0);
2889         return hwndFind;
2890 }
2891
2892 int SendAMODI(int cmd, const char *data, int len)
2893 {
2894         COPYDATASTRUCT cd;
2895         cd.dwData = cmd;
2896         cd.lpData = (void*)data;
2897         cd.cbData = len;
2898         return (int)SendMessage(hwndAMODI, WM_COPYDATA, 0, (LPARAM)&cd);
2899 }
2900
2901 void CheckAMODIAlive()
2902 {
2903         CallbackMain(DCH_LAUNCH_AMODI, NULL, 0, 0);
2904 }
2905
2906 void SendMoveMessage()
2907 {
2908 #if MOVESEND_POST
2909         PostMessage(hwndCallback, WM_MOVESEND, MouseMoving ? 0 : -1, 0);
2910 #else
2911 //      CallbackMain(DCH_MOVESEND, pt, sizeof(*pt), 0);
2912         MouseMoving = true;
2913         if (SendMoveEvent) SetEvent(SendMoveEvent);
2914 #endif
2915 }
2916 void SendCancelMove()
2917 {
2918 #if MOVESEND_POST
2919         PostMessage(hwndCallback, WM_MOVESEND, MouseMoving ? 0 : -1, 0);
2920 #else
2921 //      CallbackMain(DCH_MOVESEND, NULL, 0, (HWND)-1);
2922         MouseMoving = false;
2923         if (SendMoveEvent) SetEvent(SendMoveEvent);
2924 #endif
2925 }
2926
2927 #if !MOVESEND_POST
2928 // main program\82ÌWindows message\8f\88\97\9d\82ª\8fd\82¢\82Æ\81ACalblackMain\82à\8fd\82­\82È\82é\82½\82ß\81A
2929 // mouse move\82Í\95Êthread\82Å\8f\88\97\9d
2930 DWORD WINAPI SendMoveThread(LPVOID vdParam)
2931 {
2932         while(1){
2933                 if (WaitForSingleObject(SendMoveEvent, INFINITE) != WAIT_OBJECT_0){
2934                         break;
2935                 }
2936                 CallbackMain(DCH_MOVESEND, NULL, 0, (HWND)(MouseMoving ? 0 : -1));
2937         }
2938         return 0;
2939 }
2940 #endif
2941
2942 #if EXC_WOW64 && defined(_M_X64)
2943 void CheckWOW64()
2944 {
2945         typedef BOOL (WINAPI *FNIsWow64Process)(HANDLE hProcess, PBOOL Wow64Process);
2946
2947         FNIsWow64Process _IsWow64Process = (FNIsWow64Process)GetProcAddress(GetModuleHandle("kernel32"),"IsWow64Process");
2948         if (_IsWow64Process){
2949                 BOOL flag = FALSE;
2950                 if (_IsWow64Process(hProcess, &flag)){
2951                         fWow64 = int_bool(flag);
2952                 }
2953         }
2954 }
2955 #endif
2956
2957 bool EnablePrivilege(LPTSTR lpszPrivilege, bool bEnable)
2958 {
2959         BOOL             bResult;
2960         LUID             luid;
2961         HANDLE           hToken;
2962         TOKEN_PRIVILEGES tokenPrivileges;
2963
2964         if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
2965                 return false;
2966         
2967         if (!LookupPrivilegeValue(NULL, lpszPrivilege, &luid)) {
2968                 CloseHandle(hToken);
2969                 return false;
2970         }
2971
2972         tokenPrivileges.PrivilegeCount           = 1;
2973         tokenPrivileges.Privileges[0].Luid       = luid;
2974         tokenPrivileges.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
2975         
2976         bResult = AdjustTokenPrivileges(hToken, FALSE, &tokenPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
2977         
2978         CloseHandle(hToken);
2979
2980         return bResult && GetLastError() == ERROR_SUCCESS;
2981 }
2982
2983 /*======================================================================//
2984 //      DllMain
2985 //----------------------------------------------------------------------//
2986 // Description:
2987 //
2988 // Arguments:
2989 //
2990 // Return Value:
2991 //
2992 //======================================================================*/
2993 #ifdef _MSC_VER
2994 BOOL WINAPI DllMain(HINSTANCE hInst, DWORD reason, LPVOID )
2995 #else
2996 int WINAPI DllEntryPoint(HINSTANCE hInst, DWORD reason, LPVOID)
2997 #endif
2998 {
2999         switch ( reason ){
3000                 case DLL_PROCESS_ATTACH:
3001                         hInstance = hInst;
3002                         idProcess = GetCurrentProcessId();
3003                         for (int i=0;i<2;i++){
3004                                 hProcess = OpenProcess( PROCESS_ALL_ACCESS|PROCESS_VM_WRITE|PROCESS_VM_OPERATION, TRUE, idProcess );
3005                                 if ( hProcess ){
3006 #if USE_DBW
3007                                         DBW("Attach %d(%08X)-%d : %08X", idProcess, hProcess, attach++,_ExtTextOutA);
3008 #endif
3009                                         break;
3010                                 } else {
3011                                         DBW("OpenProcess Error: %08X %d", idProcess, GetLastError());
3012                                         if (i==0){
3013                                                 if (!EnablePrivilege(SE_DEBUG_NAME, true)) {
3014                                                         break;  // failed
3015                                                 }
3016                                         }
3017                                 }
3018                         }
3019 #if EXC_WOW64 && defined(_M_X64)
3020                         CheckWOW64();
3021 #ifdef _WIN64
3022                         if (fWow64){
3023                                 DBW("WOW64 true");
3024                                 return FALSE;
3025                         }
3026 #else
3027                         if (!fWow64){
3028                                 DBW("WOW64 false");
3029                                 return FALSE;
3030                         }
3031 #endif
3032                         DBW("fWow64=%d", fWow64);
3033 #endif
3034                         if (siPageSize==0){
3035                                 SYSTEM_INFO si;
3036                                 GetSystemInfo( &si );
3037                                 siPageSize = si.dwPageSize;
3038                         }
3039                         hInstSHCore = LoadLibrary(_T("shcore.dll"));
3040 #if !MOVESEND_POST
3041                         SendMoveEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
3042                         CreateThread(NULL , 0 , SendMoveThread , NULL , 0 , &SendMoveThreadId);
3043 #endif
3044                         break;
3045                 case DLL_PROCESS_DETACH:
3046 //                      UNPROTECT_SHARE();
3047 #if !MOVESEND_POST
3048                         if (SendMoveEvent){
3049                                 CloseHandle(SendMoveEvent);
3050                                 SendMoveEvent = NULL;
3051                         }
3052 #endif
3053                         if (hInstSHCore){
3054                                 FreeLibrary(hInstSHCore);
3055                                 hInstSHCore = NULL;
3056                         }
3057 #if USE_DBW
3058                         DBW("Detach %d-%d", GetCurrentProcessId(),--attach);
3059 #endif
3060                         if ( hProcess ){
3061                                 CloseHandle( hProcess );
3062                         }
3063                         break;
3064         }
3065         return TRUE;
3066 }
3067 //---------------------------------------------------------------------------
3068 static HWND hWin = NULL;
3069 static const char *clsname = "TDbgMsgForm";
3070 static const char *winname = "Debug Messenger";
3071 void dbw( const char *format, ... )
3072 {
3073         if ( !hWin ){
3074                 hWin = FindWindowA( clsname, winname );
3075                 if ( !hWin ) return;
3076         }
3077         va_list ap;
3078         va_start( ap, format );
3079         char buf[ 2048 ];
3080 #ifdef _WIN64
3081         strcpy(buf, "x64:");
3082         wvsprintfA( buf+4, format, ap );
3083 #else
3084         wvsprintfA( buf, format, ap );
3085 #endif
3086         COPYDATASTRUCT cds;
3087         cds.dwData = 1; // Indicate String
3088         cds.cbData = (DWORD)strlen(buf);
3089         cds.lpData = buf;
3090         SendMessage( hWin, WM_COPYDATA, NULL, (LPARAM)&cds );
3091         va_end( ap );
3092 }