1
2 #include "stdafx.h"
3 #include "../kilib/kilib.h"
4 #include "resource.h"
5
6
7 //-- 雑用Functions ----------------------------------------------------------
8
9 void getProgramFiles( kiPath* path )
10 {
11 // 1.レジストリから
12 kiRegKey key;
13 if( key.open( HKEY_CLASSES_ROOT, "Software\\Microsoft\\Windows\\CurrentVersion", KEY_QUERY_VALUE ) )
14 if( key.get( "ProgramFilesDir", path )
15 || key.get( "ProgramFilesPath", path ) )
16 return;
17
18 // 2.Windowsディレクトリからの類推
19 char buf[MAX_PATH];
20 if( ::GetWindowsDirectory( buf, MAX_PATH ) )
21 {
22 for( char* p=buf; *p!='\\' && *p; p++ );
23 *p='\0';
24
25 *path= buf, *path += '\\', *path += "Program Files";
26 if( ::GetFileAttributes( *path ) != 0xffffffff )
27 return;
28 }
29
30 // 3.しゃーないので起動ディレクトリ
31 path->beSpecialPath( kiPath::Exe );
32 }
33
34 void createShortCut( const kiPath& original, const kiPath& at, const char* name )
35 {
36 IShellLink* psl;
37 if( SUCCEEDED(::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,IID_IShellLink,(void**)&psl)) )
38 {
39 psl->SetPath( original );
40
41 IPersistFile* ppf;
42 if( SUCCEEDED(psl->QueryInterface(IID_IPersistFile,(void**)&ppf)) )
43 {
44 WORD wsz[MAX_PATH];
45 kiPath lnkfile( at );
46 lnkfile += name, lnkfile += ".lnk";
47 ::MultiByteToWideChar(CP_ACP,0,lnkfile,-1,wsz,MAX_PATH);
48 ppf->Save(wsz,TRUE);
49 ppf->Release();
50 }
51 psl->Release();
52 }
53 }
54
55
56 //-- メイン -------------------------------------------------------------------
57
58 class CKInstApp : public kiApp, kiDialog // kiAppのコンストラクタが先に呼ばれないと死ぬ。よろしくない。
59 {
60 CKInstApp() : kiDialog( IDD_MAIN ) {}
61 friend void kilib_create_new_app();
62
63 //-- メインルーチン ---------
64
65 void run( kiCmdParser& cmd )
66 {
67 if( cmd.option().len() )
68 if( cmd.option()[0][1] == 'i' )
69 {
70 install();
71 return;
72 }
73 else if( cmd.option()[0][1] == 'u' && cmd.param().len() )
74 {
75 uninstall( cmd.param()[0] );
76 return;
77 }
78 boot_uninstaller();
79 }
80
81 void install()
82 {
83 doModal();
84 if( IDCANCEL == getEndCode() )
85 return;
86
87 if( !copy() )
88 {
89 msgBox( kiStr().loadRsrc(IDS_COPYFAIL) );
90 return;
91 }
92
93 if( !regist() )
94 msgBox( kiStr().loadRsrc(IDS_REGISTFAIL) );
95
96 do_caldix();
97
98 msgBox( kiStr().loadRsrc(IDS_INSTALLFINISH),"Noah",MB_OK|MB_ICONINFORMATION );
99 }
100
101 void uninstall( const char* dir )
102 {
103 m_destdir = dir;
104 for( int i=0; i!=sizeof(m_assoc)/sizeof(bool); i++ )
105 m_assoc[i]=false;
106 Sleep(200);
107 unregist();
108 remove();
109 kill_later( kiPath(kiPath::Exe_name) );
110 msgBox( kiStr().loadRsrc(IDS_UNINSTALLFINISH),"Noah",MB_OK|MB_ICONINFORMATION );
111 }
112
113 void boot_uninstaller()
114 {
115 if( IDNO==msgBox( kiStr(500).loadRsrc(IDS_UNINSTOK), "Noah", MB_YESNO|MB_ICONQUESTION ) )
116 return;
117
118 kiPath self(kiPath::Exe_name), to(kiPath::Tmp), pos(kiPath::Exe);
119 to += "noaunins.exe";
120 ::CopyFile( self, to, FALSE );
121 to += " -u \"", to += pos, to+='"';
122
123 PROCESS_INFORMATION pi;
124 STARTUPINFO si; ki_memzero( &si,sizeof(si) ); si.cb=sizeof(si);
125 if( !::CreateProcess( NULL,const_cast<char*>((const char*)to),
126 NULL,NULL,FALSE,CREATE_NEW_PROCESS_GROUP|NORMAL_PRIORITY_CLASS,NULL,NULL,&si,&pi ) )
127 return; // 起動できなかった…。
128
129 ::CloseHandle( pi.hThread );
130 ::CloseHandle( pi.hProcess );
131
132 // レジストリのアンインストール情報削除
133 kiRegKey key;
134 if( key.open( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall" ) )
135 key.delSubKey( "Noah" );
136 }
137
138 //-- メインダイアログの処理 --
139
140 bool onOK()
141 {
142 char str[MAX_PATH];
143 sendMsgToItem( IDC_INSTALLTO, WM_GETTEXT, MAX_PATH, (LPARAM)str );
144 if( str[1]!=':' || str[2]!='\\' )
145 {
146 msgBox( kiStr().loadRsrc(IDS_BADPATH) );
147 return false;
148 }
149
150 m_destdir = str;
151 m_destdir.beBackSlash(true);
152 for( UINT i=IDC_LZH; i<=IDC_DSK; i++ )
153 m_assoc[i-IDC_LZH] = (BST_CHECKED==sendMsgToItem( i, BM_GETCHECK ));
154 m_assoc[IDC_STT-IDC_LZH] = true;
155
156 return true;
157 }
158 BOOL onInit()
159 {
160 for( int j=0; j<18; j++ )
161 m_assoc[j] = true;
162
163 kiPath prg;
164 getPrevPos( &prg );
165 if( prg.len()==0 ) // 新規インストール
166 getProgramFiles( &prg ), prg.beBackSlash(true), prg += "Noah\\";
167 else // 既に存在してる場合
168 {
169 HINSTANCE hDLL = kiSUtil::loadLibrary( "NoahXt.dll" );
170 if( hDLL )
171 {
172 typedef bool (WINAPI * XT_IA)();
173 XT_IA Init = (XT_IA)::GetProcAddress( hDLL, "Init" );
174 if( Init() )
175 {
176 typedef void (WINAPI * XT_LS)(bool*,bool*);
177 typedef void (WINAPI * XT_AS)(bool*);
178 typedef void (WINAPI * XT_LSEX)(const char*,bool*);
179 XT_LS LoadSE = (XT_LS)::GetProcAddress( hDLL, "LoadSE" );
180 XT_AS LoadAssoc = (XT_AS)::GetProcAddress( hDLL, "LoadAS" );
181 XT_LSEX LoadASEx = (XT_LSEX)::GetProcAddress( hDLL, "LoadASEx" );
182 LoadSE( &m_assoc[13], &m_assoc[14] );
183 LoadASEx( "7z\0", &m_assoc[12] );
184 LoadAssoc( m_assoc );
185 }
186 ::FreeLibrary( hDLL );
187 }
188 m_assoc[15] = kiSUtil::exist( kiPath(kiPath::Snd)+="Noah.lnk" );
189 m_assoc[16] = kiSUtil::exist( kiPath(kiPath::Dsk)+="Noah.lnk" );
190 }
191
192 sendMsgToItem( IDC_INSTALLTO, WM_SETTEXT, 0, (LPARAM)(const char*)prg );
193 for( UINT i=IDC_LZH; i<=IDC_DSK; i++ )
194 if( m_assoc[i-IDC_LZH] )
195 sendMsgToItem( i, BM_SETCHECK, BST_CHECKED );
196 return FALSE;
197 }
198 BOOL CALLBACK proc( UINT msg, WPARAM wp, LPARAM lp )
199 {
200 if( msg != WM_COMMAND )
201 return FALSE;
202 switch( LOWORD(wp) )
203 {
204 case IDC_REF:{
205 char str[MAX_PATH];
206 sendMsgToItem( IDC_INSTALLTO, WM_GETTEXT, MAX_PATH, (LPARAM)str );
207 if( kiSUtil::getFolderDlg( str, hwnd(), kiStr().loadRsrc(IDS_DIR), str ) )
208 {
209 kiPath x(str); x.beBackSlash(true); x+="Noah\\";
210 sendMsgToItem( IDC_INSTALLTO, WM_SETTEXT, 0, (LPARAM)(const char*)x );
211 }
212 }break;
213 case IDC_ALL:{
214 for( UINT i=IDC_LZH; i<=IDC_DSK; i++ )
215 sendMsgToItem( i, BM_SETCHECK, BST_UNCHECKED );
216 }break;
217 default:
218 return FALSE;
219 }
220 return TRUE;
221 }
222
223 //-- インストール ---------
224
225 bool m_assoc[18]; // LZH-JAK, 7Z, CMP MLT, SND DSK STT
226 kiPath m_destdir;
227
228 bool copy()
229 {
230 kiPath exe(kiPath::Exe,false), inst(m_destdir);
231 inst.beBackSlash(false);
232
233 // とりあえず全コピ
234 bool r = copy_dir2dir(exe,inst);
235
236 // manualの言語をてけとーに調整
237 kiPath manE(m_destdir), manJ(m_destdir);
238 manE.beBackSlash(true), manJ.beBackSlash(true);
239 manE += "manual-e.htm", manJ += "manual.htm";
240 if( ::GetACP() != 932 )
241 ::CopyFile( manE, manJ, FALSE );
242 ::DeleteFile( manE );
243
244 return r;
245 }
246
247 bool regist()
248 {
249 // NoahXt.dllによる処理
250 kiPath xtdll( m_destdir );
251 xtdll += "NoahXt.dll";
252 HINSTANCE hDLL = kiSUtil::loadLibrary( xtdll );
253 if( hDLL )
254 {
255 typedef bool (WINAPI * XT_IA)();
256 typedef void (WINAPI * XT_LS)(bool*,bool*);
257 typedef void (WINAPI * XT_SS)(bool,bool);
258 typedef void (WINAPI * XT_AS)(bool*);
259 typedef void (WINAPI * XT_SSEX)(const char*,bool);
260 XT_IA Init = (XT_IA)::GetProcAddress( hDLL, "Init" );
261 if( Init() )
262 {
263 XT_SS SaveSE = (XT_SS)::GetProcAddress( hDLL, "SaveSE" );
264 XT_AS SaveAssoc = (XT_AS)::GetProcAddress( hDLL, "SaveAS" );
265 XT_SSEX SaveASEx = (XT_SSEX)::GetProcAddress( hDLL, "SaveASEx" );
266 SaveSE( m_assoc[13], m_assoc[14] );
267 SaveASEx( "7z\0", m_assoc[12] );
268 SaveAssoc( m_assoc );
269 }
270 ::FreeLibrary( hDLL );
271 }
272
273 // ショートカット
274 ::CoInitialize( NULL );
275 kiPath tmp(m_destdir); tmp += "Noah.exe";
276 if( m_assoc[15] )
277 createShortCut( tmp, kiPath(kiPath::Snd), "Noah" );
278 if( m_assoc[16] )
279 createShortCut( tmp, kiPath(kiPath::Dsk), "Noah" );
280 if( m_assoc[17] )
281 {
282 kiPath StartMenu( CSIDL_PROGRAMS ),rsrc;
283 StartMenu += "Noah\\";
284 StartMenu.mkdir();
285
286 createShortCut( tmp, StartMenu, "Noah" );
287 tmp = m_destdir, tmp += "caldix.exe";
288 createShortCut( tmp, StartMenu, rsrc.loadRsrc(IDS_CALDIX) );
289 tmp = m_destdir, tmp += "manual.htm";
290 createShortCut( tmp, StartMenu, rsrc.loadRsrc(IDS_HELP) );
291 tmp = m_destdir, tmp += "uninst.exe";
292 createShortCut( tmp, StartMenu, rsrc.loadRsrc(IDS_UNINSTALLER) );
293 }
294 ::CoUninitialize();
295
296 // アンインストール情報をレジストリへ
297 kiPath uninst( m_destdir );
298 uninst += "uninst.exe";
299
300 kiRegKey key;
301 if( !key.create( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Noah", KEY_WRITE ) )
302 return false;
303 key.set( "DisplayName", kiStr().loadRsrc(IDS_NOAH) );
304 key.set( "UninstallString", uninst );
305 return true;
306 }
307
308 void do_caldix()
309 {
310 if( IDYES==msgBox( kiStr(1000).loadRsrc(IDS_DLLINST),"Noah",MB_YESNO|MB_ICONQUESTION ) )
311 {
312 kiStr cld;
313 cld += '"';
314 cld += m_destdir;
315 cld += "caldix.exe";
316 cld += '"';
317
318 // プロセス開始
319 PROCESS_INFORMATION pi;
320 STARTUPINFO si; ki_memzero( &si,sizeof(si) ); si.cb=sizeof(si);
321 if( !::CreateProcess( NULL,const_cast<char*>((const char*)cld),
322 NULL,NULL,FALSE,CREATE_NEW_PROCESS_GROUP|NORMAL_PRIORITY_CLASS,NULL,NULL,&si,&pi ) )
323 return;
324
325 // 終了待機
326 ::CloseHandle( pi.hThread );
327 ::WaitForSingleObject( pi.hProcess, INFINITE );
328 ::CloseHandle( pi.hProcess );
329 }
330 }
331
332 bool copy_dir2dir( kiPath& from, kiPath& to )
333 {
334 if( !kiSUtil::isdir(from) )
335 {
336 if( ::CopyFile( from, to, FALSE ) )
337 return true;
338 if( 0==ki_strcmpi( from.ext(), "dll" ) )
339 return copy_later(from, to);
340 return false;
341 }
342
343 from += '\\', to += '\\', to.mkdir();
344 if( !kiSUtil::isdir(to) )
345 return false;
346
347 kiFindFile find;
348 WIN32_FIND_DATA fd;
349 kiPath src, dst, wild(from); wild+="\\*";
350 for( find.begin( wild ); find.next(&fd); )
351 {
352 src = from, src+='\\', src += fd.cFileName;
353 dst = to , dst+='\\', dst += fd.cFileName;
354 if( !copy_dir2dir( src, dst ) )
355 return false;
356 }
357 return true;
358 }
359
360 void getPrevPos( kiPath* path )
361 {
362 *path = "";
363
364 kiRegKey key;
365 if( !key.open( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Noah", KEY_READ ) )
366 return;
367 key.get( "UninstallString", path );
368 path->beDirOnly();
369 }
370
371 //-- アンインストール ---------
372
373 typedef bool (WINAPI * XT_IA)();
374 typedef void (WINAPI * XT_LS)(bool*,bool*);
375 typedef void (WINAPI * XT_SS)(bool,bool);
376 typedef void (WINAPI * XT_AS)(bool*);
377 typedef void (WINAPI * XT_SAX)(const char*,bool);
378 typedef void (WINAPI * XT_LAX)(const char*,bool*);
379 bool unregist()
380 {
381 // NoahXt.dllによる処理
382 kiPath xtdll( m_destdir );
383 xtdll += "NoahXt.dll";
384 HINSTANCE hDLL = kiSUtil::loadLibrary( xtdll );
385 if( hDLL )
386 {
387 XT_IA Init = (XT_IA)::GetProcAddress( hDLL, "Init" );
388 if( Init() )
389 {
390 XT_SAX SaveASEx = (XT_SAX)::GetProcAddress( hDLL, "SaveASEx" );
391 XT_LAX LoadASEx = (XT_LAX)::GetProcAddress( hDLL, "LoadASEx" );
392 unregist_b2e( SaveASEx, LoadASEx );
393
394 XT_SS SaveSE = (XT_SS)::GetProcAddress( hDLL, "SaveSE" );
395 XT_AS SaveAssoc = (XT_AS)::GetProcAddress( hDLL, "SaveAS" );
396 SaveSE( m_assoc[13], m_assoc[14] );
397 SaveAssoc( m_assoc );
398 }
399 ::FreeLibrary( hDLL );
400 }
401
402 // ショートカット
403 ::CoInitialize( NULL );
404 kiPath snd(kiPath::Snd); snd += "Noah.lnk";
405 kiPath dsk(kiPath::Dsk); dsk += "Noah.lnk";
406 kiPath stt(CSIDL_PROGRAMS); stt += "Noah";
407 ::DeleteFile(snd), ::DeleteFile(dsk), stt.remove();
408
409 return true;
410 }
411
412 static void crack_str( char* p )
413 {
414 for( ; *p; p=kiStr::next(p) )
415 if( *p=='.' )
416 *p++ = '\0';
417 *++p = '\0';
418 }
419
420 void unregist_b2e( XT_SAX SaveASEx, XT_LAX LoadASEx )
421 {
422 char* first_dot;
423 kiFindFile f;
424 WIN32_FIND_DATA fd;
425 kiPath b2ewild(m_destdir);
426 b2ewild.beBackSlash(true);
427
428 f.begin( b2ewild+="b2e\\*.b2e" );
429 while( f.next(&fd) )
430 if( fd.cFileName[0] != '#' ) // # 付きは圧縮専用
431 {
432 // 拡張子を切り出し
433 ::CharLower( fd.cFileName );
434 first_dot = const_cast<char*>(kiPath::ext_all(fd.cFileName)-1);
435 *first_dot = '\0';
436 crack_str( fd.cFileName );
437 // 関連づけ削除
438 SaveASEx( fd.cFileName, false );
439 }
440 SaveASEx( "7z\0", false );
441 }
442
443 bool remove()
444 {
445 ::SetCurrentDirectory( kiPath(kiPath::Exe) );
446
447 kiPath tmp;
448 m_destdir.beBackSlash(true);
449 // インストールしたモノだけ全削除
450 tmp=m_destdir, tmp+="Noah.exe", ::DeleteFile(tmp);
451 tmp=m_destdir, tmp+="Noah.ini", ::DeleteFile(tmp);
452 tmp=m_destdir, tmp+="uninst.exe", ::DeleteFile(tmp);
453 tmp=m_destdir, tmp+="caldix.exe", ::DeleteFile(tmp);
454 tmp=m_destdir, tmp+="caldix.ini", ::DeleteFile(tmp);
455 tmp=m_destdir, tmp+="ReadMe.txt", ::DeleteFile(tmp);
456 tmp=m_destdir, tmp+="manual.htm", ::DeleteFile(tmp);
457 tmp=m_destdir, tmp+="html", tmp.remove();
458 tmp=m_destdir, tmp+="b2e\\jak.b2e", ::DeleteFile(tmp);
459 tmp=m_destdir, tmp+="b2e\\aboutb2e.txt",::DeleteFile(tmp);
460 tmp=m_destdir, tmp+="b2e", ::RemoveDirectory(tmp);
461 tmp=m_destdir, tmp+="NoahXt.dll", ::DeleteFile(tmp);
462 ::RemoveDirectory(m_destdir);
463 // NoahXt.dllは再起動後に回すかも知れない
464 if( kiSUtil::exist(tmp) )
465 {
466 kill_later(tmp);
467 tmp.beDirOnly();
468 tmp.beBackSlash(false);
469 kill_later(tmp);
470 }
471
472 return true;
473 }
474
475 void kill_later( const char* pszFile )
476 {
477 // "MoveFileEx Not Supported in Windows 95 But Functionality Is"
478 if( ::MoveFileEx( pszFile, NULL, MOVEFILE_DELAY_UNTIL_REBOOT ) )
479 return;
480 char shortPath[MAX_PATH];
481 ::GetShortPathName( pszFile, shortPath, sizeof(shortPath) );
482
483 kiPath inifile( kiPath::Win ); inifile+="wininit.ini";
484
485 char buf[30000];
486 ::GetPrivateProfileSection( "Rename", buf, 30000, inifile );
487 char* p = buf;
488 while(*p)while(*p++);
489
490 ::lstrcpy( p, "NUL=" );
491 ::lstrcat( p, shortPath );
492 while(*p++);
493 *p='\0';
494
495 ::WritePrivateProfileSection( "Rename", buf, inifile );
496
497 // 確実に書き込む
498 ::WritePrivateProfileString( NULL, NULL, NULL, inifile );
499 }
500
501 bool copy_later( const char* from, const char* to )
502 {
503 char from_temp[MAX_PATH];
504 ::lstrcpy( from_temp, to );
505 ::lstrcat( from_temp, ".new" );
506 if( !::CopyFile( from, from_temp, FALSE ) )
507 return false;
508
509 char shortFrom[MAX_PATH];
510 ::GetShortPathName( from_temp, shortFrom, sizeof(shortFrom) );
511 char shortTo[MAX_PATH];
512 ::GetShortPathName( to, shortTo, sizeof(shortTo) );
513 kiPath inifile( kiPath::Win ); inifile+="wininit.ini";
514
515 char buf[30000];
516 ::GetPrivateProfileSection( "Rename", buf, 30000, inifile );
517 char* p = buf;
518 while(*p)while(*p++);
519
520 ::lstrcpy( p, "NUL=" );
521 ::lstrcat( p, shortTo );
522 while(*p++);
523 *p++='\r',*p++='\n';
524 ::lstrcpy( p, shortTo );
525 ::lstrcat( p, "=" );
526 ::lstrcat( p, shortFrom );
527 while(*p++);
528 *p='\0';
529
530 ::WritePrivateProfileSection( "Rename", buf, inifile );
531
532 // 確実に書き込む
533 ::WritePrivateProfileString( NULL, NULL, NULL, inifile );
534 return true;
535 }
536 };
537
538 void kilib_create_new_app()
539 {
540 new CKInstApp;
541 }