OSDN Git Service

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