#include "stdafx.h"
#include "resource.h"
//----------------------------------------------------------------------------
// ユーティリティー
//----------------------------------------------------------------------------
#ifndef ListView_SetCheckState
#define ListView_SetCheckState(_hwndLV, _i, _fCheck) \
ListView_SetItemState(_hwndLV, _i, \
INDEXTOSTATEIMAGEMASK((_fCheck)+1), LVIS_STATEIMAGEMASK)
#endif
// 挿入caldixF
// なんか長いし分り難いんで(w
#define IsDblChar(x) IsDBCSLeadByte((BYTE)(x))
// 一番前=TRUE(後ろ=FALSE)の何か=cのインデックスを探して返す
int GetcX(char *buf,char c,BOOL fl)
{
int rt;
int i,len;
len = lstrlen(buf);
rt = 0;
for (i = 0;i < len;i++){
// 2バイト文字なら飛ばす
if (IsDblChar(buf[i])){
i++;
continue;
}
else{
if (buf[i] == c){
rt = i;
// 最初の奴を探すのなら
if (fl)
return(rt);
}
}
}
// 最後まで無かった
if (!rt && (i == len))
rt = len;
return(rt);
}
// ファイル名取得
char *GetFileName(char *buf)
{
int ly;
// 最後の¥
ly = GetcX(buf,'\\',FALSE);
// そのまま返す
if (ly == lstrlen(buf))
return(buf);
// \の次のポインタを返す
return(&buf[ly+1]);
}
// 挿入ここまでcaldixF
static void move_later( const char* from, const char* to )
{
// 移動先と同じディレクトリへ動かしておく
kiPath tmp( to );
::CopyFile( from, tmp+=".tmp", FALSE );
::DeleteFile( from );
// NT系ならMoveFileExが成功するはず
if( ::MoveFileEx( tmp, to, MOVEFILE_REPLACE_EXISTING|MOVEFILE_DELAY_UNTIL_REBOOT ) )
return;
// 9x系ならWININIT.INIをいじる
char inifile[MAX_PATH];
::GetWindowsDirectory( inifile, sizeof(inifile) );
::lstrcat( inifile, "\\WININIT.INI" );
// ショート名前に変換
char sfrom[MAX_PATH], sto[MAX_PATH];
::GetShortPathName( tmp, sfrom, MAX_PATH );
::GetShortPathName( to, sto, MAX_PATH );
// Renameセクションに追加
static char buf[30000];
::GetPrivateProfileSection( "Rename", buf, 30000, inifile );
char* p = buf;
while(*p)while(*p++);
::lstrcpy( p, "NUL=" );
::lstrcat( p, sto );
::lstrcat( p, "\r\n" );
::lstrcat( p, sto );
::lstrcat( p, "=" );
::lstrcat( p, sfrom );
while(*p++);
*p='\0';
// 2発打って確実に書き込む
::WritePrivateProfileSection( "Rename", buf, inifile );
::WritePrivateProfileString( NULL, NULL, NULL, inifile );
}
static void rebootWindows()
{
if( app()->osver().dwPlatformId == VER_PLATFORM_WIN32_NT )
{
// NT系では特権を取得しなくてはいけない
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
::OpenProcessToken( ::GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &hToken );
::LookupPrivilegeValue(
NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid );
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
::AdjustTokenPrivileges( hToken, FALSE, &tkp, 0, NULL, 0 );
}
::ExitWindowsEx( EWX_REBOOT, 0 );
}
static bool cancelShiteIidesuka()
{
return IDYES == app()->msgBox( kiStr().loadRsrc( IDS_CANCELOK ),
"caldix", MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 );
}
template <class T> static inline bool show( const T& dlg )
{
(const_cast<T&>(dlg)).doModal();
return IDOK == (const_cast<T&>(dlg)).getEndCode();
}
//----------------------------------------------------------------------------
// 解凍関係
//----------------------------------------------------------------------------
#include "kiutil.h"
#include "LzhTool.h"
#include "CabTool.h"
#include "ZipTool.h"
#define is_lzh(xx) (xx[2]=='-' && xx[3]=='l' && xx[4]=='h' && xx[6]=='-' && '0'<=xx[5] && xx[5]<='9')
#define is_zip(xx) (xx[2]=='P' && xx[3]=='K' && xx[4]==0x3 && xx[6]==0x4)
#define is_cab(xx) (xx[0]=='M' && xx[1]=='S' && xx[2]=='C' && xx[3]=='F')
enum arctype{ e_lzh, e_zip, e_cab, unknown };
static arctype get_archive_type( const char* arcname )
{
// 手抜き判別
arctype ans = unknown;
kiFile fp;
if( fp.open(arcname) )
{
unsigned long asize = 128 << 10;
unsigned char *buf = new unsigned char[asize];
unsigned char *p=buf, *end=buf+fp.read( buf, asize-6 );
while( p!=end )
{
if( is_lzh(p) ) { ans=e_lzh; break; }
else if( is_zip(p) ) { ans=e_zip; break; }
else if( is_cab(p) ) { ans=e_cab; break; }
p++;
}
delete [] buf;
}
return ans;
}
static void melt_it( const char* arcname, const char* dllname, kiPath& dll_rel_path )
{
const char* ext = kiPath::ext( arcname );
arctype type = unknown;
// 判別
if( 0==stricmp( ext, "lzh" ) ) type = e_lzh;
else if( 0==stricmp( ext, "zip" ) ) type = e_zip;
else if( 0==stricmp( ext, "cab" ) ) type = e_cab;
else type = get_archive_type(arcname);
// 展開
switch( type )
{
case e_lzh:{ CLzhTool().Extract( arcname, dllname, dll_rel_path ); }break;
case e_zip:{ CZipTool().Extract( arcname, dllname, dll_rel_path ); }break;
case e_cab:{ CCabTool().Extract( arcname, dllname, dll_rel_path ); }break;
}
}
//----------------------------------------------------------------------------
// DLL情報管理:Meta-WWWC-Contentの解析など
//----------------------------------------------------------------------------
class DLLInfo
{
public:
DLLInfo( const char* _name, const char* _html, int _wwwc )
: name( _name ), html( _html ), wwwc( _wwwc ), size( 0 ) {}
bool ParseHTML( char* str );
const kiStr& htmlName() const { return html; }
bool needToUpdate( kiPath& dlldir );
const kiStr& getName() const { return name; }
const kiStr& getState() const { return stat; }
const int getSize() const { return size; }
const kiStr& getArchiveName() const { return arch; }
private:
char* Get_WWWC_Content( char* str );
bool ParseWWWC( char* str );
bool CheckDateTime( const char* localDLL );
bool VersionCheckLogic(
const kiStr& dllName, const kiStr& htmlVer, int Ver, int subVer );
private:
// 固定情報
const kiStr name; // DLLの名前
const kiStr html; // チェック先HTMLの名前
const int wwwc; // 何番目のWWWCタグを利用するか
private:
// HTMLから取得する情報
kiStr arch; // 書庫名
kiStr vers; // バージョン
kiStr dttm; // 日付&時刻
int size; // サイズ
// バージョン照合の結果
kiStr stat; // 更新状況
};
char* DLLInfo::Get_WWWC_Content( char* x )
{
// もーれつに雑。
while( *x==' ' || *x=='\t' || *x=='\r' || *x=='\n' ) x++;
if( (x[0]=='m' || x[0]=='M')
&& (x[1]=='e' || x[1]=='E')
&& (x[2]=='t' || x[2]=='T')
&& (x[3]=='a' || x[3]=='A') )
{
x+=4;
while( *x==' ' || *x=='\t' || *x=='\r' || *x=='\n' ) x++;
if( (x[0]=='n' || x[0]=='N')
&& (x[1]=='a' || x[1]=='A')
&& (x[2]=='m' || x[2]=='M')
&& (x[3]=='e' || x[3]=='E')
&& (x[4]=='=')
&& (x[5]=='"')
&& (x[6]=='w' || x[6]=='W')
&& (x[7]=='w' || x[7]=='W')
&& (x[8]=='w' || x[8]=='W')
&& (x[9]=='c' || x[9]=='C')
&& (x[10]=='"') )
{
x+=11;
while( *x==' ' || *x=='\t' || *x=='\r' || *x=='\n' ) x++;
if( (x[0]=='c' || x[0]=='C')
&& (x[1]=='o' || x[1]=='O')
&& (x[2]=='n' || x[2]=='N')
&& (x[3]=='t' || x[3]=='T')
&& (x[4]=='e' || x[4]=='E')
&& (x[5]=='n' || x[5]=='N')
&& (x[6]=='t' || x[6]=='T')
&& (x[7]=='=')
&& (x[8]=='"') )
{
x+=9;
char* p=x;
while( *p!='\0' && *p!='"' ) p++;
*p='\0';
return x;
}
}
}
return NULL;
}
bool DLLInfo::ParseHTML( char* str )
{
int ct = wwwc;
for( char* p=str; *p; ++p )
if( *p == '<' )
{
for( char* x=p+1; *x; ++x )
if( *x == '>' )
break;
*x = '\0';
char* w = Get_WWWC_Content( p+1 );
if( w && (--ct)==0 )
return ParseWWWC( w );
p = x;
}
return false;
}
bool DLLInfo::ParseWWWC( char* str )
{
char *x,*k,*t,*p=str;
// 2個目のスペースまでが更新日時
for( int spc=2; *p; ++p )
if( *p==' ' )
if( (--spc)==0 )
break;
if( *p=='\0' )
return false;
*(p++) = '\0';
dttm = str;
// [xxx: ---] 部分
while( true )
{
while( *p!='\0' && *p!='[' ) ++p;
if( *p!='\0' ) ++p;
if( *p=='\0' )break;
t=x=k=p;
while( *x!='\0' && *x!=']' ) x++;
while( *k!='\0' && *k!=':' ) k++;
if( *x=='\0' || *k=='\0' || k>=x )break;
*k=*x='\0';
p=k+1;
if( 0==lstrcmpi( t, "File" ) )
arch = p;
else if( 0==lstrcmpi( t, "Ver" ) )
{
while( *p && (*p<'0' || '9'<*p) )
++p;
vers = p;
}
else if( 0==lstrcmpi( t, "Size" ) )
{
// atoi
for( int n=0; *p; p++ )
if( '0'<=*p && *p<='9' )
n = (10*n) + (*p - '0');
size = n;
}
p=x+1;
}
return ( size!=0 && arch.len()!=0 );
}
//----------------------------------------------------------------------------
// caldixの設定項目管理
//----------------------------------------------------------------------------
enum {
UNLHA, UNZIP, ZIP, CAB, TAR, UNRAR, UNGCA,
UNARJ, YZ1, BGA, JACK, AISH, ISH, UNBEL, SvZIP,
UNIMP, BH, YZ2,
DLLID_NUM };
struct CldxConfig
{
kiStr UA; // ユーザーエージェント名
bool SuperAutoMode; // (利用しない)
bool AutoMode; // 全自動ならtrue, カスタムならfalse
kiPath InstallTo; // インストール先
int CheckServer; // 更新チェックに使うサーバ 窓辺=0, CSD=1, 惑星=2
int ProxyPort; // プロキシのポート番号
kiStr ProxyServer; // プロキシサーバ名
kiStr ProxyUser; // プロキシユーザ名(利用しない)
kiStr ProxyPwd; // プロキシパスワード(利用しない)
bool George; // 常時接続モードならtrue, 汎用モードならfalse
bool UseCustomDir; // 全自動でも、カスタムと同じディレクトリを用いる
bool ShowReadMe; // 最後にcldxフォルダを開くか否か
// 挿入caldixF
kiStr Filer; // フォルダを開くファイラー
kiStr F_Prefix; // ファイラに渡すオプション前
kiStr F_Suffix; // ファイラに渡すオプション後ろ
// 挿入ここまでcaldixF
bool DoCheck[DLLID_NUM]; // 各DLLをチェック対象にするかどうか
int InstMode; // ダウンロードしたDLLの扱い
int Expire; // 日時チェックで更新対象とする範囲(単位:Day)
kiArray<DLLInfo*> List; // チェック対象DLLのリスト
CldxConfig()
: UA( "caldix/1.21" )
, SuperAutoMode( false )
, AutoMode( true )
, InstallTo( kiPath::Sys )
{
kiIniFile ini;
ini.setFileName( "caldix.ini" );
ini.setSection( "conf" );
InstallTo = ini.getStr ( "dll", InstallTo );
CheckServer = ini.getInt ( "checkserv", 0 ) % 3;
ProxyServer = ini.getStr ( "proxy", "" );
ProxyPort = ini.getInt ( "proxyport", -80 );
George =!ini.getBool( "askhang", false ); // [1.21] デフォルトを false に変更。流石に今時…
UseCustomDir = ini.getBool( "custdir", false );
ShowReadMe = ini.getBool( "readme", true );
InstMode = ini.getInt ( "mode", 1 );
Expire = ini.getInt ( "expire", 7 );
int version = ini.getInt ( "ver", 110 );
// 挿入caldixF
Filer = ini.getStr ( "Filer","explorer");
F_Prefix = ini.getStr ( "F_Prefix","");
F_Suffix = ini.getStr ( "F_Suffix","");
if( Filer=="" || Filer.isSame("explorer") )
Filer = kiPath(kiPath::Win,true), Filer += "explorer.exe";
// 挿入ここまでcaldixF
for( int i=0; i<DLLID_NUM; ++i )
DoCheck[i] = false;
const char* ptr = ini.getStr( "DLLList", "LZzCTRGAYBJaIb7iH" );
while( *ptr )
switch( 0x7f & (*(ptr++)) )
{
case 'L': DoCheck[UNLHA] = true; break;
case 'Z': DoCheck[UNZIP] = true; break;
case 'z': DoCheck[ZIP] = true; break;
case 'C': DoCheck[CAB] = true; break;
case 'T': DoCheck[TAR] = true; break;
case 'R': DoCheck[UNRAR] = true; break;
case 'G': DoCheck[UNGCA] = true; break;
case 'A': DoCheck[UNARJ] = true; break;
case 'Y': DoCheck[YZ1] = true; break;
case 'B': DoCheck[BGA] = true; break;
case 'J': DoCheck[JACK] = true; break;
case 'a': DoCheck[AISH] = true; break;
case 'I': DoCheck[ISH] = true; break;
case 'b': DoCheck[UNBEL] = true; break;
case '7': DoCheck[SvZIP] = true; break;
case 'i': DoCheck[UNIMP] = true; break;
case 'H': DoCheck[BH] = true; break;
case '2': DoCheck[YZ2] = true; break;
}
if( version<111 )
DoCheck[SvZIP] = true; // ver1.11より前には7-zip32.dllは
// 存在しなかったのでここで強制ON
if( version<112 )
DoCheck[UNIMP] = true; // ver1.12より前にはUnImp32.dllは
// 存在しなかったのでここで強制ON
if( version<118 )
DoCheck[BH] = true; // ver1.18より前にはBh32.dllは
// 存在しなかったのでここで強制ON
if( version<120 )
DoCheck[YZ2] = true; // ver1.20より前にはYz2.dllは
// 存在しなかったのでここで強制ON
}
void GenerateDLLList()
{
if( DoCheck[UNLHA] )
List.add( new DLLInfo( "Unlha32.dll", "unlha32.html", 1 ) );
if( DoCheck[UNZIP] )
List.add( new DLLInfo( "UnZip32.dll", "unzip32.html", 1 ) );
if( DoCheck[ZIP] )
List.add( new DLLInfo( "Zip32j.dll", "zip32j.html", 1 ) ),
List.add( new DLLInfo( "Zip32.dll", "zip32j.html", 2 ) ),
List.add( new DLLInfo( "Sfx32gui.dat", "sfx32gui.html", 1 ) );
if( DoCheck[CAB] )
List.add( new DLLInfo( "Cab32.dll", "cab32.html", 1 ) );
if( DoCheck[TAR] )
List.add( new DLLInfo( "Tar32.dll", "tar32.html", 1 ) );
if( DoCheck[UNRAR] )
List.add( new DLLInfo( "Unrar32.dll", "unrar32.html", 1 ) );
if( DoCheck[UNGCA] )
List.add( new DLLInfo( "UnGCA32.dll", "ungca32.html", 1 ) );
if( DoCheck[UNARJ] )
List.add( new DLLInfo( "Unarj32j.dll", "unarj32.html", 1 ) );
if( DoCheck[YZ1] )
List.add( new DLLInfo( "Yz1.dll", "yz1.html", 1 ) );
if( DoCheck[BGA] )
List.add( new DLLInfo( "Bga32.dll", "bga32.html", 1 ) );
if( DoCheck[JACK] )
List.add( new DLLInfo( "Jack32.dll", "jack32.html", 1 ) );
if( DoCheck[AISH] )
List.add( new DLLInfo( "Aish32.dll", "aish32.html", 1 ) );
if( DoCheck[ISH] )
List.add( new DLLInfo( "Ish32.dll", "ish32.html", 1 ) );
if( DoCheck[UNBEL] )
List.add( new DLLInfo( "Unbel32.dll", "unbel32.html", 1 ) );
if( DoCheck[SvZIP] )
List.add( new DLLInfo( "7-zip32.dll", "7-zip32.html", 1 ) );
if( DoCheck[UNIMP] )
List.add( new DLLInfo( "UnImp32.dll", "unimp32.html", 1 ) );
if( DoCheck[BH] )
List.add( new DLLInfo( "Bh32.dll", "bh32.html", 1 ) );
if( DoCheck[YZ2] )
List.add( new DLLInfo( "Yz2.dll", "yz2.html", 1 ) );
}
~CldxConfig()
{
if( !AutoMode )
{
kiIniFile ini;
ini.setFileName( "caldix.ini" );
ini.setSection( "conf" );
ini.putStr ( "dll", InstallTo );
ini.putInt ( "checkserv", CheckServer );
ini.putStr ( "proxy", ProxyServer );
ini.putInt ( "proxyport", ProxyPort );
ini.putBool( "askhang", !George );
ini.putBool( "custdir", UseCustomDir );
ini.putBool( "readme", ShowReadMe );
ini.putInt ( "mode", InstMode );
ini.putInt ( "expire", Expire );
ini.putInt ( "ver", 121 );
// 挿入caldixF
ini.putStr ( "Filer", Filer );
ini.putStr ( "F_Prefix", F_Prefix );
ini.putStr ( "F_Suffix", F_Suffix );
// 挿入ここまでcaldixF
kiStr chk;
for( int i=0; i<DLLID_NUM; ++i )
if( DoCheck[i] )
chk += "LZzCTRGAYBJaIb7iH2"[i];
ini.putStr( "DLLList", chk );
}
for( unsigned int i=0; i<List.len(); ++i )
delete List[i];
}
};
CldxConfig* cfg = NULL;
//----------------------------------------------------------------------------
// DLLのバージョンチェック
//----------------------------------------------------------------------------
struct _zip_version_type
{
unsigned char major;
unsigned char minor;
unsigned char patchlevel;
unsigned char not_used;
};
struct ZpVer
{
unsigned long structlen;
unsigned long flag;
char betalevel[10];
char date[20];
char zlib_version[10];
_zip_version_type zip;
_zip_version_type os2dll;
_zip_version_type windll;
};
static WORD Zip32DLLGetVersion( const char* dll )
{
WORD ans=0;
HINSTANCE inst = kiutil::safepathLoadLibrary( dll ); // dll はフルパスなので要らないはずだけど念のため
if( inst )
{
typedef int (WINAPI * ZPVR)(ZpVer*);
ZPVR v = (ZPVR)::GetProcAddress( inst, "ZpVersion" );
if( v )
{
ZpVer x;
v( &x );
ans = x.zip.major*100 + x.zip.minor*10 + x.zip.patchlevel;
}
::FreeLibrary( inst );
}
return ans;
}
bool DLLInfo::CheckDateTime( const char* localDLL )
{
// ローカルのDLLの日付を取得
FILETIME ft;
SYSTEMTIME StLocal;
HANDLE h = ::CreateFile(
localDLL, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN, NULL );
if( h == INVALID_HANDLE_VALUE )
return true;
::GetFileTime( h, NULL, NULL, &ft );
::FileTimeToSystemTime( &ft, &StLocal );
::CloseHandle( h );
// Webの方のの日付を取得
const char* p = dttm;
SYSTEMTIME StWeb = StLocal;
for( StWeb.wYear=0; *p && *p!='/'; ++p )
StWeb.wYear = StWeb.wYear*10 + (*p-'0');
if(*p)++p;
for( StWeb.wMonth=0; *p && *p!='/'; ++p )
StWeb.wMonth = StWeb.wMonth*10 + (*p-'0');
if(*p)++p;
for( StWeb.wDay=0; *p && *p!=' '; ++p )
StWeb.wDay = StWeb.wDay*10 + (*p-'0');
// Webの方が1週間以上新しければ更新とかそんな感じ
if( (StLocal.wYear> StWeb.wYear)
|| (StLocal.wYear==StWeb.wYear && StLocal.wMonth>StWeb.wMonth)
|| (StLocal.wYear==StWeb.wYear && StLocal.wMonth==StWeb.wMonth && StLocal.wDay>=StWeb.wDay) )
return false; // ローカルの方が新しいので更新しない
if( StLocal.wYear+2 < StWeb.wYear )
return true; // 確実に1年以上新しいので更新
if( StLocal.wYear+1 == StWeb.wYear )
StWeb.wMonth += 12;
// cfg->Expire 日以上新しければ更新
StWeb.wDay += 30 * (StWeb.wMonth - StLocal.wMonth);
return ( StLocal.wDay+cfg->Expire < StWeb.wDay );
}
//-------------------------------------------------------------------------------
// バージョンチェック for caldix/1.15 or older + caldixF fix
//-------------------------------------------------------------------------------
/*
bool DLLInfo::VersionCheckLogic(
const kiStr& dllName,
const kiStr& htmlVer,
int ver, int sub )
{
// 文字列に変換
char verstr[100];
if( dllName=="Unimp32.dll" )
if( sub==0 )
::wsprintf( verstr, "%d.%02d", ver/100, ver%100 );
else if( sub >= 100 )
::wsprintf( verstr, "%d.%02d%c", ver/100, ver%100, sub/100+'a'-1 );
else
::wsprintf( verstr, "%d.%02d%c", ver/100, ver%100, sub+'a'-1 );
else if( dllName=="7-zip32.dll" ) // 7-zipだけは無条件でSubVersionも数値で入れる
::wsprintf( verstr, "%d.%02d.%02d.%02d", ver/100, ver%100, sub/100,sub%100 );
else if( sub < 100 )
::wsprintf( verstr, "%d.%02d", ver/100, ver%100 );
else
::wsprintf( verstr, "%d.%02d%c", ver/100, ver%100, sub/100+'a'-1 );
// 比較(htmlVerの方がVer.subVerより新しければtrue)
return
(CSTR_GREATER_THAN == ::CompareString(LOCALE_USER_DEFAULT,SORT_STRINGSORT,vers,-1,verstr,-1));
}
*/
//-------------------------------------------------------------------------------
// バージョンチェック for caldix/1.17 or newer
//-------------------------------------------------------------------------------
const char* find_first_non_digit( const char* p )
{
while( '0'<=*p && *p<='9' ) ++p;
return p;
}
bool DLLInfo::VersionCheckLogic(
const kiStr& dllName, // DLL名
const kiStr& htmVerStr, // HTML上のバージョン文字列
int locVer, int locSub ) // ローカルDLLのバージョン
{
const char* vs = htmVerStr;
if( dllName == "Unimp32.dll" && locSub<100 )
locSub *= 100;
// バージョン文字列を解析。以下の4つの形式を認識する
//("%d.%d.%d.%d", ver/100, ver%100, sub/100, sub%100)
//("%d.%d", ver/100, ver%100) && sub<100
//("%d.%d%c", ver/100, ver%100, sub/100+'a'-1)
//("%d.%d.%d", ver/100, ver%100, sub)
int htmVer=0, htmSub=0;
{
// [%d][.]
const int d1 = atoi(vs);
vs = find_first_non_digit(vs);
if( *vs!='.' ) return false; ++vs;
// [%d]
const int d2 = atoi(vs);
const char* vs2 = find_first_non_digit(vs);
if( vs2-vs==1 && dllName=="Zip32.dll" ) // adhoc対処
htmVer = d1*100 + d2*10;
else
htmVer = d1*100 + d2;
vs = vs2;
if( *vs=='.' ) // [.]
{
++vs;
// [%d]
const int d3 = atoi(vs);
vs = find_first_non_digit(vs);
if( *vs=='.' ) // [.]
{
++vs;
// [%d]
const int d4 = atoi(vs);
htmSub = d3*100 + d4;
}
else
htmSub = d3;
}
else if( 'a'<=*vs && *vs<='z' ) // [a-z]
htmSub = (*vs-'a'+1) * 100;
else if( 'A'<=*vs && *vs<='Z' ) // [A-Z]
htmSub = (*vs-'A'+1) * 100;
}
return (locVer < htmVer) || (locVer==htmVer && locSub<htmSub);
}
bool DLLInfo::needToUpdate( kiPath& dlldir )
{
// 情報取得できていなかった場合は更新しない
if( vers.len() == 0 )
return false;
// 対象DLLのフルパス
kiPath dllPath( dlldir );
dllPath += name;
// DLLが存在しなかった場合は新しくインストール
if( !kiSUtil::exist( dllPath ) )
{
stat.loadRsrc( IDS_NEWINST );
return true;
}
// 存在した場合…
bool updatable = false;
if( name=="Sfx32gui.dat" )
{
// 特別処理1:Sfx32gui.datの場合は日付チェック
updatable = CheckDateTime( dllPath );
}
else
{
// それ以外は、バージョン番号でチェック
WORD ver=1, sub=0;
if( name == "Zip32.dll" )
{
ver = Zip32DLLGetVersion( dllPath );
}
else if( name != "Sfx32gui.dat" )
{
kiArcDLLRaw dll( dllPath );
ver = dll.getVer();
sub = dll.getVerSub();
if( name=="Unimp32.dll" && !dll.isVerSubAvail() )
ver=6, sub=0; // 特殊処理2:古いunimpは0.0.6.0として扱う
}
// バージョンチェックをここで実行
updatable = VersionCheckLogic( name, vers, ver, sub );
// 特殊処理3:Unrar32.dllで、違いがSubVersionだけのときは日付チェック
if( updatable && name=="Unrar32.dll" )
{
char verstr[100];
::wsprintf( verstr, "%d.%02dz", ver/100, ver%100 );
if( CSTR_GREATER_THAN == ::CompareString(LOCALE_USER_DEFAULT,SORT_STRINGSORT,verstr,-1,vers,-1) )
updatable = CheckDateTime( kiPath(dlldir)+="Unrar.dll" );
}
}
// 更新可能
if( updatable )
{
char str[100];
::wsprintf( str, stat.loadRsrc( IDS_UPDINST ), (const char*)vers );
stat = str;
}
return updatable;
}
//----------------------------------------------------------------------------
// startDlg : 自動|カスタムの選択
//----------------------------------------------------------------------------
class startDlg : public kiDialog
{
public:
startDlg() : kiDialog( IDD_START ) {}
private:
virtual BOOL onInit()
{
// 二重起動禁止
char cls[256], wnd[256];
::GetClassName( hwnd(), cls, sizeof(cls)-1 );
::GetWindowText( hwnd(), wnd, sizeof(wnd)-1 );
if( HWND h = ::FindWindow(cls,wnd) )
if( h!=hwnd() || (h=::FindWindowEx(NULL,h,cls,wnd)) )
{
end( IDCANCEL );
setFront( h );
return FALSE;
}
app()->setMainWnd( this );
UINT md = (cfg->AutoMode ? IDC_WORKTYPE1 : IDC_WORKTYPE2);
sendMsgToItem( md, BM_SETCHECK, BST_CHECKED );
return FALSE;
}
virtual bool onOK()
{
cfg->AutoMode =
(BST_CHECKED == sendMsgToItem( IDC_WORKTYPE1, BM_GETCHECK ));
return true;
}
};
//----------------------------------------------------------------------------
// customDlg : 接続先/インストール先の選択 プロキシ|詳細への分岐
//----------------------------------------------------------------------------
class customDlg : public kiDialog
{
public:
customDlg() : kiDialog( IDD_CUSTOM1 ) {}
private:
virtual BOOL onInit()
{
app()->setMainWnd( this );
sendMsgToItem( IDC_DLLDIR, WM_SETTEXT, 0, (LPARAM)(const char*)(cfg->InstallTo) );
sendMsgToItem( IDC_CONNECTTO1+cfg->CheckServer, BM_SETCHECK, BST_CHECKED );
return FALSE;
}
virtual BOOL CALLBACK proc( UINT msg, WPARAM wp, LPARAM lp )
{
if( msg==WM_COMMAND )
if( LOWORD(wp)==IDC_REF )
{
kiSUtil::getFolderDlgOfEditBox( item(IDC_DLLDIR), hwnd(), NULL );
return TRUE;
}
else if( LOWORD(wp)==IDC_PROXY )
{
show( proxyDlg() );
return TRUE;
}
else if( LOWORD(wp)==IDC_DETAIL )
{
show( detailDlg() );
return TRUE;
}
return FALSE;
}
virtual bool onOK()
{
char str[MAX_PATH];
sendMsgToItem( IDC_DLLDIR, WM_GETTEXT, sizeof(str)-1, (LPARAM)str );
cfg->InstallTo=str, cfg->InstallTo.beBackSlash( true );
for(int i=0; i<=2; ++i)
if( BST_CHECKED == sendMsgToItem( IDC_CONNECTTO1+i, BM_GETCHECK ) )
cfg->CheckServer = i;
return true;
}
virtual bool onCancel()
{
return cancelShiteIidesuka();
}
private:
class detailDlg : public kiDialog
{
public:
detailDlg() : kiDialog( IDD_DETAIL ) {}
private:
virtual BOOL onInit()
{
if( cfg->George )
sendMsgToItem( IDC_CONNECT_ALWAYS, BM_SETCHECK, BST_CHECKED );
if( cfg->ShowReadMe )
sendMsgToItem( IDC_SHOW_README, BM_SETCHECK, BST_CHECKED );
if( cfg->UseCustomDir )
sendMsgToItem( IDC_SAVE_DESTDIR, BM_SETCHECK, BST_CHECKED );
for( int i=0; i<DLLID_NUM; ++i )
if( cfg->DoCheck[i] )
sendMsgToItem( IDC_DLHA+i, BM_SETCHECK, BST_CHECKED );
// 挿入caldixF
sendMsgToItem( IDC_FILERPATH, WM_SETTEXT, 0, (LPARAM)(const char*)(cfg->Filer) );
sendMsgToItem( IDC_FILEROPT, WM_SETTEXT, 0, (LPARAM)(const char*)(cfg->F_Prefix) );
sendMsgToItem( IDC_FILEROPT2, WM_SETTEXT, 0, (LPARAM)(const char*)(cfg->F_Suffix) );
// 挿入ここまでcaldixF
return FALSE;
}
// 挿入caldixF
virtual BOOL CALLBACK proc( UINT msg, WPARAM wp, LPARAM lp )
{
// 指定ボタン
if((msg==WM_COMMAND) && (LOWORD(wp)==IDC_REF )){
kiSUtil::getOpenFileNameDlgOfEditBox(item(IDC_FILERPATH),hwnd());
return TRUE;
}
return FALSE;
}
// 挿入ここまでcaldixF
virtual bool onOK()
{
cfg->George =
(BST_CHECKED==sendMsgToItem( IDC_CONNECT_ALWAYS, BM_GETCHECK ));
cfg->ShowReadMe =
(BST_CHECKED==sendMsgToItem( IDC_SHOW_README, BM_GETCHECK ));
cfg->UseCustomDir =
(BST_CHECKED==sendMsgToItem( IDC_SAVE_DESTDIR, BM_GETCHECK ));
for( int i=0; i<DLLID_NUM; ++i )
cfg->DoCheck[i] =
(BST_CHECKED==sendMsgToItem( IDC_DLHA+i, BM_GETCHECK ));
// 挿入caldixF
char str[500];
sendMsgToItem( IDC_FILERPATH, WM_GETTEXT, sizeof(str)-1, (LPARAM)str );
cfg->Filer = str;
sendMsgToItem( IDC_FILEROPT, WM_GETTEXT, sizeof(str)-1, (LPARAM)str );
cfg->F_Prefix = str;
sendMsgToItem( IDC_FILEROPT2, WM_GETTEXT, sizeof(str)-1, (LPARAM)str );
cfg->F_Suffix = str;
// 挿入ここまでcaldixF
return true;
}
};
class proxyDlg : public kiDialog
{
public:
proxyDlg() : kiDialog( IDD_PROXY ) {}
private:
virtual BOOL onInit()
{
if( cfg->ProxyPort>0 )
{
sendMsgToItem( IDC_USEPROXY, BM_SETCHECK, BST_CHECKED );
::EnableWindow( item(IDC_HOST_N), TRUE );
::EnableWindow( item(IDC_PORT_N), TRUE );
::EnableWindow( item(IDC_HOST), TRUE );
::EnableWindow( item(IDC_PORT), TRUE );
::SetDlgItemInt( hwnd(), IDC_PORT, cfg->ProxyPort, FALSE );
}
else
::SetDlgItemInt( hwnd(), IDC_PORT, -cfg->ProxyPort, FALSE );
sendMsgToItem( IDC_HOST, WM_SETTEXT, 0, (LPARAM)(const char*)cfg->ProxyServer );
return FALSE;
}
virtual BOOL CALLBACK proc( UINT msg, WPARAM wp, LPARAM lp )
{
if((msg==WM_COMMAND) && (LOWORD(wp)==IDC_USEPROXY)){
BOOL x = ( BST_CHECKED==sendMsgToItem( IDC_USEPROXY, BM_GETCHECK ) );
::EnableWindow( item(IDC_HOST_N), x );
::EnableWindow( item(IDC_PORT_N), x );
::EnableWindow( item(IDC_HOST), x );
::EnableWindow( item(IDC_PORT), x );
return TRUE;
}
return FALSE;
}
virtual bool onOK()
{
char str[500];
sendMsgToItem( IDC_HOST, WM_GETTEXT, sizeof(str)-1, (LPARAM)str );
cfg->ProxyServer = str;
cfg->ProxyPort = ::GetDlgItemInt( hwnd(), IDC_PORT, NULL, FALSE );
if( BST_CHECKED!=sendMsgToItem( IDC_USEPROXY, BM_GETCHECK ) )
cfg->ProxyPort *= -1;
return true;
}
};
};
//----------------------------------------------------------------------------
// mirrorMan : バージョンチェック先サーバ情報管理
//----------------------------------------------------------------------------
class mirrorInfo
{
private:
enum { MAD, CSD, WAK, SERVER_NUM };
static const char* c_serv[SERVER_NUM];
static const char* c_path[SERVER_NUM];
static const char* c_nick[SERVER_NUM];
int mirrors[SERVER_NUM+1];
public:
mirrorInfo()
{
for(int i=0; i!=SERVER_NUM+1; ++i)
mirrors[i] = -1;
}
// どのサーバを先に見に行くか選択。
void setPreferedServer( int p )
{
switch( p )
{
default:
case MAD:
mirrors[0] = MAD;
mirrors[1] = CSD;
mirrors[2] = WAK;
break;
case CSD:
mirrors[0] = CSD;
mirrors[1] = MAD;
mirrors[2] = WAK;
break;
case WAK:
mirrors[0] = WAK;
mirrors[1] = MAD;
mirrors[2] = CSD;
break;
}
}
// m番目のミラーサーバがDownしてるっぽい場合、候補から消去
void server_is_down( int m )
{
for(int i=m; i!=SERVER_NUM; ++i)
mirrors[i] = mirrors[i+1];
}
// t番目のミラーサーバの情報を取得
bool isMirrorLeft( int m ) const { return mirrors[m] >= 0; }
kiStr serverName ( int m ) const { return c_serv[mirrors[m]]; }
kiStr basePath ( int m ) const { return c_path[mirrors[m]]; }
kiStr nickname ( int m ) const { return c_nick[mirrors[m]]; }
kiStr baseURL ( int m ) const {
return (kiStr("http://")+=c_serv[mirrors[m]])+=c_path[mirrors[m]];
}
};
// static constants
const char* mirrorInfo::c_serv[mirrorInfo::SERVER_NUM] = {
"www.madobe.net",
"www.csdinc.co.jp",
"archiver.wakusei.ne.jp",
};
const char* mirrorInfo::c_path[mirrorInfo::SERVER_NUM] = {
"/archiver/lib/",
"/archiver/lib/",
"/lib/",
};
const char* mirrorInfo::c_nick[mirrorInfo::SERVER_NUM] = {
"Madobe",
"CSD",
"Wakusei",
};
static mirrorInfo mirrorMan;
//----------------------------------------------------------------------------
// verDlg : 接続して実際のバージョンチェックを行う
//----------------------------------------------------------------------------
class verDlg : public kiDialog
{
public:
verDlg( HINTERNET hi )
: kiDialog( IDD_VERCHECK ), h(hi), ss(NULL), http(NULL) {}
~verDlg()
{
if( ss )
::InternetCloseHandle( ss );
if( http )
::InternetCloseHandle( http );
}
private:
HANDLE hT;
HINTERNET h, http, ss;
volatile bool m_endFlag;
BOOL onInit()
{
app()->setMainWnd( this );
sendMsgToItem( IDC_BAR, PBM_SETSTEP, 1 );
sendMsgToItem( IDC_BAR, PBM_SETRANGE, 0, MAKELPARAM(0,cfg->List.len()*3) );
m_endFlag = false;
DWORD id;
if( !(hT = ::CreateThread( NULL, 0, threadEntry, this, 0, &id )) )
end( IDCANCEL );
return FALSE;
}
bool onCancel()
{
m_endFlag = true;
DWORD ex;
while( ::GetExitCodeThread( hT, &ex ) && ex==STILL_ACTIVE )
::Sleep(0);
::CloseHandle( hT );
return true;
}
static DWORD WINAPI threadEntry( void* prm )
{
((verDlg*)prm)->threadWorker();
return 0;
}
private:
// 作業用マクロ
#define CHECK_CANCEL() if(m_endFlag) break
#define STEP_GRAPH() CHECK_CANCEL(); sendMsgToItem( IDC_BAR, PBM_STEPIT )
#define RETRY_() ::InternetCloseHandle( http ); http=NULL; goto retry;
#define RETRY_error() do{ ++Mir; RETRY_() }while(0)
#define RETRY_serverdown() do{ mirrorMan.server_is_down(Mir); RETRY_() }while(0)
#define INET_CONNECT( __s ) ::InternetConnect( h, __s, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0 )
#define HTTP_REQ( __n ) ::HttpOpenRequest( http, "GET", __n, "HTTP/1.0", NULL, NULL, 0, 0 )
#define HTTP_SEND() status=0,::HttpSendRequest( ss, NULL, 0, NULL, 0 ), ::HttpQueryInfoA( ss, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER,&status,&size,&dw),status;
void threadWorker()
{
// 作業変数
DWORD dw = 0, size = sizeof(DWORD), status;
kiStr name;
char buf[4000];
// メインループ
for( unsigned int i=0; i<cfg->List.len(); ++i )
{
if( !mirrorMan.isMirrorLeft(0) )
break; // どのサーバにも繋げない場合、終了
STEP_GRAPH();
//
// 未接続ならサーバへ繋ぐ
//
int Mir = 0;
retry:
if( !http )
{
if( !mirrorMan.isMirrorLeft(Mir) )
continue; // このDLLの情報取得は無理でした
http = INET_CONNECT( mirrorMan.serverName(Mir) );
if( !http )
RETRY_serverdown(); // 次のミラーを試す
}
//
// HTTPリクエスト作成
//
name = mirrorMan.basePath(Mir);
name+= cfg->List[i]->htmlName();
ss = HTTP_REQ( name );
if( !ss )
RETRY_serverdown();
CHECK_CANCEL();
//
// HTTPリクエスト送信
//
bool succeeded = false;
int try_auth = 3;
while( !succeeded && (try_auth-->0) )
{
status = HTTP_SEND();
if( status/100 == 2 ) // 200など。成功
{
succeeded = true;
break;
}
else if( status == 0 ) // タイムアウト。別サーバをtry
{
::InternetCloseHandle( ss );
RETRY_serverdown();
}
else if( status == 407 ) // 407 Proxy Authentication Required
{
// パスワードを打たせてもう一度
DWORD dwRet = ::InternetErrorDlg(
hwnd(), ss, GetLastError(),
FLAGS_ERROR_UI_FILTER_FOR_ERRORS |
FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS |
FLAGS_ERROR_UI_FLAGS_GENERATE_DATA,
NULL );
// 認証失敗したら終了
if( dwRet != ERROR_INTERNET_FORCE_RETRY )
{
::InternetCloseHandle( ss );
end( IDOK ); return;
}
continue;
}
else // その他のエラー。あきらめて次のDLLに進む
{
::InternetCloseHandle( ss );
break;
}
}
//
// 読込
//
STEP_GRAPH();
if( succeeded )
{
DWORD read;
::InternetReadFile( ss, buf, sizeof(buf)-1, &read );
::InternetCloseHandle( ss );
buf[ read ] = '\0';
}
//
// 解析
//
STEP_GRAPH();
if( succeeded )
cfg->List[i]->ParseHTML( buf );
}
if( !m_endFlag )
end( IDOK );
}
};
//----------------------------------------------------------------------------
// dllDlg: ダウンロードするDLLの選択
//----------------------------------------------------------------------------
class dllDlg : public kiDialog
{
public:
dllDlg( kiArray<DLLInfo*>& upd ) : kiDialog( IDD_CUSTOM2 ), m_upd(upd) {}
private:
kiArray<DLLInfo*>& m_upd;
BOOL onInit()
{
app()->setMainWnd( this );
SHFILEINFO fi;
HIMAGELIST hI = (HIMAGELIST)::SHGetFileInfo(
kiPath(kiPath::Sys)+="KERNEL32.DLL", 0, &fi, sizeof(fi),
SHGFI_SYSICONINDEX | SHGFI_ICON | SHGFI_SMALLICON );
int iDLL = fi.iIcon;
int iEXE = kiSUtil::getSysIcon( "exe" );
kiStr str;
kiListView list( this, IDC_UPDATELIST );
list.setImageList( NULL, hI );
list.insertColumn( 0, str.loadRsrc( IDS_LV_DLLNAME ), 120 );
list.insertColumn( 1, str.loadRsrc( IDS_LV_STATE ), 110 );
for( unsigned int i=0; i<m_upd.len(); i++ )
{
list.insertItem( i, m_upd[i]->getName(), 0, strcmpi( "dll", kiPath::ext(m_upd[i]->getName()) ) ? iEXE : iDLL );
list.setSubItem( i, 1, m_upd[i]->getState() );
}
sendMsgToItem( IDC_UPDATELIST,LVM_SETEXTENDEDLISTVIEWSTYLE,LVS_EX_CHECKBOXES,LVS_EX_CHECKBOXES );
for( i=0; i!=m_upd.len(); i++ )
ListView_SetCheckState( item(IDC_UPDATELIST), i, TRUE );
for( int j=0; j!=3; j++ )
sendMsgToItem( IDC_INSTMODE1+j,BM_SETCHECK,j==cfg->InstMode ? BST_CHECKED : BST_UNCHECKED );
return FALSE;
}
bool onCancel()
{
if( !cancelShiteIidesuka() )
return false;
kiListView( this, IDC_UPDATELIST ).setImageList( NULL, NULL );
return true;
}
bool onOK()
{
for( unsigned int i=0; i!=3; i++ )
if( BST_CHECKED == sendMsgToItem( IDC_INSTMODE1+i, BM_GETCHECK ) )
{
cfg->InstMode = i;
break;
}
kiArray<DLLInfo*> res;
res = m_upd, m_upd.empty();
for( i=0; i<res.len(); i++ )
if( ListView_GetCheckState( item(IDC_UPDATELIST), i ) )
m_upd.add( res[i] );
kiListView( this, IDC_UPDATELIST ).setImageList( NULL, NULL );
return true;
}
};
//----------------------------------------------------------------------------
// downloadDlg : ダウンロード
//----------------------------------------------------------------------------
class downloadDlg : public kiDialog, IBindStatusCallback
{
public:
downloadDlg( const kiArray<DLLInfo*>& lst, const kiPath& pth )
: kiDialog( IDD_VERCHECK ), m_lst( lst ), m_pth( pth ), m_cRef( 1 ){}
private:
const kiArray<DLLInfo*>& m_lst;
const kiPath& m_pth;
unsigned long m_cRef;
unsigned long m_total;
unsigned long m_step;
unsigned long m_startTime, m_lastTime;
bool m_stateCancel;
BOOL onInit()
{
app()->setMainWnd( this );
m_startTime = m_lastTime = ::GetTickCount();
m_stateCancel = false;
m_step = m_total = 0;
for( unsigned int i=0; i<m_lst.len(); i++ )
m_total += m_lst[i]->getSize();
sendMsgToItem( IDC_BAR, PBM_SETRANGE,0, MAKELPARAM(0,32768) );
setTimeInfo( 0 );
::ShowWindow( hwnd(), SW_SHOW );
::UpdateWindow( hwnd() );
kiPath url, fil;
// メインループ
for( i=0; i<m_lst.len(); i++ )
{
int Mir = 0;
retry:
if( !mirrorMan.isMirrorLeft(Mir) )
{
app()->msgBox( kiStr(1000).loadRsrc( IDS_DLERROR ), "caldix", MB_ICONINFORMATION|MB_SYSTEMMODAL );
break;
}
// "○○をダウンロード中..." のテキストを更新
char msg[300];
::wsprintf( msg, kiStr().loadRsrc(IDS_DOWNLOADING),
(const char*)m_lst[i]->getName(), (const char*)mirrorMan.nickname(Mir) );
sendMsgToItem( IDC_MSG, WM_SETTEXT, 0, (LPARAM)msg );
::EnableWindow( item(IDC_MSG), FALSE );
::EnableWindow( item(IDC_MSG), TRUE );
// ダウンロード元とダウンロード先
url = mirrorMan.baseURL(Mir), url += m_lst[i]->getArchiveName();
fil = m_pth, fil += m_lst[i]->getArchiveName();
if( S_OK != ::URLDownloadToFile( NULL, url, fil, 0, this ) )
{
++Mir;
goto retry;
}
m_step += m_lst[i]->getSize();
}
end( i==m_lst.len() ? IDOK : IDCANCEL );
return FALSE;
}
bool onCancel()
{
if( cancelShiteIidesuka() )
m_stateCancel = true;
return false;
}
public:
void setTimeInfo( unsigned long bytesread )
{
int sec = (bytesread==0 || m_lastTime==m_startTime)
? (int)((double)(m_total) / 7000)
: (int)((double)((m_total-bytesread)) * (m_lastTime - m_startTime) / 1000 / bytesread);
static char str[300];
::wsprintf( str, (const char*)(kiStr().loadRsrc(IDS_REST)),
(m_total-bytesread)/1000, sec/60, sec%60 );
sendMsgToItem( IDC_RESTTIME, WM_SETTEXT, 0, (LPARAM)str );
}
STDMETHODIMP_(ULONG) AddRef() { return (++m_cRef); }
STDMETHODIMP_(ULONG) Release() { return (m_cRef ? --m_cRef : 0L); }
STDMETHODIMP GetBindInfo( DWORD*, BINDINFO* ) { return E_NOTIMPL; }
STDMETHODIMP GetPriority( LONG* ) { return E_NOTIMPL; }
STDMETHODIMP OnLowResource( DWORD ) { return E_NOTIMPL; }
STDMETHODIMP OnDataAvailable( DWORD, DWORD, FORMATETC*, STGMEDIUM* ) { return E_NOTIMPL; }
STDMETHODIMP OnObjectAvailable( REFIID, IUnknown* ) { return E_NOTIMPL; }
STDMETHODIMP OnStartBinding( DWORD, IBinding* ) { return E_NOTIMPL; }
STDMETHODIMP OnStopBinding( HRESULT, LPCWSTR ) { return E_NOTIMPL; }
STDMETHODIMP QueryInterface( REFIID riid, void** ppv )
{
*ppv = NULL;
AddRef();
if( IsEqualIID( riid, IID_IUnknown ) || IsEqualIID( riid, IID_IBindStatusCallback ) )
*ppv = (IBindStatusCallback*)this;
else
{
Release();
return E_NOINTERFACE;
}
return NOERROR;
}
STDMETHODIMP OnProgress( ULONG cur, ULONG max, ULONG status, LPCWSTR txt )
{
msgLoop( PEEK );
if( m_stateCancel )
{
end( IDCANCEL );
return E_ABORT;
}
DWORD time = ::GetTickCount();
if( time-m_lastTime >= 5000 )
{
m_lastTime = time;
setTimeInfo( m_step+cur );
}
sendMsgToItem( IDC_BAR, PBM_SETPOS, (int)(((double)(m_step+cur))/m_total*32768) );
return S_OK;
}
};
//----------------------------------------------------------------------------
// instDlg : system等へインストール
//----------------------------------------------------------------------------
class instDlg : public kiDialog
{
public:
instDlg( kiArray<DLLInfo*>& upd, const kiPath& arcdir, const kiPath& work, const kiPath& to )
: kiDialog( IDD_INSTALL ), m_upd( upd ), m_arcdir( arcdir ), m_workdir( work ), m_dlldir( to ) {}
private:
kiArray<DLLInfo*>& m_upd;
const kiPath& m_arcdir;
const kiPath& m_workdir;
const kiPath& m_dlldir;
bool onCancel() { return false; }
bool onOK() { return false; }
BOOL onInit()
{
bool needreboot=false;
app()->setMainWnd( this );
::ShowWindow( hwnd(), SW_SHOW );
::UpdateWindow( hwnd() );
//-- 解凍&インストール開始〜 ---------------
char tmp[MAX_PATH];
kiPath arc, dll, path;
for( unsigned int i=0; i<m_upd.len(); i++ )
{
// 書庫名:フルパス
arc = m_arcdir, arc += m_upd[i]->getArchiveName();
// ドキュメント保存先:フルパス
dll = m_workdir, ::lstrcpyn(tmp,m_upd[i]->getName(),m_upd[i]->getName().len()-3), dll += tmp, dll.remove();
dll += "\\", dll.mkdir(), ::SetCurrentDirectory( dll );
// 解凍( path=書庫内のDLLの相対パス )
melt_it( arc, m_upd[i]->getName(), path );
// インストール
if( !install_it( dll, path ) )
{
needreboot = true;
}
if( path.isSame( "aish32.dll" ) )
{
if( !install_it( dll, "Aishmv32.dll" ) )
needreboot = true;
}
else if( path.isSame( "unrar32.dll" ) )
{
if( !install_it( dll, "unrar.dll" ) )
needreboot = true;
}
else if( path.isSame( "yz1.dll" ) )
{
if( !install_it( dll, "yzdec.exe" ) )
needreboot = true;
kiPath uyz( m_dlldir );
if( !kiSUtil::exist( uyz+="UnYz1.dll" ) )
if( !install_it( dll, "UnYz1.dll" ) )
needreboot = true;
}
else if( path.isSame( "bh32.dll" ) )
{
if( !install_it( dll, "bhsfx.exe" ) )
needreboot = true;
}
// メッセージ処理
msg();
}
//-- 解凍&インストール終了〜 ---------------
end( needreboot ? IDCANCEL : IDOK );
return FALSE;
}
private:
bool install_it( const char* position, const char* relpath )
{
kiPath from( position ); from += relpath;
if( ::GetFileAttributes(from) != 0xffffffff )
{
kiPath to( m_dlldir ); to += kiPath::name(relpath);
if( ::CopyFile( from, to, FALSE ) )
::DeleteFile( from );
else
{
// 再起動後コピー準備
move_later( from, to );
return false;
}
}
return true;
}
};
//----------------------------------------------------------------------------
// caldix : メインルーチン
//----------------------------------------------------------------------------
#include <ras.h>
#include <raserror.h>
class caldix : public kiApp
{
caldix()
{
shellInit();
kiutil::pathInit();
cfg = new CldxConfig;
}
void run( kiCmdParser& cmd )
{
// ダイアログ [全自動/カスタム]
if( !cfg->SuperAutoMode && !show( startDlg() ) )
return;
if( cfg->AutoMode )
{
// 全自動なら、インストール先をシステムにするかもしれない
if( !cfg->UseCustomDir )
cfg->InstallTo.beSpecialPath( kiPath::Sys );
}
else
{
// ダイアログ [インストール先とか]
if( !show( customDlg() ) )
return;
}
// 設定の調整
cfg->InstallTo.beBackSlash( true );
cfg->GenerateDLLList();
// 常時接続モードでない場合、接続を確立
if( !cfg->George )
if( ERROR_SUCCESS != ::InternetAttemptConnect(0) )
{
msgBox( kiStr().loadRsrc( IDS_NOINTERNET ) );
return;
}
// WinInet開始…
HINTERNET h = ::InternetOpen( cfg->UA, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );
if( !h )
{
msgBox( kiStr().loadRsrc( IDS_NOINTERNET ) );
return;
}
// プロクシの設定
if( cfg->ProxyServer.len() && cfg->ProxyPort>0 )
{
kiStr pr( "http=http://" );
pr += cfg->ProxyServer;
pr += ':';
pr += kiStr().setInt(cfg->ProxyPort);
INTERNET_PROXY_INFO pi = {INTERNET_OPEN_TYPE_PROXY,(const char*)pr,"<local>"};
::InternetSetOption( h, INTERNET_OPTION_PROXY, (void*)&pi, sizeof(pi) );
::UrlMkSetSessionOption( INTERNET_OPTION_PROXY, (void*)&pi, sizeof(pi), 0 );
}
// タイムアウトは5秒
DWORD TimeOut = 5*1000;
::InternetSetOption( h, INTERNET_OPTION_RECEIVE_TIMEOUT, &TimeOut, sizeof(TimeOut) );
// 接続先サーバ情報を設定から取得
mirrorMan.setPreferedServer( cfg->CheckServer );
// ダイアログ [WWWC META CHECK]
if( !show( verDlg(h) ) )
{
::InternetCloseHandle( h );
askRasHangUp();
return;
}
// バージョン比較
kiStr tmp;
kiArray<DLLInfo*> upd;
for( unsigned int i=0; i<cfg->List.len(); ++i )
if( cfg->List[i]->needToUpdate( cfg->InstallTo ) )
upd.add( cfg->List[i] );
if( upd.len()==0 )
{
::InternetCloseHandle( h );
msgBox( kiStr().loadRsrc( IDS_NONEED ), "caldix", MB_ICONINFORMATION );
askRasHangUp();
return;
}
if( ! cfg->AutoMode )
{
// ダイアログ [インストールするDLLとか]
if( !show(dllDlg(upd)) || upd.len()==0 )
{
::InternetCloseHandle( h );
askRasHangUp();
return;
}
}
// ダウンロード
char buf[MAX_PATH];
::GetTempFileName( kiPath( kiPath::Tmp ), "cld", 0, buf );
::DeleteFile( buf );
kiPath dlto( buf );
dlto.beBackSlash( true );
dlto.mkdir();
if( !show( downloadDlg(upd, dlto) ) )
{
dlto.remove();
::InternetCloseHandle( h );
askRasHangUp();
return;
}
// インストール準備
bool needreboot = false;
cfg->InstallTo.mkdir();
kiPath workDir( kiPath::Exe ); workDir.lower();
UINT drv = workDir.getDriveType();
if( strstr(workDir,"temporary internet files")!=NULL
|| (drv!=DRIVE_FIXED && drv!=DRIVE_REMOTE && drv!=DRIVE_UNKNOWN) )
workDir.beSpecialPath( kiPath::Dsk ), workDir.beBackSlash( true );
workDir += "cldx\\";
workDir.mkdir();
if( cfg->InstMode != 1 )
{
// 書庫コピー
kiPath from, to;
for( unsigned int i=0; i<upd.len(); i++ )
{
from = dlto, from += upd[i]->getArchiveName();
to = workDir, to += upd[i]->getArchiveName();
::CopyFile( from, to, FALSE );
}
}
if( cfg->InstMode != 0 )
{
// インストール
if( !show( instDlg( upd, dlto, workDir, cfg->InstallTo ) ) )
needreboot = true;
}
// 閉じ処理
dlto.remove();
::InternetCloseHandle( h );
if( !needreboot )
{
if( ! cfg->SuperAutoMode )
msgBox( kiStr(500).loadRsrc( IDS_FINISHED ), "caldix", MB_ICONINFORMATION|MB_SYSTEMMODAL );
askRasHangUp();
}
else
if( IDYES!=msgBox( kiStr(1000).loadRsrc( IDS_REBOOT ), "caldix", MB_ICONINFORMATION|MB_YESNO|MB_SYSTEMMODAL ) )
needreboot = false;
// 簡易説明書出力
if( ::GetACP() == 932 )
{
kiFile fp;
if( fp.open( kiPath(workDir)+="読んでね.txt", false ) )
{
static const char * text =
"このフォルダには、caldixでダウンロードされた\r\n"
"DLLの説明書を格納してあります。よくお読み下さい。\r\n"
"\r\n"
"★ UNZIP32.DLL を企業内等で利用する場合には、必ず\r\n"
"★ ライセンス契約が必要です。詳細は下記ページにて。\r\n"
"★ http://www.csdinc.co.jp/archiver/lib/unzip32.html\r\n"
"\r\n"
"それぞれのDLLの作者様のサイトは、\r\n"
" 『統合アーカイバプロジェクト』\r\n"
" http://www.csdinc.co.jp/archiver/ \r\n"
"からリンクをたどって訪れることが出来ます。\r\n"
"是非一度は行ってみることをお勧めします。\r\n"
"\r\n"
"DLLのアンインストールは uncaldix が便利。\r\n"
" http://www6.plala.or.jp/amasoft/soft/uncaldix.html\r\n"
"\r\n"
"caldixに関するご質問等は( http://www.kmonos.net/ )へ\r\n"
; fp.write( text, ki_strlen(text) );
}
}
// 出力先開く
if( cfg->ShowReadMe )
{
char cmdline[1000];
// コメントアウトcaldixF
/*
::wsprintf( cmdline, "explorer \"%s\"", (const char*)workDir );
::WinExec( cmdline, SW_SHOWDEFAULT );
*/
// コメントアウトここまでcaldixF
// 挿入caldixF
char wdir[MAX_PATH*3];
// caldixのパスを取得
GetModuleFileName(NULL,wdir,MAX_PATH);
// caldix.exe→cldxにする
lstrcpy(GetFileName(wdir),"cldx");
// prefixとpostfixをつける( modified by k.inaba )
bool bNeedQuote = false;
for(int i=0; i!=cfg->Filer.len(); ++i)
if(cfg->Filer[i]==' ') { bNeedQuote=true; break; }
::wsprintf( cmdline,
bNeedQuote ? "\"%s\" %s\"%s\"%s" : "%s %s\"%s\"%s",
(const char*)cfg->Filer,
(const char*)cfg->F_Prefix, wdir, (const char*)cfg->F_Suffix);
// ファイラ起動( modified by k.inaba )
STARTUPINFO si = {sizeof(si)};
PROCESS_INFORMATION pi;
{
kiPath original_cur(kiPath::Cur), sys(kiPath::Sys); // 大丈夫なはずだけど念のためのカレント移動
::SetCurrentDirectory(sys);
::CreateProcess( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, wdir, &si, &pi );
::SetCurrentDirectory(original_cur);
}
::CloseHandle(pi.hProcess);
::CloseHandle(pi.hThread);
// 挿入ここまでcaldixF
}
if( needreboot )
rebootWindows(); // 再起動でーす
}
void askRasHangUp()
{
// 訊かないモード
if( cfg->George )
return;
// DLL,及び必要な関数をロード
HINSTANCE rasdll = kiutil::safepathLoadLibrary( "RASAPI32.DLL" );
if( rasdll == NULL )
return;
typedef DWORD (WINAPI * rE)( LPRASCONN,LPDWORD,LPDWORD );
typedef DWORD (WINAPI * rH)( HRASCONN );
typedef BOOL (WINAPI * rS)( HRASCONN,LPRASCONNSTATUS );
rE RasEnumConnections = (rE)::GetProcAddress( rasdll, "RasEnumConnectionsA" );
rH RasHangUp = (rH)::GetProcAddress( rasdll, "RasHangUpA" );
rS RasGetConnectStatus= (rS)::GetProcAddress( rasdll, "RasGetConnectStatusA" );
if( RasEnumConnections!=NULL && RasHangUp!=NULL && RasGetConnectStatus!=NULL )
{
RASCONN* RasConn = new RASCONN[1];
DWORD Num, Size = sizeof(RASCONN);
RasConn->dwSize = sizeof(RASCONN);
int Sts = RasEnumConnections( RasConn, &Size, &Num );
if( (Sts==ERROR_BUFFER_TOO_SMALL) || (Sts==ERROR_NOT_ENOUGH_MEMORY) )
{
delete [] RasConn;
RasConn = new RASCONN[Size/sizeof(RASCONN)];
Sts = RasEnumConnections( RasConn, &Size, &Num );
}
if( Sts==0 && Num>=1 )
{
// 訊く。
if( IDYES==msgBox( kiStr(1000).loadRsrc( IDS_RASHANGUP ), "caldix", MB_ICONINFORMATION|MB_YESNO|MB_SYSTEMMODAL ) )
{
// 切る
RASCONNSTATUS RasSts;
RasSts.dwSize = sizeof(RASCONNSTATUS);
for( DWORD i=0; i<Num; i++ )
{
RasHangUp( RasConn->hrasconn );
while( RasGetConnectStatus( RasConn->hrasconn, &RasSts ) != ERROR_INVALID_HANDLE )
::Sleep( 10 );
}
}
}
delete [] RasConn;
}
::FreeLibrary( rasdll );
}
~caldix()
{
delete cfg;
}
friend void kilib_create_new_app();
};
void kilib_create_new_app()
{
new caldix;
}