#include "stdafx.h"
#include "../kilib/kilib.h"
#include "resource.h"
//-- 雑用Functions ----------------------------------------------------------
void getProgramFiles( kiPath* path )
{
// 1.レジストリから
kiRegKey key;
if( key.open( HKEY_CLASSES_ROOT, "Software\\Microsoft\\Windows\\CurrentVersion", KEY_QUERY_VALUE ) )
if( key.get( "ProgramFilesDir", path )
|| key.get( "ProgramFilesPath", path ) )
return;
// 2.Windowsディレクトリからの類推
char buf[MAX_PATH];
if( ::GetWindowsDirectory( buf, MAX_PATH ) )
{
for( char* p=buf; *p!='\\' && *p; p++ );
*p='\0';
*path= buf, *path += '\\', *path += "Program Files";
if( ::GetFileAttributes( *path ) != 0xffffffff )
return;
}
// 3.しゃーないので起動ディレクトリ
path->beSpecialPath( kiPath::Exe );
}
void createShortCut( const kiPath& original, const kiPath& at, const char* name )
{
IShellLink* psl;
if( SUCCEEDED(::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,IID_IShellLink,(void**)&psl)) )
{
psl->SetPath( original );
IPersistFile* ppf;
if( SUCCEEDED(psl->QueryInterface(IID_IPersistFile,(void**)&ppf)) )
{
WORD wsz[MAX_PATH];
kiPath lnkfile( at );
lnkfile += name, lnkfile += ".lnk";
::MultiByteToWideChar(CP_ACP,0,lnkfile,-1,wsz,MAX_PATH);
ppf->Save(wsz,TRUE);
ppf->Release();
}
psl->Release();
}
}
//-- メイン -------------------------------------------------------------------
class CKInstApp : public kiApp, kiDialog // kiAppのコンストラクタが先に呼ばれないと死ぬ。よろしくない。
{
CKInstApp() : kiDialog( IDD_MAIN ) {}
friend void kilib_create_new_app();
//-- メインルーチン ---------
void run( kiCmdParser& cmd )
{
if( cmd.option().len() )
if( cmd.option()[0][1] == 'i' )
{
install();
return;
}
else if( cmd.option()[0][1] == 'u' && cmd.param().len() )
{
uninstall( cmd.param()[0] );
return;
}
boot_uninstaller();
}
void install()
{
doModal();
if( IDCANCEL == getEndCode() )
return;
if( !copy() )
{
msgBox( kiStr().loadRsrc(IDS_COPYFAIL) );
return;
}
if( !regist() )
msgBox( kiStr().loadRsrc(IDS_REGISTFAIL) );
do_caldix();
msgBox( kiStr().loadRsrc(IDS_INSTALLFINISH),"Noah",MB_OK|MB_ICONINFORMATION );
}
void uninstall( const char* dir )
{
m_destdir = dir;
for( int i=0; i!=sizeof(m_assoc)/sizeof(bool); i++ )
m_assoc[i]=false;
Sleep(200);
unregist();
remove();
kill_later( kiPath(kiPath::Exe_name) );
msgBox( kiStr().loadRsrc(IDS_UNINSTALLFINISH),"Noah",MB_OK|MB_ICONINFORMATION );
}
void boot_uninstaller()
{
if( IDNO==msgBox( kiStr(500).loadRsrc(IDS_UNINSTOK), "Noah", MB_YESNO|MB_ICONQUESTION ) )
return;
kiPath self(kiPath::Exe_name), to(kiPath::Tmp), pos(kiPath::Exe);
to += "noaunins.exe";
::CopyFile( self, to, FALSE );
to += " -u \"", to += pos, to+='"';
PROCESS_INFORMATION pi;
STARTUPINFO si; ki_memzero( &si,sizeof(si) ); si.cb=sizeof(si);
if( !::CreateProcess( NULL,const_cast<char*>((const char*)to),
NULL,NULL,FALSE,CREATE_NEW_PROCESS_GROUP|NORMAL_PRIORITY_CLASS,NULL,NULL,&si,&pi ) )
return; // 起動できなかった…。
::CloseHandle( pi.hThread );
::CloseHandle( pi.hProcess );
// レジストリのアンインストール情報削除
kiRegKey key;
if( key.open( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall" ) )
key.delSubKey( "Noah" );
}
//-- メインダイアログの処理 --
bool onOK()
{
char str[MAX_PATH];
sendMsgToItem( IDC_INSTALLTO, WM_GETTEXT, MAX_PATH, (LPARAM)str );
if( str[1]!=':' || str[2]!='\\' )
{
msgBox( kiStr().loadRsrc(IDS_BADPATH) );
return false;
}
m_destdir = str;
m_destdir.beBackSlash(true);
for( UINT i=IDC_LZH; i<=IDC_DSK; i++ )
m_assoc[i-IDC_LZH] = (BST_CHECKED==sendMsgToItem( i, BM_GETCHECK ));
m_assoc[IDC_STT-IDC_LZH] = true;
return true;
}
BOOL onInit()
{
for( int j=0; j<18; j++ )
m_assoc[j] = true;
kiPath prg;
getPrevPos( &prg );
if( prg.len()==0 ) // 新規インストール
getProgramFiles( &prg ), prg.beBackSlash(true), prg += "Noah\\";
else // 既に存在してる場合
{
HINSTANCE hDLL = kiSUtil::loadLibrary( "NoahXt.dll" );
if( hDLL )
{
typedef bool (WINAPI * XT_IA)();
XT_IA Init = (XT_IA)::GetProcAddress( hDLL, "Init" );
if( Init() )
{
typedef void (WINAPI * XT_LS)(bool*,bool*);
typedef void (WINAPI * XT_AS)(bool*);
typedef void (WINAPI * XT_LSEX)(const char*,bool*);
XT_LS LoadSE = (XT_LS)::GetProcAddress( hDLL, "LoadSE" );
XT_AS LoadAssoc = (XT_AS)::GetProcAddress( hDLL, "LoadAS" );
XT_LSEX LoadASEx = (XT_LSEX)::GetProcAddress( hDLL, "LoadASEx" );
LoadSE( &m_assoc[13], &m_assoc[14] );
LoadASEx( "7z\0", &m_assoc[12] );
LoadAssoc( m_assoc );
}
::FreeLibrary( hDLL );
}
m_assoc[15] = kiSUtil::exist( kiPath(kiPath::Snd)+="Noah.lnk" );
m_assoc[16] = kiSUtil::exist( kiPath(kiPath::Dsk)+="Noah.lnk" );
}
sendMsgToItem( IDC_INSTALLTO, WM_SETTEXT, 0, (LPARAM)(const char*)prg );
for( UINT i=IDC_LZH; i<=IDC_DSK; i++ )
if( m_assoc[i-IDC_LZH] )
sendMsgToItem( i, BM_SETCHECK, BST_CHECKED );
return FALSE;
}
BOOL CALLBACK proc( UINT msg, WPARAM wp, LPARAM lp )
{
if( msg != WM_COMMAND )
return FALSE;
switch( LOWORD(wp) )
{
case IDC_REF:{
char str[MAX_PATH];
sendMsgToItem( IDC_INSTALLTO, WM_GETTEXT, MAX_PATH, (LPARAM)str );
if( kiSUtil::getFolderDlg( str, hwnd(), kiStr().loadRsrc(IDS_DIR), str ) )
{
kiPath x(str); x.beBackSlash(true); x+="Noah\\";
sendMsgToItem( IDC_INSTALLTO, WM_SETTEXT, 0, (LPARAM)(const char*)x );
}
}break;
case IDC_ALL:{
for( UINT i=IDC_LZH; i<=IDC_DSK; i++ )
sendMsgToItem( i, BM_SETCHECK, BST_UNCHECKED );
}break;
default:
return FALSE;
}
return TRUE;
}
//-- インストール ---------
bool m_assoc[18]; // LZH-JAK, 7Z, CMP MLT, SND DSK STT
kiPath m_destdir;
bool copy()
{
kiPath exe(kiPath::Exe,false), inst(m_destdir);
inst.beBackSlash(false);
// とりあえず全コピ
bool r = copy_dir2dir(exe,inst);
// manualの言語をてけとーに調整
kiPath manE(m_destdir), manJ(m_destdir);
manE.beBackSlash(true), manJ.beBackSlash(true);
manE += "manual-e.htm", manJ += "manual.htm";
if( ::GetACP() != 932 )
::CopyFile( manE, manJ, FALSE );
::DeleteFile( manE );
return r;
}
bool regist()
{
// NoahXt.dllによる処理
kiPath xtdll( m_destdir );
xtdll += "NoahXt.dll";
HINSTANCE hDLL = kiSUtil::loadLibrary( xtdll );
if( hDLL )
{
typedef bool (WINAPI * XT_IA)();
typedef void (WINAPI * XT_LS)(bool*,bool*);
typedef void (WINAPI * XT_SS)(bool,bool);
typedef void (WINAPI * XT_AS)(bool*);
typedef void (WINAPI * XT_SSEX)(const char*,bool);
XT_IA Init = (XT_IA)::GetProcAddress( hDLL, "Init" );
if( Init() )
{
XT_SS SaveSE = (XT_SS)::GetProcAddress( hDLL, "SaveSE" );
XT_AS SaveAssoc = (XT_AS)::GetProcAddress( hDLL, "SaveAS" );
XT_SSEX SaveASEx = (XT_SSEX)::GetProcAddress( hDLL, "SaveASEx" );
SaveSE( m_assoc[13], m_assoc[14] );
SaveASEx( "7z\0", m_assoc[12] );
SaveAssoc( m_assoc );
}
::FreeLibrary( hDLL );
}
// ショートカット
::CoInitialize( NULL );
kiPath tmp(m_destdir); tmp += "Noah.exe";
if( m_assoc[15] )
createShortCut( tmp, kiPath(kiPath::Snd), "Noah" );
if( m_assoc[16] )
createShortCut( tmp, kiPath(kiPath::Dsk), "Noah" );
if( m_assoc[17] )
{
kiPath StartMenu( CSIDL_PROGRAMS ),rsrc;
StartMenu += "Noah\\";
StartMenu.mkdir();
createShortCut( tmp, StartMenu, "Noah" );
tmp = m_destdir, tmp += "caldix.exe";
createShortCut( tmp, StartMenu, rsrc.loadRsrc(IDS_CALDIX) );
tmp = m_destdir, tmp += "manual.htm";
createShortCut( tmp, StartMenu, rsrc.loadRsrc(IDS_HELP) );
tmp = m_destdir, tmp += "uninst.exe";
createShortCut( tmp, StartMenu, rsrc.loadRsrc(IDS_UNINSTALLER) );
}
::CoUninitialize();
// アンインストール情報をレジストリへ
kiPath uninst( m_destdir );
uninst += "uninst.exe";
kiRegKey key;
if( !key.create( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Noah", KEY_WRITE ) )
return false;
key.set( "DisplayName", kiStr().loadRsrc(IDS_NOAH) );
key.set( "UninstallString", uninst );
return true;
}
void do_caldix()
{
if( IDYES==msgBox( kiStr(1000).loadRsrc(IDS_DLLINST),"Noah",MB_YESNO|MB_ICONQUESTION ) )
{
kiStr cld;
cld += '"';
cld += m_destdir;
cld += "caldix.exe";
cld += '"';
// プロセス開始
PROCESS_INFORMATION pi;
STARTUPINFO si; ki_memzero( &si,sizeof(si) ); si.cb=sizeof(si);
if( !::CreateProcess( NULL,const_cast<char*>((const char*)cld),
NULL,NULL,FALSE,CREATE_NEW_PROCESS_GROUP|NORMAL_PRIORITY_CLASS,NULL,NULL,&si,&pi ) )
return;
// 終了待機
::CloseHandle( pi.hThread );
::WaitForSingleObject( pi.hProcess, INFINITE );
::CloseHandle( pi.hProcess );
}
}
bool copy_dir2dir( kiPath& from, kiPath& to )
{
if( !kiSUtil::isdir(from) )
{
if( ::CopyFile( from, to, FALSE ) )
return true;
if( 0==ki_strcmpi( from.ext(), "dll" ) )
return copy_later(from, to);
return false;
}
from += '\\', to += '\\', to.mkdir();
if( !kiSUtil::isdir(to) )
return false;
kiFindFile find;
WIN32_FIND_DATA fd;
kiPath src, dst, wild(from); wild+="\\*";
for( find.begin( wild ); find.next(&fd); )
{
src = from, src+='\\', src += fd.cFileName;
dst = to , dst+='\\', dst += fd.cFileName;
if( !copy_dir2dir( src, dst ) )
return false;
}
return true;
}
void getPrevPos( kiPath* path )
{
*path = "";
kiRegKey key;
if( !key.open( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Noah", KEY_READ ) )
return;
key.get( "UninstallString", path );
path->beDirOnly();
}
//-- アンインストール ---------
typedef bool (WINAPI * XT_IA)();
typedef void (WINAPI * XT_LS)(bool*,bool*);
typedef void (WINAPI * XT_SS)(bool,bool);
typedef void (WINAPI * XT_AS)(bool*);
typedef void (WINAPI * XT_SAX)(const char*,bool);
typedef void (WINAPI * XT_LAX)(const char*,bool*);
bool unregist()
{
// NoahXt.dllによる処理
kiPath xtdll( m_destdir );
xtdll += "NoahXt.dll";
HINSTANCE hDLL = kiSUtil::loadLibrary( xtdll );
if( hDLL )
{
XT_IA Init = (XT_IA)::GetProcAddress( hDLL, "Init" );
if( Init() )
{
XT_SAX SaveASEx = (XT_SAX)::GetProcAddress( hDLL, "SaveASEx" );
XT_LAX LoadASEx = (XT_LAX)::GetProcAddress( hDLL, "LoadASEx" );
unregist_b2e( SaveASEx, LoadASEx );
XT_SS SaveSE = (XT_SS)::GetProcAddress( hDLL, "SaveSE" );
XT_AS SaveAssoc = (XT_AS)::GetProcAddress( hDLL, "SaveAS" );
SaveSE( m_assoc[13], m_assoc[14] );
SaveAssoc( m_assoc );
}
::FreeLibrary( hDLL );
}
// ショートカット
::CoInitialize( NULL );
kiPath snd(kiPath::Snd); snd += "Noah.lnk";
kiPath dsk(kiPath::Dsk); dsk += "Noah.lnk";
kiPath stt(CSIDL_PROGRAMS); stt += "Noah";
::DeleteFile(snd), ::DeleteFile(dsk), stt.remove();
return true;
}
static void crack_str( char* p )
{
for( ; *p; p=kiStr::next(p) )
if( *p=='.' )
*p++ = '\0';
*++p = '\0';
}
void unregist_b2e( XT_SAX SaveASEx, XT_LAX LoadASEx )
{
char* first_dot;
kiFindFile f;
WIN32_FIND_DATA fd;
kiPath b2ewild(m_destdir);
b2ewild.beBackSlash(true);
f.begin( b2ewild+="b2e\\*.b2e" );
while( f.next(&fd) )
if( fd.cFileName[0] != '#' ) // # 付きは圧縮専用
{
// 拡張子を切り出し
::CharLower( fd.cFileName );
first_dot = const_cast<char*>(kiPath::ext_all(fd.cFileName)-1);
*first_dot = '\0';
crack_str( fd.cFileName );
// 関連づけ削除
SaveASEx( fd.cFileName, false );
}
SaveASEx( "7z\0", false );
}
bool remove()
{
::SetCurrentDirectory( kiPath(kiPath::Exe) );
kiPath tmp;
m_destdir.beBackSlash(true);
// インストールしたモノだけ全削除
tmp=m_destdir, tmp+="Noah.exe", ::DeleteFile(tmp);
tmp=m_destdir, tmp+="Noah.ini", ::DeleteFile(tmp);
tmp=m_destdir, tmp+="uninst.exe", ::DeleteFile(tmp);
tmp=m_destdir, tmp+="caldix.exe", ::DeleteFile(tmp);
tmp=m_destdir, tmp+="caldix.ini", ::DeleteFile(tmp);
tmp=m_destdir, tmp+="ReadMe.txt", ::DeleteFile(tmp);
tmp=m_destdir, tmp+="manual.htm", ::DeleteFile(tmp);
tmp=m_destdir, tmp+="html", tmp.remove();
tmp=m_destdir, tmp+="b2e\\jak.b2e", ::DeleteFile(tmp);
tmp=m_destdir, tmp+="b2e\\aboutb2e.txt",::DeleteFile(tmp);
tmp=m_destdir, tmp+="b2e", ::RemoveDirectory(tmp);
tmp=m_destdir, tmp+="NoahXt.dll", ::DeleteFile(tmp);
::RemoveDirectory(m_destdir);
// NoahXt.dllは再起動後に回すかも知れない
if( kiSUtil::exist(tmp) )
{
kill_later(tmp);
tmp.beDirOnly();
tmp.beBackSlash(false);
kill_later(tmp);
}
return true;
}
void kill_later( const char* pszFile )
{
// "MoveFileEx Not Supported in Windows 95 But Functionality Is"
if( ::MoveFileEx( pszFile, NULL, MOVEFILE_DELAY_UNTIL_REBOOT ) )
return;
char shortPath[MAX_PATH];
::GetShortPathName( pszFile, shortPath, sizeof(shortPath) );
kiPath inifile( kiPath::Win ); inifile+="wininit.ini";
char buf[30000];
::GetPrivateProfileSection( "Rename", buf, 30000, inifile );
char* p = buf;
while(*p)while(*p++);
::lstrcpy( p, "NUL=" );
::lstrcat( p, shortPath );
while(*p++);
*p='\0';
::WritePrivateProfileSection( "Rename", buf, inifile );
// 確実に書き込む
::WritePrivateProfileString( NULL, NULL, NULL, inifile );
}
bool copy_later( const char* from, const char* to )
{
char from_temp[MAX_PATH];
::lstrcpy( from_temp, to );
::lstrcat( from_temp, ".new" );
if( !::CopyFile( from, from_temp, FALSE ) )
return false;
char shortFrom[MAX_PATH];
::GetShortPathName( from_temp, shortFrom, sizeof(shortFrom) );
char shortTo[MAX_PATH];
::GetShortPathName( to, shortTo, sizeof(shortTo) );
kiPath inifile( kiPath::Win ); inifile+="wininit.ini";
char buf[30000];
::GetPrivateProfileSection( "Rename", buf, 30000, inifile );
char* p = buf;
while(*p)while(*p++);
::lstrcpy( p, "NUL=" );
::lstrcat( p, shortTo );
while(*p++);
*p++='\r',*p++='\n';
::lstrcpy( p, shortTo );
::lstrcat( p, "=" );
::lstrcat( p, shortFrom );
while(*p++);
*p='\0';
::WritePrivateProfileSection( "Rename", buf, inifile );
// 確実に書き込む
::WritePrivateProfileString( NULL, NULL, NULL, inifile );
return true;
}
};
void kilib_create_new_app()
{
new CKInstApp;
}