OSDN Git Service

初期化処理の改善:amodi.exeの起動を正しく検知できず、amodiが使用できなくなる場合の対応
[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 //              DWORD startTime = GetTickCount();
428                 int r = WaitForInputIdle( pi.hProcess, waittime );
429                 ret = r==0;
430                 if (!ret){
431                         dbw("CreateProcess: %d, 0x%X", r, GetLastError());
432                 } else {
433 //                      dbw("CreateProcess: %d", GetTickCount() - startTime);
434                 }
435         }
436         CloseHandle( pi.hProcess );
437         return ret;
438 }
439 static const char *MyWinTitle = "<Processing...>";
440 HANDLE WinExecEx( const char *cmd, int show, const char *dir, const char *title )
441 {
442         STARTUPINFO sui;
443         memset( &sui, 0, sizeof(STARTUPINFO) );
444         sui.cb = sizeof(STARTUPINFO);
445         sui.dwFlags = STARTF_USESHOWWINDOW;
446         sui.wShowWindow = (WORD)show;
447         sui.lpTitle = (LPTSTR)(title ? title : MyWinTitle);
448         PROCESS_INFORMATION pi;
449         if ( !CreateProcess( NULL, (LPTSTR)cmd, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, dir, &sui, &pi ) )
450                 return NULL;
451         return pi.hProcess;
452 }
453 bool LaunchPdic()
454 {
455         TAppIni *ini = new TAppIni;
456         if ( !ini->hroot ){
457                 delete ini;
458                 return false;
459         }
460
461         AnsiString s = ini->ReadString( PFS_COMMON, PFS_PATH, "" );
462         delete ini;
463         if ( s.Length() == 0 )
464                 return false;
465         s += "\\";
466         s += NAME_PDICEXE;
467
468         return _WinExec( s.c_str(), SW_SHOWNOACTIVATE|SW_MINIMIZE, 500 );
469 }
470 bool MODIInstalled()
471 {
472         HANDLE h = WinExecEx(EXMODIST_EXE_PATH, SW_HIDE);
473         if (!h){
474                 dbw("ExMODist exec error: %d", GetLastError());
475                 return false;
476         }
477         WaitForSingleObject(h, INFINITE);
478         DWORD exitCode = 0;
479         BOOL r = GetExitCodeProcess(h, &exitCode);
480         CloseHandle(h);
481         if (r){
482                 return exitCode ? true : false;
483         }
484         return false;
485 }
486 bool AMODIRunable()
487 {
488         return MODIInstalled() && GetDNFVersion()>=451;
489 }
490 bool LaunchAMODI()
491 {
492         if (!AMODIRunable()) return false;
493
494         int show = 
495 #ifdef _DEBUG
496                 SW_SHOWNOACTIVATE|SW_MINIMIZE;
497 #else
498                 SW_HIDE;
499 #endif
500         if (!_WinExec( AMODI_EXE_PATH, show, 300))
501                 return false;
502
503         HWND hwnd = NULL;
504         for (int i=0;i<10;i++){
505                 hwnd = FindAMODI();
506                 if (hwnd)
507                         break;
508                 Sleep(10);
509         }
510         return hwnd!=NULL;
511 }
512 void TerminateAMODI()
513 {
514         HWND hwnd = FindAMODI();
515         if (hwnd){
516                 PostMessage(hwnd, WM_CLOSE, 0, 0);
517         }
518 }
519 void ShowAMODI()
520 {
521         HWND hwnd = FindAMODI();
522         if (hwnd){
523                 ShowWindow(hwnd, SW_SHOW);
524                 ShowWindow(hwnd, SW_RESTORE);
525         }
526 }
527 static HWND hwndFind;
528 static const char *findClass = NULL;
529 static const char *findWindow = NULL;
530 static const char *findAppName = NULL;
531 static BOOL CALLBACK EnumWindowsProc( HWND hwnd, LPARAM lParam )
532 {
533         char buf[80];
534         
535         if (findClass){
536                 if ( !GetClassName( hwnd, buf, sizeof(buf)-1 ) ) return TRUE;
537                 //DBW("class: %s", buf);
538                 if (strcmp( buf, findClass )) return TRUE;
539         }
540         if (findWindow){
541                 if (GetWindowText(hwnd, buf, sizeof(buf))<0){
542                         return TRUE;
543                 }
544                 //DBW("wnd: %s", buf);
545                 if (strcmp(buf, findWindow)){ return TRUE; }
546         }
547
548         if (findAppName){
549                 COPYDATASTRUCT cd;
550                 cd.dwData = WMCD_EXISTCHECK;
551                 cd.lpData = (void*)findAppName;
552                 cd.cbData = strlen(findAppName)+1;
553                 if ( SendMessage( hwnd, WM_COPYDATA, 0, (LPARAM)&cd ) ){
554                         goto jfound;
555                 }
556         } else {
557 jfound:
558                 hwndFind = hwnd;
559                 return FALSE;
560         }
561         return TRUE;
562 }
563
564 HWND FindApp(const char *clsname, const char *wndname, const char *appname)
565 {
566         hwndFind = NULL;
567         findClass = clsname;
568         findWindow = wndname;
569         findAppName = appname;
570         EnumWindows( (FARPROC)EnumWindowsProc, 0 );
571         return hwndFind;
572 }
573 HWND FindPrev()
574 {
575         return FindApp("TDCHookMainForm", NULL, APPNAME);
576 }
577 int CheckVersion(HWND hwnd)
578 {
579         int ver = SendMessage(hwnd, WM_GET_VERSION, 0, 0);
580         if (ver==0){ return -1; }       // older than ver.2.0
581         return ver - VersionValue;
582 }
583 HWND FindAMODI()
584 {
585         static const char APPNAME_AMODI[] =  "Auto MODI";
586         return FindApp(NULL, APPNAME_AMODI, APPNAME_AMODI);
587 }
588 static HWND hwndFound;
589 static BOOL CALLBACK EnumWindowsProcPS( HWND hwnd, LPARAM lParam )
590 {
591         char clsname[80];
592         if ( !GetClassName( hwnd, clsname, sizeof(clsname)-1 ) ) return TRUE;
593         if ( strcmp( clsname, "PSPOPUPWIN" )
594                 && strcmp( clsname, "PSMENU" ) ) return TRUE;
595
596         hwndFound = hwnd;
597         
598         return FALSE;
599 }
600 // PDIC\82Ìpopup window\82ð\92T\82·
601 HWND FindPopupWindow( )
602 {
603         hwndFound = NULL;
604         EnumWindows( (WNDENUMPROC)EnumWindowsProcPS, 0 );
605         return hwndFound;
606 }
607
608 void ShowManual(HWND hwnd)
609 {
610         AnsiString dir = ExtractFileDir( Application->ExeName );
611         ShellExecute( hwnd, "open", NAME_DKPPTXT, NULL, dir.c_str(), SW_SHOW ); 
612 }
613
614 void ShowLatestVersion()
615 {
616 #if __PROTO
617         const char *url = "http://pdic.la.coocan.jp/unicode/dev.html";
618 #else
619         const char *url = "http://dokopop.osdn.jp/";
620 #endif
621         ShellExecute( NULL, _T("open"), url, NULL, NULL, SW_SHOW );
622 }
623
624 // \8eQ\8dl
625 // https://msdn.microsoft.com/ja-jp/library/hh925568(v=vs.110).aspx#net_d
626 // http://www.atmarkit.co.jp/ait/articles/1210/26/news086.html
627 unsigned GetDNFVersion()
628 {
629         HKEY dnfKey;
630         if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\NET Framework Setup\\NDP", 0, KEY_READ, &dnfKey ) == ERROR_SUCCESS ){
631                 int version = 0;
632                 HKEY verKey;
633                 if ( RegOpenKeyEx( dnfKey, "v4.0", 0, KEY_READ, &verKey ) == ERROR_SUCCESS ){
634                         version = 400;
635                         RegCloseKey(verKey);
636                         if ( RegOpenKeyEx( dnfKey, "v4", 0, KEY_READ, &verKey ) == ERROR_SUCCESS ){
637                                 HKEY fullKey;
638                                 if ( RegOpenKeyEx( verKey, "Full", 0, KEY_READ, &fullKey ) == ERROR_SUCCESS ){
639                                         DWORD dwType = REG_DWORD;
640                                         DWORD dwByte = 4;
641                                         DWORD dwValue = 0;
642                                         if ( RegQueryValueEx( fullKey, "Release", NULL, &dwType, (BYTE*)&dwValue, &dwByte) == ERROR_SUCCESS){
643 #if 0
644                                                 if (dwValue >= 394254){
645                                                         version = 461;
646                                                 } else
647                                                 if (dwValue >= 393295){
648                                                         version = 460;
649                                                 } else
650                                                 if (dwValue >= 379893){
651                                                         version = 452;
652                                                 } else
653 #endif
654                                                 if (dwValue >= 378675){
655                                                         version = 451;
656                                                 } else
657                                                 if (dwValue >= 378389){
658                                                         version = 450;
659                                                 }
660                                         }
661                                         RegCloseKey( fullKey );
662                                 }
663                                 RegCloseKey( verKey );
664                         }
665                 } else
666                 if ( RegOpenKeyEx( dnfKey, "v3.5", 0, KEY_READ, &verKey ) == ERROR_SUCCESS ){
667                         version = 350;
668                         RegCloseKey(verKey);
669                 }
670                 RegCloseKey(dnfKey);
671                 return version;
672         }
673         return 0;
674 }
675
676 static HWND hWin = NULL;
677 static const char *clsname = "TDbgMsgForm";
678 static const char *winname = "Debug Messenger";
679 void dbw( const char *format, ... )
680 {
681         if ( !hWin ){
682                 hWin = FindWindowA( clsname, winname );
683                 if ( !hWin ) return;
684         }
685         va_list ap;
686         va_start( ap, format );
687         char buf[ 2048 ];
688         wvsprintf( buf, format, ap );
689         COPYDATASTRUCT cds;
690         cds.dwData = 1; // Indicate String
691         cds.cbData = strlen(buf);
692         cds.lpData = buf;
693         SendMessage( hWin, WM_COPYDATA, NULL, (LPARAM)&cds );
694         va_end( ap );
695 }
696