OSDN Git Service

ec8168cfb3aabdec61fbb077f9dcd37f3b56c2c1
[dokopop/dokopop.git] / DCHookTest / Util.cpp
1 //---------------------------------------------------------------------------
2 #include <vcl.h>
3 #pragma hdrstop
4 #include <tchar.h>
5 #include "prgconfig.h"
6 #include "Util.h"
7 #include "prgprof.h"
8
9 //---------------------------------------------------------------------------
10 const char *AppName = "DokoPop";
11 const char *StrVersion = "Ver.2.0.27";
12 int VersionValue = 0x02001B;    // xxyyzz -> xx.yy.zz x=major y=minor(0-255) z=release(0-255)
13
14 #pragma package(smart_init)
15
16 #ifdef USE_UNICODE
17 const char APPNAME[] = {"DokoPop/Unicode"};
18 #else
19 const char APPNAME[] = {"DokoPop"};
20 #endif
21
22 const char *AMODI_EXE_PATH = "amodi.exe";
23 //const char *AMODI_EXE_PATH = "\\src\\amodi\\amodi\\bin\\Debug\\amodi.exe";
24
25 const char *EXMODIST_EXE_PATH = "ExMODIst.exe";
26
27 bool WindowsNT = true;
28 bool fWow64 = false;
29
30 HWND hwndMain = NULL;
31
32 HKEY OpenKey( HKEY hkey, const char *keyname )
33 {
34         HKEY newkey;
35         if ( RegOpenKeyEx( hkey, keyname, 0, KEY_ALL_ACCESS, &newkey ) == ERROR_SUCCESS ){
36                 return newkey;
37         }
38         return NULL;
39 }
40
41 HKEY CreateKey( HKEY hkey, const char *keyname )
42 {
43         HKEY newkey;
44         DWORD result;
45         if ( RegCreateKeyEx( hkey, keyname, 0, (LPTSTR)keyname, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &newkey, &result ) == ERROR_SUCCESS ){
46                 return newkey;
47         }
48         return NULL;
49 }
50 DWORD GetValueLength( HKEY hkey, const char *name )
51 {
52         DWORD len = 0;
53         if ( RegQueryValueEx( hkey, (LPTSTR)name, 0, NULL, NULL, &len ) == ERROR_SUCCESS ){
54                 return len;
55         }
56         return 0L;
57 }
58 #if 0
59 DWORD ReadInteger( HKEY hkey, const char *name, DWORD val )
60 {
61         DWORD len = sizeof(DWORD);
62         DWORD v;
63         if ( RegQueryValueEx( hkey, (LPTSTR)name, 0, NULL, (LPBYTE)&v, &len ) == ERROR_SUCCESS ){
64                 return v;
65         }
66         return val;
67 }
68 AnsiString ReadString( HKEY hkey, const char *name, const char *def )
69 {
70         DWORD len = GetValueLength( hkey, name );
71         if ( len ){
72                 char *buf = new char[ len ];
73                 if ( RegQueryValueEx( hkey, (LPTSTR)name, 0, NULL, (LPBYTE)buf, &len ) == ERROR_SUCCESS ){
74                         AnsiString s = buf;
75                         delete buf;
76                         return s;
77                 }
78         }
79         return def;
80 }
81 #endif
82 TMyIni::TMyIni( HKEY root, const char *soft, bool can_create )
83 {
84         hroot = can_create ? CreateKey( root, soft ) : OpenKey( root, soft );
85 }
86 TMyIni::~TMyIni()
87 {
88         if ( hroot ){
89                 RegCloseKey( hroot );
90         }
91 }
92 void TMyIni::WriteInteger( const char *section, const char *key, int val )
93 {
94         HKEY hkey = CreateKey( hroot, section );
95         if ( hkey ){
96                 RegSetValueEx( hkey, (LPCTSTR)key, 0, REG_DWORD, (LPBYTE)&val, sizeof(DWORD) );
97                 RegCloseKey( hkey );
98         }
99 }
100 int TMyIni::ReadInteger( const char *section, const char *key, int val )
101 {
102         HKEY hkey = OpenKey( hroot, section );
103         if ( hkey ){
104                 DWORD len = sizeof(DWORD);
105                 DWORD v;
106                 if ( RegQueryValueEx( hkey, (LPTSTR)key, 0, NULL, (LPBYTE)&v, &len ) == ERROR_SUCCESS ){
107                         return v;
108                 }
109         }
110         return val;
111 }
112 void TMyIni::WriteString( const char *section, const char *key, const char *str )
113 {
114         HKEY hkey = NULL;
115         if ( section )
116                 hkey = CreateKey( hroot, section );
117         if ( !section || hkey ){
118                 RegSetValueEx( hkey, (LPCTSTR)key, 0, REG_SZ, (LPBYTE)str, lstrlen(str)+1 );
119                 RegCloseKey( hkey );
120         }
121 }
122 AnsiString TMyIni::ReadString( const char *section, const char *key, const char *str )
123 {
124         HKEY hkey = NULL;
125         if ( section )
126                 hkey = OpenKey( hroot, section );
127         if ( !section || hkey ){
128                 DWORD len = GetValueLength( hkey, key );
129                 if ( len ){
130                         char *buf = new char[ len ];
131                         if ( RegQueryValueEx( hkey, (LPTSTR)key, 0, NULL, (LPBYTE)buf, &len ) == ERROR_SUCCESS ){
132                                 AnsiString s = buf;
133                                 delete[] buf;
134                                 return s;
135                         }
136                         delete[] buf;
137                 }
138         }
139         return str;
140 }
141
142 #define NAMEBUFFSIZE    512
143 BOOL QueryInfoKey( HKEY hkey, DWORD *maxvalue, DWORD *maxdata );
144 BOOL EnumValue( HKEY hkey, DWORD index, AnsiString &name, void *pbuffer=NULL, DWORD *maxlen=NULL, DWORD *type=NULL );
145
146 void TMyIni::ReadValues( const char *section, TStrings *strs )
147 {
148         strs->Clear();
149
150         HKEY hkey = OpenKey( hroot, section );
151         if ( hkey ){
152                 DWORD maxvaluename;
153                 DWORD maxvaluedata;
154                 if ( !QueryInfoKey( hkey, &maxvaluename, &maxvaluedata ) ){
155                         // \93®\82©\82È\82¢\81I\81I\81I
156                         maxvaluename = 128;
157                         maxvaluedata = 4096;    // \93K\93\96\81I\81I
158                 }
159
160                 AnsiString _entry;
161                 char *buf = new char[ maxvaluedata + 1 ];
162                 for ( int i=0;;i++ ){
163                         DWORD maxlen = maxvaluedata + 1;
164                         if ( !EnumValue( hkey, i, _entry, buf, &maxlen ) )
165                                 break;
166                         strs->Add( _entry );
167                 }
168                 delete[] buf;
169         }
170 }
171
172 //
173 // TAppIni class
174 //
175 TAppIni::TAppIni()
176         :super(HKEY_CURRENT_USER, REG_PDICEXE, false)
177 {
178 #ifdef USE_UNICODE
179         if (!hroot){
180                 super::super(HKEY_CURRENT_USER, REG_PDICEXE, false);
181         }
182 #endif
183 }
184
185 const char *sLeft = "Left";
186 const char *sTop = "Top";
187 const char *sWidth  = "Width";
188 const char *sHeight = "Height";
189
190 void LoadForm( const char *section, TForm *form, HWND hwnd )
191 {
192         RECT rc;
193         if ( hwnd ){
194                 GetWindowRect( hwnd, &rc );
195         } else {
196                 rc.left = rc.top = 0;
197         }
198         form->Left = Ini->ReadInteger(section, sLeft, form->Left) + rc.left;
199         form->Top = Ini->ReadInteger(section, sTop, form->Top ) + rc.top;
200         RECT rcScr;
201         GetScreenSize(form->Handle?form->Handle:hwnd, &rcScr);
202         int sx = rcScr.right - rcScr.left;
203         int sy = rcScr.bottom - rcScr.top;
204
205         switch ( form->BorderStyle ){
206         case bsSizeable:
207         case bsToolWindow:
208         case bsSizeToolWin:
209                 form->Width = Ini->ReadInteger( section, sWidth, form->Width );
210                 form->Height = Ini->ReadInteger( section, sHeight, form->Height );
211                 break;
212         }
213         // \89æ\96Ê\82Ì\8aO\82©\82Ç\82¤\82©\81H
214         if (form->Left+form->Width >= sx){
215                 // \89E\92[
216                 form->Left = sx - form->Width;
217         }
218         if (form->Left < rcScr.left){
219                 // \8d\92[
220                 form->Left = rcScr.left;
221         }
222         if (form->Top+form->Height >= sy){
223                 // \89º\92[
224                 form->Top = sy - form->Height;
225         }
226         if (form->Top < rcScr.top){
227                 // \8fã\92[
228                 form->Top = rcScr.top;
229         }
230 }
231 void SaveForm( const char *section, TForm *form, HWND hwnd )
232 {
233         RECT rc;
234         if ( hwnd ){
235                 GetWindowRect( hwnd, &rc );
236         } else {
237                 rc.left = rc.top = 0;
238         }
239         Ini->WriteInteger( section, sLeft, form->Left - rc.left );
240         Ini->WriteInteger( section, sTop, form->Top - rc.top );
241         switch ( form->BorderStyle ){
242         case bsSizeable:
243         case bsToolWindow:
244         case bsSizeToolWin:
245                 Ini->WriteInteger( section, sWidth, form->Width );
246                 Ini->WriteInteger( section, sHeight, form->Height );
247                 break;
248         }
249 }
250
251 BOOL QueryInfoKey( HKEY hkey, DWORD *maxvalue, DWORD *maxdata )
252 {
253         char *classname = new char[ 512 ];      // \82±\82ñ\82È\82à\82ñ\82Å\82¢\82¢\82©\82È\82\9f\81H
254         DWORD classnamesize = 512;
255         DWORD SubKeys;
256         DWORD MaxSubKey;
257         DWORD MaxClass;
258         DWORD Values;
259         DWORD MaxValueName;
260         DWORD MaxValueData;
261         DWORD SecurityDescriptor;
262         FILETIME LastWriteTime;
263         if ( ::RegQueryInfoKey( hkey, classname, &classnamesize,
264                 NULL,
265                 &SubKeys,
266                 &MaxSubKey,
267                 &MaxClass,
268                 &Values,
269                 &MaxValueName,
270                 &MaxValueData,
271                 &SecurityDescriptor,
272                 &LastWriteTime
273                 ) != ERROR_SUCCESS ){
274                 delete[] classname;
275                 return FALSE;
276         }
277         if ( maxvalue )
278                 *maxvalue = MaxValueName;
279         if ( maxdata )
280                 *maxdata = MaxValueData;
281         delete[] classname;
282         return TRUE;
283 }
284 BOOL EnumValue( HKEY hkey, DWORD index, AnsiString &name, void *pbuffer, DWORD *maxlen, DWORD *type )
285 {
286         char *buffer = new char[ NAMEBUFFSIZE ];
287         DWORD buflen = NAMEBUFFSIZE;
288         if ( RegEnumValue( hkey, index, buffer, &buflen, 0, type, (LPBYTE)pbuffer, maxlen ) == ERROR_SUCCESS ){
289                 name = buffer;
290                 delete[] buffer;
291                 return TRUE;
292         }
293         delete[] buffer;
294         return FALSE;
295 }
296 bool CheckPassword( const char *str )
297 {
298         AnsiString s;
299         if ( str ){
300                 s = str;
301         } else {
302                 s = Ini->ReadString( "Main", "PW", "" );
303         }
304         return s == "123";
305 }
306 void CheckWOW64()
307 {
308         typedef BOOL WINAPI (*FNIsWow64Process)(HANDLE hProcess, PBOOL Wow64Process);
309
310         FNIsWow64Process _IsWow64Process = (FNIsWow64Process)GetProcAddress(GetModuleHandle("kernel32"),"IsWow64Process");
311         if (_IsWow64Process){
312                 BOOL flag = FALSE;
313                 if (_IsWow64Process(GetCurrentProcess(), &flag)){
314                         fWow64 = flag;
315                 }
316         }
317 }
318 void MoveToTop( HWND hwnd )
319 {
320         if ( IsIconic( hwnd ) )
321                 ShowWindow( hwnd, SW_RESTORE );
322
323         // Undocumented way
324
325         HMODULE hUser32 = GetModuleHandle("user32");
326         if ( hUser32 ){
327                 typedef void (WINAPI *PROCSWITCHTOTHISWINDOW) (HWND, BOOL);
328                 PROCSWITCHTOTHISWINDOW SwitchToThisWindow = (PROCSWITCHTOTHISWINDOW)GetProcAddress(hUser32, TEXT("SwitchToThisWindow"));
329                 if ( SwitchToThisWindow ){
330                         SwitchToThisWindow( hwnd, true );
331                         FreeLibrary( hUser32 );
332                         return;
333                 }
334         }
335
336         FreeLibrary( hUser32 );
337
338         DWORD locktimeout;
339         /*BOOL changed = */ SystemParametersInfo( SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &locktimeout, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE );
340         SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, NULL, SPIF_UPDATEINIFILE);
341         SetForegroundWindow(hwnd);
342         SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, locktimeout, NULL, SPIF_UPDATEINIFILE);
343 }
344 // window(hwnd)\82ðhwndParent\82Ìcenter\82Ö\88Ú\93®
345 // screen\82Ì\8aO\82Ö\8fo\82é\8fê\8d\87\82Í\92²\90®\82·\82é
346 void MoveCenter( HWND hwnd, HWND hwndParent )
347 {
348         RECT rc;
349         RECT rd;
350         if (!hwndParent){
351                 hwndParent = hwndMain;  // parent\82ª\82È\82¯\82ê\82Îmain window
352         }
353         if (hwndParent){
354 #ifndef WINCE
355                 if ( IsIconic(hwndParent) ){
356                         GetScreenSize(hwndParent, &rc);
357                 } else
358 #endif
359                 {
360                         ::GetWindowRect( hwndParent, &rc );
361                 }
362         } else {
363                 GetScreenSize(hwnd, &rc);
364         }
365         RECT rcScr;
366         GetScreenSize(hwnd, &rcScr);
367         ::GetWindowRect( hwnd, &rd );
368         int width = rd.right - rd.left;
369         int height = rd.bottom - rd.top;
370         int left = rc.left + ( ( rc.right - rc.left ) - width )/2;
371         int top = rc.top + ( ( rc.bottom - rc.top ) - height )/2;
372         if ( left < rcScr.left ){
373                 left = rcScr.left;
374         }
375         if ( top < rcScr.top ){
376                 top = rcScr.top;
377         }
378         if ( left + width > rcScr.right ){
379                 left = rcScr.right - (rd.right - rd.left);
380         }
381         if ( top + height > rcScr.bottom ){
382                 top = rcScr.bottom - (rd.bottom - rd.top);
383         }
384         ::SetWindowPos( hwnd, (HWND)NULL, left & ~7, top, 0, 0, SWP_NOSIZE | SWP_NOZORDER );
385 }
386 void GetScreenSize(HWND hwndBase, RECT *rcWork, RECT *rcScreen)
387 {
388 #if 0
389         if (!PdicMain){
390                 __assert(false);
391                 MLFXPC_CMN_ASSERT(false);
392                 if (rcScreen){
393                         SetRect(rcScreen, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
394                 }
395                 if (rcWork){
396                         SystemParametersInfo(SPI_GETWORKAREA, 0, rcWork, 0);
397                 }
398                 return;
399         }
400 #endif
401         //__assert(hwndMain!=NULL);
402         HMONITOR hMonitor = MonitorFromWindow(hwndBase ? hwndBase : (hwndMain ? hwndMain : GetActiveWindow()), MONITOR_DEFAULTTONEAREST);
403         //__assert(hMonitor!=NULL);
404         MONITORINFO mi;
405         memset(&mi, 0, sizeof(mi));
406         mi.cbSize = sizeof(mi);
407         GetMonitorInfo(hMonitor, &mi);
408         if (rcScreen){
409                 *rcScreen = mi.rcMonitor;
410         }
411         if (rcWork){
412                 *rcWork = mi.rcWork;
413         }
414 }
415 bool _WinExec( const char *cmd, int show, int waittime, const char *dir)
416 {
417         STARTUPINFO sui;
418         memset( &sui, 0, sizeof(STARTUPINFO) );
419         sui.cb = sizeof(STARTUPINFO);
420         sui.dwFlags = STARTF_USESHOWWINDOW;
421         sui.wShowWindow = (WORD)show;
422         sui.lpTitle = (LPTSTR)"";
423         PROCESS_INFORMATION pi;
424         if ( !CreateProcess( NULL, (LPTSTR)cmd, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, dir, &sui, &pi ) )
425                 return false;
426         bool ret = true;
427         if ( waittime ){
428 //              DWORD startTime = GetTickCount();
429                 int r = WaitForInputIdle( pi.hProcess, waittime );
430                 ret = r==0;
431                 if (!ret){
432                         dbw("CreateProcess: %d, 0x%X", r, GetLastError());
433                 } else {
434 //                      dbw("CreateProcess: %d", GetTickCount() - startTime);
435                 }
436         }
437         CloseHandle( pi.hProcess );
438         return ret;
439 }
440 static const char *MyWinTitle = "<Processing...>";
441 HANDLE WinExecEx( const char *cmd, int show, const char *dir, const char *title )
442 {
443         STARTUPINFO sui;
444         memset( &sui, 0, sizeof(STARTUPINFO) );
445         sui.cb = sizeof(STARTUPINFO);
446         sui.dwFlags = STARTF_USESHOWWINDOW;
447         sui.wShowWindow = (WORD)show;
448         sui.lpTitle = (LPTSTR)(title ? title : MyWinTitle);
449         PROCESS_INFORMATION pi;
450         if ( !CreateProcess( NULL, (LPTSTR)cmd, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, dir, &sui, &pi ) )
451                 return NULL;
452         return pi.hProcess;
453 }
454 bool LaunchPdic()
455 {
456         TAppIni *ini = new TAppIni;
457         if ( !ini->hroot ){
458                 delete ini;
459                 return false;
460         }
461
462         AnsiString s = ini->ReadString( PFS_COMMON, PFS_PATH, "" );
463         delete ini;
464         if ( s.Length() == 0 )
465                 return false;
466         s += "\\";
467         s += NAME_PDICEXE;
468
469         return _WinExec( s.c_str(), SW_SHOWNOACTIVATE|SW_MINIMIZE, 500 );
470 }
471 bool MODIInstalled()
472 {
473         HANDLE h = WinExecEx(EXMODIST_EXE_PATH, SW_HIDE);
474         if (!h){
475                 dbw("ExMODist exec error: %d", GetLastError());
476                 return false;
477         }
478         WaitForSingleObject(h, INFINITE);
479         DWORD exitCode = 0;
480         BOOL r = GetExitCodeProcess(h, &exitCode);
481         CloseHandle(h);
482         if (r){
483                 return exitCode ? true : false;
484         }
485         return false;
486 }
487 bool AMODIRunable()
488 {
489         return MODIInstalled() && GetDNFVersion()>=451;
490 }
491 bool LaunchAMODI()
492 {
493         if (!AMODIRunable()) return false;
494
495         int show = 
496 #ifdef _DEBUG
497                 SW_SHOWNOACTIVATE|SW_MINIMIZE;
498 #else
499                 SW_HIDE;
500 #endif
501         if (!_WinExec( AMODI_EXE_PATH, show, 300))
502                 return false;
503
504         HWND hwnd = NULL;
505         for (int i=0;i<10;i++){
506                 hwnd = FindAMODI();
507                 if (hwnd)
508                         break;
509                 Sleep(10);
510         }
511         return hwnd!=NULL;
512 }
513 void TerminateAMODI()
514 {
515         HWND hwnd = FindAMODI();
516         if (hwnd){
517                 PostMessage(hwnd, WM_CLOSE, 0, 0);
518         }
519 }
520 void ShowAMODI()
521 {
522         HWND hwnd = FindAMODI();
523         if (hwnd){
524                 ShowWindow(hwnd, SW_SHOW);
525                 ShowWindow(hwnd, SW_RESTORE);
526         }
527 }
528 static HWND hwndFind;
529 static const char *findClass = NULL;
530 static const char *findWindow = NULL;
531 static const char *findAppName = NULL;
532 static BOOL CALLBACK EnumWindowsProc( HWND hwnd, LPARAM lParam )
533 {
534         char buf[80];
535         
536         if (findClass){
537                 if ( !GetClassName( hwnd, buf, sizeof(buf)-1 ) ) return TRUE;
538                 //DBW("class: %s", buf);
539                 if (strcmp( buf, findClass )) return TRUE;
540         }
541         if (findWindow){
542                 if (GetWindowText(hwnd, buf, sizeof(buf))<0){
543                         return TRUE;
544                 }
545                 //DBW("wnd: %s", buf);
546                 if (strcmp(buf, findWindow)){ return TRUE; }
547         }
548
549         if (findAppName){
550                 COPYDATASTRUCT cd;
551                 cd.dwData = WMCD_EXISTCHECK;
552                 cd.lpData = (void*)findAppName;
553                 cd.cbData = strlen(findAppName)+1;
554                 if ( SendMessage( hwnd, WM_COPYDATA, 0, (LPARAM)&cd ) ){
555                         goto jfound;
556                 }
557         } else {
558 jfound:
559                 hwndFind = hwnd;
560                 return FALSE;
561         }
562         return TRUE;
563 }
564
565 HWND FindApp(const char *clsname, const char *wndname, const char *appname)
566 {
567         hwndFind = NULL;
568         findClass = clsname;
569         findWindow = wndname;
570         findAppName = appname;
571         EnumWindows( (FARPROC)EnumWindowsProc, 0 );
572         return hwndFind;
573 }
574 HWND FindPrev()
575 {
576         return FindApp("TDCHookMainForm", NULL, APPNAME);
577 }
578 int CheckVersion(HWND hwnd)
579 {
580         int ver = SendMessage(hwnd, WM_GET_VERSION, 0, 0);
581         if (ver==0){ return -1; }       // older than ver.2.0
582         return ver - VersionValue;
583 }
584 HWND FindAMODI()
585 {
586         static const char APPNAME_AMODI[] =  "Auto MODI";
587         return FindApp(NULL, APPNAME_AMODI, APPNAME_AMODI);
588 }
589 static HWND hwndFound;
590 static BOOL CALLBACK EnumWindowsProcPS( HWND hwnd, LPARAM lParam )
591 {
592         char clsname[80];
593         if ( !GetClassName( hwnd, clsname, sizeof(clsname)-1 ) ) return TRUE;
594         if ( strcmp( clsname, "PSPOPUPWIN" )
595                 && strcmp( clsname, "PSMENU" ) ) return TRUE;
596
597         hwndFound = hwnd;
598         
599         return FALSE;
600 }
601 // PDIC\82Ìpopup window\82ð\92T\82·
602 HWND FindPopupWindow( )
603 {
604         hwndFound = NULL;
605         EnumWindows( (WNDENUMPROC)EnumWindowsProcPS, 0 );
606         return hwndFound;
607 }
608
609 void ShowManual(HWND hwnd)
610 {
611         AnsiString dir = ExtractFileDir( Application->ExeName );
612         ShellExecute( hwnd, "open", NAME_DKPPTXT, NULL, dir.c_str(), SW_SHOW ); 
613 }
614
615 void ShowLatestVersion()
616 {
617 #if __PROTO
618         const char *url = "http://pdic.la.coocan.jp/unicode/dev.html";
619 #else
620         const char *url = "http://dokopop.osdn.jp/";
621 #endif
622         ShellExecute( NULL, _T("open"), url, NULL, NULL, SW_SHOW );
623 }
624
625 // \8eQ\8dl
626 // https://msdn.microsoft.com/ja-jp/library/hh925568(v=vs.110).aspx#net_d
627 // http://www.atmarkit.co.jp/ait/articles/1210/26/news086.html
628 unsigned GetDNFVersion()
629 {
630         HKEY dnfKey;
631         if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\NET Framework Setup\\NDP", 0, KEY_READ, &dnfKey ) == ERROR_SUCCESS ){
632                 int version = 0;
633                 HKEY verKey;
634                 if ( RegOpenKeyEx( dnfKey, "v4.0", 0, KEY_READ, &verKey ) == ERROR_SUCCESS ){
635                         version = 400;
636                         RegCloseKey(verKey);
637                         if ( RegOpenKeyEx( dnfKey, "v4", 0, KEY_READ, &verKey ) == ERROR_SUCCESS ){
638                                 HKEY fullKey;
639                                 if ( RegOpenKeyEx( verKey, "Full", 0, KEY_READ, &fullKey ) == ERROR_SUCCESS ){
640                                         DWORD dwType = REG_DWORD;
641                                         DWORD dwByte = 4;
642                                         DWORD dwValue = 0;
643                                         if ( RegQueryValueEx( fullKey, "Release", NULL, &dwType, (BYTE*)&dwValue, &dwByte) == ERROR_SUCCESS){
644 #if 0
645                                                 if (dwValue >= 394254){
646                                                         version = 461;
647                                                 } else
648                                                 if (dwValue >= 393295){
649                                                         version = 460;
650                                                 } else
651                                                 if (dwValue >= 379893){
652                                                         version = 452;
653                                                 } else
654 #endif
655                                                 if (dwValue >= 378675){
656                                                         version = 451;
657                                                 } else
658                                                 if (dwValue >= 378389){
659                                                         version = 450;
660                                                 }
661                                         }
662                                         RegCloseKey( fullKey );
663                                 }
664                                 RegCloseKey( verKey );
665                         }
666                 } else
667                 if ( RegOpenKeyEx( dnfKey, "v3.5", 0, KEY_READ, &verKey ) == ERROR_SUCCESS ){
668                         version = 350;
669                         RegCloseKey(verKey);
670                 }
671                 RegCloseKey(dnfKey);
672                 return version;
673         }
674         return 0;
675 }
676
677 static HWND hWin = NULL;
678 static const char *clsname = "TDbgMsgForm";
679 static const char *winname = "Debug Messenger";
680 void dbw( const char *format, ... )
681 {
682         if ( !hWin ){
683                 hWin = FindWindowA( clsname, winname );
684                 if ( !hWin ) return;
685         }
686         va_list ap;
687         va_start( ap, format );
688         char buf[ 2048 ];
689         wvsprintf( buf, format, ap );
690         COPYDATASTRUCT cds;
691         cds.dwData = 1; // Indicate String
692         cds.cbData = strlen(buf);
693         cds.lpData = buf;
694         SendMessage( hWin, WM_COPYDATA, NULL, (LPARAM)&cds );
695         va_end( ap );
696 }
697