// NoahXt.cpp
// -- all of 'NoahXt.dll' (ShellExtension && Configuration of Noah)
#undef WINVER
#define WINVER 0x0400
#ifndef STRICT
#define STRICT
#endif
#define INC_OLE2
#undef _WIN32_IE
#define _WIN32_IE 0x0200
#include <windows.h>
#include <windowsx.h>
#include <shlobj.h>
#include <lmaccess.h>
// カレントディレクトリを安全なところに移してLoadLibrary
static HMODULE safepathLoadLibrary(LPCTSTR lpFileName)
{
char original_cur[MAX_PATH], sys[MAX_PATH];
::GetCurrentDirectory(MAX_PATH, original_cur);
::GetSystemDirectory(sys, MAX_PATH);
::SetCurrentDirectory(sys);
HMODULE han = ::LoadLibrary(lpFileName);
::SetCurrentDirectory(original_cur);
return han;
}
//-------------------------------------------------------
//-- Noah Config API ------------------------------------
//-------------------------------------------------------
bool WINAPI Init();
void WINAPI LoadSE( bool* a, bool* x );
void WINAPI SaveSE( bool a, bool x );
void WINAPI LoadAS( bool asso[] );
void WINAPI SaveAS( bool asso[] );
void WINAPI LoadASEx( const char* ext, bool* x );
void WINAPI SaveASEx( const char* ext, bool x );
//-------------------------------------------------------
//-- グローバル変数 -------------------------------------
//-------------------------------------------------------
char g_szNoah[MAX_PATH]; // Where is Noah ?
char g_szDLL[MAX_PATH]; // What's my name ?
bool g_bJpn; // am I in Japanese Mode ?
bool g_isNT; // is Windows NT/2000 ?
int g_cRef; // reference counter
bool g_bChanged; // association changed ?
//-------------------------------------------------------
//-- GUID {953AFAE9-C2A9-4674-9811-D7E281B001E1} --------
//-------------------------------------------------------
static const GUID CLSID_NoahXt =
{ 0x953afae9, 0xc2a9, 0x4674, { 0x98, 0x11, 0xd7, 0xe2, 0x81, 0xb0, 0x1, 0xe1 } };
static const char* ProgID_NoahXt = "NoahXt";
//--------------------------------------------------------
//-- シェルエクステンション・本体 --------------------------
//--------------------------------------------------------
class noahXt : public IContextMenu, IShellExtInit
{
public:
noahXt() { m_szDir[0]=0; m_pDataObj=NULL; m_cRef=0L; g_cRef++; }
~noahXt() { if( m_pDataObj ) m_pDataObj->Release(); g_cRef--; }
STDMETHODIMP_(ULONG) AddRef() { return (++m_cRef); }
STDMETHODIMP_(ULONG) Release() { if( --m_cRef )return m_cRef; delete this; return 0L; }
STDMETHODIMP QueryInterface( REFIID riid, void** ppv )
{
*ppv = NULL;
AddRef();
if( IsEqualIID( riid, IID_IUnknown ) || IsEqualIID( riid, IID_IShellExtInit ) )
*ppv = (IShellExtInit*)this;
else if( IsEqualIID( riid, IID_IContextMenu ) )
*ppv = (IContextMenu*)this;
else
{
Release();
return E_NOINTERFACE;
}
return NOERROR;
}
STDMETHODIMP Initialize( const ITEMIDLIST* pF, IDataObject* pD, HKEY )
{
::SHGetPathFromIDList( pF, m_szDir );
if( m_pDataObj )m_pDataObj->Release();
if( pD ) (m_pDataObj=pD)->AddRef();
return NOERROR;
}
#define CMPR_CMD_E ("Com&press Here")
#define EXTR_CMD_E ("E&xtract Here")
#define CMPR_CMD (g_bJpn ? "ここに圧縮(&P)" : CMPR_CMD_E)
#define EXTR_CMD (g_bJpn ? "ここに解凍(&X)" : EXTR_CMD_E)
#define CMPR_HLP (g_bJpn ? "ファイルをNoahで圧縮します。" : "Compress These Files By Noah")
#define EXTR_HLP (g_bJpn ? "ファイルをNoahで展開" : "Extract Files By Noah")
// 右クリックメニューへ追加
STDMETHODIMP QueryContextMenu( HMENU h, UINT i, UINT id, UINT idLast, UINT flag )
{
if( (flag&0x000F)!=CMF_NORMAL && !(flag&CMF_VERBSONLY) && !(flag&CMF_EXPLORE) )
return NOERROR;
// レジストリから設定読み込み
// できれば、ここでm_bEXTに関しては拡張子判定を行いたいところ…(^^;
LoadSE( &m_bCMP, &m_bEXT );
if( m_bCMP ) ::InsertMenu( h, i++, MF_STRING|MF_BYPOSITION, id++, CMPR_CMD );
if( m_bEXT ) ::InsertMenu( h, i++, MF_STRING|MF_BYPOSITION, id++, EXTR_CMD );
return MAKE_HRESULT( SEVERITY_SUCCESS, 0, id );
}
// コマンド実行
STDMETHODIMP InvokeCommand( LPCMINVOKECOMMANDINFO lpcmi )
{
if( 0==HIWORD(lpcmi->lpVerb) )
switch( filter_cmd( LOWORD(lpcmi->lpVerb) ) )
{
case 0: return operation( "-a" );
case 1: return operation( "-x" );
}
return E_INVALIDARG;
}
// ヘルプ文字列など
STDMETHODIMP GetCommandString( UINT cmd, UINT flag, UINT*, LPSTR pszName, UINT cchMax )
{
cmd = filter_cmd( cmd );
if( cmd==2 )
return E_FAIL;
switch( flag )
{
case GCS_HELPTEXT: ::lstrcpyn( pszName, cmd==0 ? CMPR_HLP : EXTR_HLP, cchMax ); break;
case GCS_VERB: ::lstrcpyn( pszName, cmd==0 ? CMPR_CMD_E : EXTR_CMD_E, cchMax ); break;
}
return NOERROR;
}
private:
// コマンドIDを compress=0, melt=1, else=2 にフィルタリング
UINT filter_cmd( UINT i )
{
if( m_bCMP )if( m_bEXT )return (i<=1 ? i : 2);
else return (i==0 ? 0 : 2);
else if( m_bEXT )return (i==0 ? 1 : 2);
else return 2;
}
// Noah.exeへ渡す処理 "Compress Here" or "Extract Here"
STDMETHODIMP operation( const char* opt )
{
STGMEDIUM md;
FORMATETC fe = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
if( SUCCEEDED( m_pDataObj->GetData( &fe, &md ) ) )
{
const HDROP& hDrop = (HDROP)md.hGlobal;
const int num = ::DragQueryFile( hDrop, 0xffffffff, NULL, 0 );
if( num )
{
// main command
char* cmd = new char[10 + MAX_PATH * (num+2)];
::lstrcpy( cmd, g_szNoah );
::lstrcat( cmd, " " );
::lstrcat( cmd, opt );
// destdir
::lstrcat( cmd, " \"-D" );
::lstrcat( cmd, m_szDir );
::lstrcat( cmd, "\"" );
// filelist
char str[MAX_PATH];
for( int i=0; i!=num; i++ )
{
::DragQueryFile( hDrop, i, str, sizeof(str) );
::lstrcat( cmd, " \"" );
::lstrcat( cmd, str );
::lstrcat( cmd, "\"" );
}
// call 'Noah'
::WinExec( cmd, SW_SHOWDEFAULT );
delete [] cmd;
}
::ReleaseStgMedium( &md );
}
return NOERROR;
}
private:
ULONG m_cRef;
IDataObject* m_pDataObj;
char m_szDir[MAX_PATH];
bool m_bCMP, m_bEXT;
};
//-- クラス工場 -------------------------------------------
class noahXtClassFactory : public IClassFactory
{
public:
noahXtClassFactory() { m_cRef = 0L; g_cRef++; }
~noahXtClassFactory() { g_cRef--; }
STDMETHODIMP_(ULONG) AddRef() { return (++m_cRef); }
STDMETHODIMP_(ULONG) Release() { if( --m_cRef )return m_cRef; delete this; return 0L; }
STDMETHODIMP LockServer( BOOL ) { return NOERROR; }
STDMETHODIMP QueryInterface( REFIID riid, void** ppv )
{
*ppv = NULL;
AddRef();
if( IsEqualIID( riid, IID_IUnknown ) || IsEqualIID( riid, IID_IClassFactory ) )
{
*ppv = (IClassFactory*)this;
return NOERROR;
}
Release();
return E_NOINTERFACE;
}
STDMETHODIMP CreateInstance( IUnknown* pOuter, REFIID riid, void** ppvObj )
{
*ppvObj = NULL;
if( pOuter )
return CLASS_E_NOAGGREGATION;
noahXt* pXt = new noahXt;
return pXt ? pXt->QueryInterface( riid, ppvObj ) : E_OUTOFMEMORY;
}
private:
ULONG m_cRef;
};
//-- システム向けAPI ---------------------------------------
extern "C" int APIENTRY
DllMain( HINSTANCE inst, DWORD why, LPVOID reserved )
{
if( why==DLL_PROCESS_ATTACH )
{
::GetModuleFileName( inst, g_szDLL, sizeof(g_szDLL) );
::lstrcpy( g_szNoah, g_szDLL );
for( char *p=g_szNoah,*y=g_szNoah-1; *p; p=::CharNext(p) )
if( *p=='\\' )
y=p;
::lstrcpy( y+1, "Noah.exe" );
::GetShortPathName( g_szNoah, g_szNoah, MAX_PATH );
OSVERSIONINFO osVer;
osVer.dwOSVersionInfoSize = sizeof(osVer);
::GetVersionEx( &osVer );
g_isNT = ( osVer.dwPlatformId == VER_PLATFORM_WIN32_NT );
g_bJpn = (::GetUserDefaultLangID()==0x0411);
g_cRef = 0;
g_bChanged = false;
}
else if( why==DLL_PROCESS_DETACH )
{
if( g_bChanged )
::SHChangeNotify( SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL );
}
return TRUE;
}
STDAPI DllCanUnloadNow()
{
return ( g_cRef==0 ? S_OK : S_FALSE );
}
STDAPI DllGetClassObject( REFCLSID rclsid, REFIID riid, void** ppvOut )
{
*ppvOut = NULL;
if( IsEqualIID( rclsid, CLSID_NoahXt ) )
{
noahXtClassFactory* p = new noahXtClassFactory;
return p->QueryInterface( riid, ppvOut );
}
return CLASS_E_CLASSNOTAVAILABLE;
}
//--------------------------------------------------------
//--------------------------------------------------------
//--------------------------------------------------------
//-- kiRegKey from K.I.LIB -------------------------//
//------ 'not using kiStr && REG_SZ only' version --//
class kiRegKey
{
public:
kiRegKey()
{ m_hKey = NULL; }
~kiRegKey()
{ close(); }
operator HKEY() const
{ return m_hKey; }
bool open( HKEY parent, LPCTSTR keyname, REGSAM access )
{ close(); return (ERROR_SUCCESS == ::RegOpenKeyEx( parent, keyname, 0, access, &m_hKey )); }
bool create( HKEY parent, LPCTSTR keyname, REGSAM access )
{ close(); DWORD x; return (ERROR_SUCCESS == ::RegCreateKeyEx( parent, keyname, 0, REG_NONE, REG_OPTION_NON_VOLATILE, access, NULL, &m_hKey, &x )); }
void close()
{ if( m_hKey ) ::RegCloseKey( m_hKey ); }
static bool exist( HKEY parent, LPCTSTR keyname )
{ HKEY k; if( ERROR_SUCCESS!=::RegOpenKeyEx( parent,keyname,0,KEY_READ,&k ) ) return false; ::RegCloseKey( k ); return true; }
bool set( LPCTSTR valname, LPCTSTR val )
{ return (ERROR_SUCCESS == ::RegSetValueEx( m_hKey, valname, 0, REG_SZ, (BYTE*)val, ::lstrlen(val)+1 )); }
bool get( LPCTSTR valname, char* val, DWORD siz )
{ return ( ERROR_SUCCESS == RegQueryValueEx( m_hKey, valname, NULL, NULL, (BYTE*)val, &siz )); }
bool del( LPCTSTR valname )
{ return (ERROR_SUCCESS == RegDeleteValue( m_hKey, valname )); }
static void delSubKey( HKEY k, LPCTSTR n )
{
if( !g_isNT )
{
::RegDeleteKey( k, n );
return;
}
// NT系では、サブキーのあるキーは消せないので再帰的に。
// しかもEnum中にDeleteはできない上にvector<string>等も
// 封印しているためわけのわからんコードになってます。
// 消したいキーを開く
HKEY k2;
while( ERROR_SUCCESS == ::RegOpenKeyEx( k,n,0,KEY_ENUMERATE_SUB_KEYS|KEY_SET_VALUE,&k2 ) )
{
// 1個目の子キー名を取得
char buf[200];
DWORD bs = sizeof(buf);
if( ERROR_SUCCESS == ::RegEnumKeyEx( k2,0,buf,&bs,NULL,NULL,NULL,NULL ) )
{
// あればそれを削除
delSubKey( k2, buf );
::RegCloseKey( k2 );
}
else
{
// なければ、消したいキーを消せる
::RegCloseKey( k2 );
::RegDeleteKey( k, n );
return;
}
}
}
private:
HKEY m_hKey;
};
//--------------------------------------------------------
//-- Noahの設定用APIなど ----------------------------------
//--------------------------------------------------------
char g_szAsCmd[MAX_PATH+10];
char g_szAsIcon[MAX_PATH+10];
// 管理者権限判別
//-- IsAdmin() : very very thanks! to ardry, the author of 'meltice'.
bool IsAdmin()
{
bool isadmin=false;
//-- 9x対策のため、動的にDLLロード
HINSTANCE hInstDll = safepathLoadLibrary( "NetAPI32" );
if( !hInstDll )
return false;
//-- NetUserGetLocalGroupes API 取得
typedef NET_API_STATUS (NET_API_FUNCTION *PNETUSRGETLCLGRP)(LPCWSTR,wchar_t *,DWORD,DWORD,VOID*,DWORD,LPDWORD,LPDWORD);
PNETUSRGETLCLGRP pNetUserGetLocalGroups = (PNETUSRGETLCLGRP)::GetProcAddress(hInstDll, "NetUserGetLocalGroups");
if( !pNetUserGetLocalGroups )
{
::FreeLibrary( hInstDll );
return false;
}
//-- ユーザー名取得
char userA[256];
wchar_t userW[256];
DWORD tmp = 256;
::GetUserName( userA, &tmp );
::MultiByteToWideChar( CP_ACP, 0, userA, -1, userW, 255 );
//-- 本筋
LOCALGROUP_USERS_INFO_0* pBuf;
DWORD entry;
char buf[256];
if( 0 == pNetUserGetLocalGroups(NULL,userW,0,0,(BYTE**)&pBuf,-1,&entry,&tmp) )
{
for( unsigned int i=0; i<entry; i++ )
{
::WideCharToMultiByte( CP_ACP, 0, pBuf[i].lgrui0_name, -1, buf, 256, NULL, NULL );
if( 0 == ::lstrcmp( buf, "Administrators" ) )
{
isadmin=true;
break;
}
}
//-- メモリ解放
typedef NET_API_STATUS (NET_API_FUNCTION * PNETAPIBUFFERFREE)(void*);
PNETAPIBUFFERFREE pNetApiBufferFree = (PNETAPIBUFFERFREE)::GetProcAddress( hInstDll, "NetApiBufferFree" );
if( pNetApiBufferFree )
pNetApiBufferFree( pBuf );
}
//-- DLL解放
::FreeLibrary( hInstDll );
return isadmin;
}
// レジストリへの書き込み権限判定…うまくいかないらしい
//
//bool IsRegWritable()
//{
// HKEY key;
// if( ERROR_SUCCESS != // 適当なクラスキーへの書き込み権限を調べる
// ::RegOpenKeyEx( HKEY_CLASSES_ROOT, "ttffile", 0, KEY_WRITE, &key ) )
// return false;
// ::RegCloseKey( key );
// return true;
//}
//** bool Init()
//**
//** 設定画面用に起動するときは最初にコレを呼ぶこと。
//** false が返ってきたときは、諸事情により利用できないことを示す。
bool WINAPI Init()
{
::wsprintf( g_szAsIcon, "%s,%%d", g_szDLL );
::wsprintf( g_szAsCmd , "%s -x \"%%1\"", g_szNoah );
if( g_isNT )
if( !IsAdmin() )
// if( !IsRegWritable() )
return false;
return true;
}
//** void LoadSE( bool* a, bool* x )
//**
//** シェルエクステンションの設定を返す。
//** a: [ここに圧縮]がONか否か x: [ここに解凍]がONか否か
void WINAPI LoadSE( bool* a, bool* x )
{
*a = kiRegKey::exist( HKEY_CLASSES_ROOT, "CLSID\\{953AFAE9-C2A9-4674-9811-D7E281B001E1}\\CShl" );
*x = kiRegKey::exist( HKEY_CLASSES_ROOT, "CLSID\\{953AFAE9-C2A9-4674-9811-D7E281B001E1}\\MShl" );
}
//** void SaveSE( bool a, bool x )
//**
//** シェルエクステンションの設定を保存する。
//** a: [ここに圧縮]がONか否か x: [ここに解凍]がONか否か
void WINAPI SaveSE( bool a, bool x )
{
kiRegKey key, key2;
if( !a && !x )
{
kiRegKey::delSubKey( HKEY_CLASSES_ROOT, "CLSID\\{953AFAE9-C2A9-4674-9811-D7E281B001E1}" );
kiRegKey::delSubKey( HKEY_CLASSES_ROOT, "Folder\\shellex\\DragDropHandlers\\NoahXt" );
kiRegKey::delSubKey( HKEY_CLASSES_ROOT, "Drive\\shellex\\DragDropHandlers\\NoahXt" );
if( key.open( HKEY_CLASSES_ROOT, "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved", KEY_SET_VALUE ) )
key.del( "{953AFAE9-C2A9-4674-9811-D7E281B001E1}" );
}
else
{
// CLSID 登録
key.create( HKEY_CLASSES_ROOT, "CLSID\\{953AFAE9-C2A9-4674-9811-D7E281B001E1}", KEY_WRITE );
key.set( "", ProgID_NoahXt );
key2.create( key, "InprocServer32", KEY_WRITE );
key2.set( "", g_szDLL );
key2.set( "ThreadingModel", "Apartment" );
if(a)key2.create( key, "CShl", KEY_READ );
else kiRegKey::delSubKey( key, "CShl" );
if(x)key2.create( key, "MShl", KEY_READ );
else kiRegKey::delSubKey( key, "MShl" );
// Folder の DnD Handler として登録
key.create( HKEY_CLASSES_ROOT, "Folder\\shellex\\DragDropHandlers\\NoahXt", KEY_WRITE );
key.set( "", "{953AFAE9-C2A9-4674-9811-D7E281B001E1}" );
// Drive の DnD Handler として登録
key.create( HKEY_CLASSES_ROOT, "Drive\\shellex\\DragDropHandlers\\NoahXt", KEY_WRITE );
key.set( "", "{953AFAE9-C2A9-4674-9811-D7E281B001E1}" );
// NT系用に、Approved List に書いておく
if( g_isNT && key.open( HKEY_CLASSES_ROOT, "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved", KEY_SET_VALUE ) )
key.set( "{953AFAE9-C2A9-4674-9811-D7E281B001E1}", ProgID_NoahXt );
}
}
void asso_on( const char* ext, const int no );
void asso_off( const char* ext, const int no );
bool is_asso_on( const char* ext );
enum { A_BEGIN, LZH=0, ZIP, CAB, RAR, TAR, YZ1, GCA, ARJ, BGA, ACE, CPT, JAK, A_END,
OTH=A_END, SvnZ=CPT };
static const char* ext_list[] = {
"lzh\0lzs\0lha\0",
"zip\0",
"cab\0",
"rar\0",
"tar\0tgz\0tbz\0taz\0gz\0bz2\0z\0xz\0lzma\0",
"yz1\0",
"gca\0",
"arj\0",
"gza\0bza\0",
"ace\0",
"cpt\0",
"jak\0",
};
//** void LoadAS( bool asso[] )
//**
//** 標準の関連付けの設定を返す。
//** LZH=0, ZIP, CAB, RAR, TAR, YZ1, GCA, ARJ, BGA, ACE, CPT, JAK
void WINAPI LoadAS( bool asso[] )
{
for( int i=A_BEGIN; i<A_END; i++ )
asso[i] = is_asso_on( ext_list[i] );
}
//** void SaveAS( bool asso[] )
//**
//** 標準の関連付けの設定を保存。
//** LZH=0, ZIP, CAB, RAR, TAR, YZ1, GCA, ARJ, BGA, ACE, CPT, JAK
void WINAPI SaveAS( bool asso[] )
{
for( int i=A_BEGIN; i<A_END; i++ )
{
int icon_type = i;
if( i==CPT ) icon_type = OTH; // v3.195: cptは、"その他"アイコン
if( asso[i] )
asso_on( ext_list[i], icon_type );
else
asso_off( ext_list[i], icon_type );
}
}
//** void LoadASEx( const char* ext, bool* x )
//**
//** 指定した拡張子がNoahに関連付けられているかどうかを返す
void WINAPI LoadASEx( const char* ext, bool* x )
{
*x = is_asso_on( ext );
}
//** void SaveASEx( const char* ext, bool x )
//**
//** 指定した拡張子をNoahに関連付けたり解除したり
void WINAPI SaveASEx( const char* ext, bool x )
{
int icon_type = OTH; // デフォルトは"その他"アイコン
if( 0==lstrcmp(ext,"7z") ) icon_type = SvnZ; // v3.195: 7zに限り、7z専用アイコン
if( x ) asso_on( ext, icon_type );
else asso_off( ext, icon_type );
}
//---------------------------------------------------------------
#define step(_x) (_x+=::lstrlen(_x)+1)
#define MltCmd (g_bJpn ? "解凍(&E)" : "&Extract")
#define JntCmd (g_bJpn ? "結合(&E)" : "Combin&e")
#define MltTyp (g_bJpn ? "書庫(%s)" : "Archive(%s)")
#define JntTyp (g_bJpn ? "分割ファイル(%s)" : "RipperedFile(%s)")
#define CmdName(_n) (_n==JAK ? JntCmd : MltCmd)
#define TypName(_n) (_n==JAK ? JntTyp : MltTyp)
static void recover_zip()
{
if( kiRegKey::exist( HKEY_CLASSES_ROOT, "CompressedFolder" ) )
{
kiRegKey key, key2;
if( key.create( HKEY_CLASSES_ROOT, ".zip", KEY_WRITE ) )
{
key.set( "", "CompressedFolder" );
if( key2.create( key, "ShellNew", KEY_WRITE ) )
key2.set( "NullFIle", "" );
}
}
}
static void recover_cab()
{
if( kiRegKey::exist( HKEY_CLASSES_ROOT, "CLSID\\{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}" ) )
{
kiRegKey key;
if( key.create( HKEY_CLASSES_ROOT, ".cab", KEY_WRITE ) )
key.set( "", "CLSID\\{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}" );
}
}
void asso_on( const char* ext, const int no )
{
if( is_asso_on( ext ) )
return;
g_bChanged = true;
kiRegKey key, key2, key3, key4;
char str[500],asc[20]="NoahXt.";
::lstrcpy( asc+7, ext );
for( const char* p=ext; *p; step(p) )
{
//-- "HKCR/.lzh" = "NoahXt.lzh", "HKCR/.lzs" = "NoahXt.lzh" ...
str[0]='.', ::lstrcpy( str+1, p );
if( key.create( HKEY_CLASSES_ROOT, str, KEY_WRITE ) )
{
key.set( "", asc );
kiRegKey::delSubKey( key, "ShellNew" );
}
}
if( key.create( HKEY_CLASSES_ROOT, asc, KEY_WRITE ) )
{
//-- "HKCR/NoahXt.lzh" = "書庫( lzh )"
::wsprintf( str, TypName(no), ext );
key.set( "", str );
key.del( "EditFlags" );
if( key2.create( key, "DefaultIcon", KEY_WRITE ) )
{
//-- "HKCR/NoahXt.lzh/DefaultIcon" = "...Noah.exe, 1"
::wsprintf( str, g_szAsIcon, no );
key2.set( "", str );
}
if( key2.create( key, "Shell", KEY_WRITE ) )
{
//-- "HKCR/NoahXt.lzh/Shell" = "Open"
key2.set( "", "Open" );
if( key3.create( key2, "Open", KEY_WRITE ) )
{
//-- "HKCR/NoahXt.lzh/Shell/Open" = "解凍(&X)"
key3.set( "", CmdName(no) );
if( key4.create( key3, "Command", KEY_WRITE ) )
//-- "HKCR/NoahXt.lzh/Shell/Open/Command" = "...Noah.exe -x "%1""
key4.set( "", g_szAsCmd );
}
}
}
}
void asso_off( const char* ext, const int no )
{
if( !is_asso_on( ext ) )
return;
g_bChanged = true;
//-- delete "HKCR/NoahXt.lzh"
char str[20] = "NoahXt.";
::lstrcpy( str+7, ext );
kiRegKey::delSubKey( HKEY_CLASSES_ROOT, str );
//-- delete "HKCR/.lzh" "HKCR/.lzs" ...
for( const char* p=ext; *p; step(p) )
{
str[0]='.', ::lstrcpy( str+1, p );
kiRegKey::delSubKey( HKEY_CLASSES_ROOT, str );
}
switch( no )
{
// CAB, ZIP to Windows Default Association
case CAB: recover_cab(); break;
case ZIP: recover_zip(); break;
}
}
bool is_asso_on( const char* ext )
{
//-- "HKCR/.lzh" exists ?
char str[20] = ".";
::lstrcpy( str+1, ext );
kiRegKey key;
if( !key.open( HKEY_CLASSES_ROOT, str, KEY_READ ) )
return false;
if( !key.get( "", str, 20 ) )
return false;
//-- the value of "HKCR/.lzh" is "NoahXt.lzh" ?
char asc[20] = "NoahXt.";
::lstrcpy( asc+7, ext );
return ( 0==::lstrcmp( str, asc ) );
}