1 // NoahXt.cpp
2 // -- all of 'NoahXt.dll' (ShellExtension && Configuration of Noah)
3
4 #undef WINVER
5 #define WINVER 0x0400
6 #ifndef STRICT
7 #define STRICT
8 #endif
9 #define INC_OLE2
10 #undef _WIN32_IE
11 #define _WIN32_IE 0x0200
12
13 #include <windows.h>
14 #include <windowsx.h>
15 #include <shlobj.h>
16 #include <lmaccess.h>
17
18 // カレントディレクトリを安全なところに移してLoadLibrary
19 static HMODULE safepathLoadLibrary(LPCTSTR lpFileName)
20 {
21 char original_cur[MAX_PATH], sys[MAX_PATH];
22 ::GetCurrentDirectory(MAX_PATH, original_cur);
23 ::GetSystemDirectory(sys, MAX_PATH);
24 ::SetCurrentDirectory(sys);
25 HMODULE han = ::LoadLibrary(lpFileName);
26 ::SetCurrentDirectory(original_cur);
27 return han;
28 }
29
30 //-------------------------------------------------------
31 //-- Noah Config API ------------------------------------
32 //-------------------------------------------------------
33
34
35
36 bool WINAPI Init();
37 void WINAPI LoadSE( bool* a, bool* x );
38 void WINAPI SaveSE( bool a, bool x );
39 void WINAPI LoadAS( bool asso[] );
40 void WINAPI SaveAS( bool asso[] );
41 void WINAPI LoadASEx( const char* ext, bool* x );
42 void WINAPI SaveASEx( const char* ext, bool x );
43
44
45
46 //-------------------------------------------------------
47 //-- グローバル変数 -------------------------------------
48 //-------------------------------------------------------
49
50
51
52 char g_szNoah[MAX_PATH]; // Where is Noah ?
53 char g_szDLL[MAX_PATH]; // What's my name ?
54 bool g_bJpn; // am I in Japanese Mode ?
55 bool g_isNT; // is Windows NT/2000 ?
56 int g_cRef; // reference counter
57 bool g_bChanged; // association changed ?
58
59
60
61 //-------------------------------------------------------
62 //-- GUID {953AFAE9-C2A9-4674-9811-D7E281B001E1} --------
63 //-------------------------------------------------------
64
65
66
67 static const GUID CLSID_NoahXt =
68 { 0x953afae9, 0xc2a9, 0x4674, { 0x98, 0x11, 0xd7, 0xe2, 0x81, 0xb0, 0x1, 0xe1 } };
69 static const char* ProgID_NoahXt = "NoahXt";
70
71
72
73 //--------------------------------------------------------
74 //-- シェルエクステンション・本体 --------------------------
75 //--------------------------------------------------------
76
77
78
79 class noahXt : public IContextMenu, IShellExtInit
80 {
81 public:
82 noahXt() { m_szDir[0]=0; m_pDataObj=NULL; m_cRef=0L; g_cRef++; }
83 ~noahXt() { if( m_pDataObj ) m_pDataObj->Release(); g_cRef--; }
84 STDMETHODIMP_(ULONG) AddRef() { return (++m_cRef); }
85 STDMETHODIMP_(ULONG) Release() { if( --m_cRef )return m_cRef; delete this; return 0L; }
86 STDMETHODIMP QueryInterface( REFIID riid, void** ppv )
87 {
88 *ppv = NULL;
89 AddRef();
90 if( IsEqualIID( riid, IID_IUnknown ) || IsEqualIID( riid, IID_IShellExtInit ) )
91 *ppv = (IShellExtInit*)this;
92 else if( IsEqualIID( riid, IID_IContextMenu ) )
93 *ppv = (IContextMenu*)this;
94 else
95 {
96 Release();
97 return E_NOINTERFACE;
98 }
99 return NOERROR;
100 }
101 STDMETHODIMP Initialize( const ITEMIDLIST* pF, IDataObject* pD, HKEY )
102 {
103 ::SHGetPathFromIDList( pF, m_szDir );
104 if( m_pDataObj )m_pDataObj->Release();
105 if( pD ) (m_pDataObj=pD)->AddRef();
106 return NOERROR;
107 }
108
109 #define CMPR_CMD_E ("Com&press Here")
110 #define EXTR_CMD_E ("E&xtract Here")
111 #define CMPR_CMD (g_bJpn ? "ここに圧縮(&P)" : CMPR_CMD_E)
112 #define EXTR_CMD (g_bJpn ? "ここに解凍(&X)" : EXTR_CMD_E)
113 #define CMPR_HLP (g_bJpn ? "ファイルをNoahで圧縮します。" : "Compress These Files By Noah")
114 #define EXTR_HLP (g_bJpn ? "ファイルをNoahで展開" : "Extract Files By Noah")
115
116 // 右クリックメニューへ追加
117 STDMETHODIMP QueryContextMenu( HMENU h, UINT i, UINT id, UINT idLast, UINT flag )
118 {
119 if( (flag&0x000F)!=CMF_NORMAL && !(flag&CMF_VERBSONLY) && !(flag&CMF_EXPLORE) )
120 return NOERROR;
121
122 // レジストリから設定読み込み
123 // できれば、ここでm_bEXTに関しては拡張子判定を行いたいところ…(^^;
124 LoadSE( &m_bCMP, &m_bEXT );
125
126 if( m_bCMP ) ::InsertMenu( h, i++, MF_STRING|MF_BYPOSITION, id++, CMPR_CMD );
127 if( m_bEXT ) ::InsertMenu( h, i++, MF_STRING|MF_BYPOSITION, id++, EXTR_CMD );
128 return MAKE_HRESULT( SEVERITY_SUCCESS, 0, id );
129 }
130 // コマンド実行
131 STDMETHODIMP InvokeCommand( LPCMINVOKECOMMANDINFO lpcmi )
132 {
133 if( 0==HIWORD(lpcmi->lpVerb) )
134 switch( filter_cmd( LOWORD(lpcmi->lpVerb) ) )
135 {
136 case 0: return operation( "-a" );
137 case 1: return operation( "-x" );
138 }
139 return E_INVALIDARG;
140 }
141 // ヘルプ文字列など
142 STDMETHODIMP GetCommandString( UINT cmd, UINT flag, UINT*, LPSTR pszName, UINT cchMax )
143 {
144 cmd = filter_cmd( cmd );
145 if( cmd==2 )
146 return E_FAIL;
147 switch( flag )
148 {
149 case GCS_HELPTEXT: ::lstrcpyn( pszName, cmd==0 ? CMPR_HLP : EXTR_HLP, cchMax ); break;
150 case GCS_VERB: ::lstrcpyn( pszName, cmd==0 ? CMPR_CMD_E : EXTR_CMD_E, cchMax ); break;
151 }
152 return NOERROR;
153 }
154 private:
155 // コマンドIDを compress=0, melt=1, else=2 にフィルタリング
156 UINT filter_cmd( UINT i )
157 {
158 if( m_bCMP )if( m_bEXT )return (i<=1 ? i : 2);
159 else return (i==0 ? 0 : 2);
160 else if( m_bEXT )return (i==0 ? 1 : 2);
161 else return 2;
162 }
163 // Noah.exeへ渡す処理 "Compress Here" or "Extract Here"
164 STDMETHODIMP operation( const char* opt )
165 {
166 STGMEDIUM md;
167 FORMATETC fe = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
168 if( SUCCEEDED( m_pDataObj->GetData( &fe, &md ) ) )
169 {
170 const HDROP& hDrop = (HDROP)md.hGlobal;
171 const int num = ::DragQueryFile( hDrop, 0xffffffff, NULL, 0 );
172 if( num )
173 {
174 // main command
175 char* cmd = new char[10 + MAX_PATH * (num+2)];
176 ::lstrcpy( cmd, g_szNoah );
177 ::lstrcat( cmd, " " );
178 ::lstrcat( cmd, opt );
179 // destdir
180 ::lstrcat( cmd, " \"-D" );
181 ::lstrcat( cmd, m_szDir );
182 ::lstrcat( cmd, "\"" );
183 // filelist
184 char str[MAX_PATH];
185 for( int i=0; i!=num; i++ )
186 {
187 ::DragQueryFile( hDrop, i, str, sizeof(str) );
188 ::lstrcat( cmd, " \"" );
189 ::lstrcat( cmd, str );
190 ::lstrcat( cmd, "\"" );
191 }
192 // call 'Noah'
193 ::WinExec( cmd, SW_SHOWDEFAULT );
194 delete [] cmd;
195 }
196 ::ReleaseStgMedium( &md );
197 }
198 return NOERROR;
199 }
200 private:
201 ULONG m_cRef;
202 IDataObject* m_pDataObj;
203 char m_szDir[MAX_PATH];
204 bool m_bCMP, m_bEXT;
205 };
206
207 //-- クラス工場 -------------------------------------------
208
209 class noahXtClassFactory : public IClassFactory
210 {
211 public:
212 noahXtClassFactory() { m_cRef = 0L; g_cRef++; }
213 ~noahXtClassFactory() { g_cRef--; }
214 STDMETHODIMP_(ULONG) AddRef() { return (++m_cRef); }
215 STDMETHODIMP_(ULONG) Release() { if( --m_cRef )return m_cRef; delete this; return 0L; }
216 STDMETHODIMP LockServer( BOOL ) { return NOERROR; }
217 STDMETHODIMP QueryInterface( REFIID riid, void** ppv )
218 {
219 *ppv = NULL;
220 AddRef();
221 if( IsEqualIID( riid, IID_IUnknown ) || IsEqualIID( riid, IID_IClassFactory ) )
222 {
223 *ppv = (IClassFactory*)this;
224 return NOERROR;
225 }
226 Release();
227 return E_NOINTERFACE;
228 }
229 STDMETHODIMP CreateInstance( IUnknown* pOuter, REFIID riid, void** ppvObj )
230 {
231 *ppvObj = NULL;
232 if( pOuter )
233 return CLASS_E_NOAGGREGATION;
234 noahXt* pXt = new noahXt;
235 return pXt ? pXt->QueryInterface( riid, ppvObj ) : E_OUTOFMEMORY;
236 }
237 private:
238 ULONG m_cRef;
239 };
240
241 //-- システム向けAPI ---------------------------------------
242
243 extern "C" int APIENTRY
244 DllMain( HINSTANCE inst, DWORD why, LPVOID reserved )
245 {
246 if( why==DLL_PROCESS_ATTACH )
247 {
248 ::GetModuleFileName( inst, g_szDLL, sizeof(g_szDLL) );
249 ::lstrcpy( g_szNoah, g_szDLL );
250 for( char *p=g_szNoah,*y=g_szNoah-1; *p; p=::CharNext(p) )
251 if( *p=='\\' )
252 y=p;
253 ::lstrcpy( y+1, "Noah.exe" );
254 ::GetShortPathName( g_szNoah, g_szNoah, MAX_PATH );
255
256 OSVERSIONINFO osVer;
257 osVer.dwOSVersionInfoSize = sizeof(osVer);
258 ::GetVersionEx( &osVer );
259 g_isNT = ( osVer.dwPlatformId == VER_PLATFORM_WIN32_NT );
260
261 g_bJpn = (::GetUserDefaultLangID()==0x0411);
262 g_cRef = 0;
263 g_bChanged = false;
264 }
265 else if( why==DLL_PROCESS_DETACH )
266 {
267 if( g_bChanged )
268 ::SHChangeNotify( SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL );
269 }
270 return TRUE;
271 }
272
273 STDAPI DllCanUnloadNow()
274 {
275 return ( g_cRef==0 ? S_OK : S_FALSE );
276 }
277
278 STDAPI DllGetClassObject( REFCLSID rclsid, REFIID riid, void** ppvOut )
279 {
280 *ppvOut = NULL;
281 if( IsEqualIID( rclsid, CLSID_NoahXt ) )
282 {
283 noahXtClassFactory* p = new noahXtClassFactory;
284 return p->QueryInterface( riid, ppvOut );
285 }
286 return CLASS_E_CLASSNOTAVAILABLE;
287 }
288
289
290
291 //--------------------------------------------------------
292 //--------------------------------------------------------
293 //--------------------------------------------------------
294
295
296 //-- kiRegKey from K.I.LIB -------------------------//
297 //------ 'not using kiStr && REG_SZ only' version --//
298
299
300 class kiRegKey
301 {
302 public:
303 kiRegKey()
304 { m_hKey = NULL; }
305 ~kiRegKey()
306 { close(); }
307 operator HKEY() const
308 { return m_hKey; }
309 bool open( HKEY parent, LPCTSTR keyname, REGSAM access )
310 { close(); return (ERROR_SUCCESS == ::RegOpenKeyEx( parent, keyname, 0, access, &m_hKey )); }
311 bool create( HKEY parent, LPCTSTR keyname, REGSAM access )
312 { close(); DWORD x; return (ERROR_SUCCESS == ::RegCreateKeyEx( parent, keyname, 0, REG_NONE, REG_OPTION_NON_VOLATILE, access, NULL, &m_hKey, &x )); }
313 void close()
314 { if( m_hKey ) ::RegCloseKey( m_hKey ); }
315 static bool exist( HKEY parent, LPCTSTR keyname )
316 { HKEY k; if( ERROR_SUCCESS!=::RegOpenKeyEx( parent,keyname,0,KEY_READ,&k ) ) return false; ::RegCloseKey( k ); return true; }
317 bool set( LPCTSTR valname, LPCTSTR val )
318 { return (ERROR_SUCCESS == ::RegSetValueEx( m_hKey, valname, 0, REG_SZ, (BYTE*)val, ::lstrlen(val)+1 )); }
319 bool get( LPCTSTR valname, char* val, DWORD siz )
320 { return ( ERROR_SUCCESS == RegQueryValueEx( m_hKey, valname, NULL, NULL, (BYTE*)val, &siz )); }
321 bool del( LPCTSTR valname )
322 { return (ERROR_SUCCESS == RegDeleteValue( m_hKey, valname )); }
323 static void delSubKey( HKEY k, LPCTSTR n )
324 {
325 if( !g_isNT )
326 {
327 ::RegDeleteKey( k, n );
328 return;
329 }
330
331 // NT系では、サブキーのあるキーは消せないので再帰的に。
332 // しかもEnum中にDeleteはできない上にvector<string>等も
333 // 封印しているためわけのわからんコードになってます。
334
335 // 消したいキーを開く
336 HKEY k2;
337 while( ERROR_SUCCESS == ::RegOpenKeyEx( k,n,0,KEY_ENUMERATE_SUB_KEYS|KEY_SET_VALUE,&k2 ) )
338 {
339 // 1個目の子キー名を取得
340 char buf[200];
341 DWORD bs = sizeof(buf);
342 if( ERROR_SUCCESS == ::RegEnumKeyEx( k2,0,buf,&bs,NULL,NULL,NULL,NULL ) )
343 {
344 // あればそれを削除
345 delSubKey( k2, buf );
346 ::RegCloseKey( k2 );
347 }
348 else
349 {
350 // なければ、消したいキーを消せる
351 ::RegCloseKey( k2 );
352 ::RegDeleteKey( k, n );
353 return;
354 }
355 }
356 }
357 private:
358 HKEY m_hKey;
359 };
360
361
362
363 //--------------------------------------------------------
364 //-- Noahの設定用APIなど ----------------------------------
365 //--------------------------------------------------------
366
367
368
369 char g_szAsCmd[MAX_PATH+10];
370 char g_szAsIcon[MAX_PATH+10];
371
372
373 // 管理者権限判別
374 //-- IsAdmin() : very very thanks! to ardry, the author of 'meltice'.
375
376 bool IsAdmin()
377 {
378 bool isadmin=false;
379
380 //-- 9x対策のため、動的にDLLロード
381 HINSTANCE hInstDll = safepathLoadLibrary( "NetAPI32" );
382 if( !hInstDll )
383 return false;
384
385 //-- NetUserGetLocalGroupes API 取得
386 typedef NET_API_STATUS (NET_API_FUNCTION *PNETUSRGETLCLGRP)(LPCWSTR,wchar_t *,DWORD,DWORD,VOID*,DWORD,LPDWORD,LPDWORD);
387 PNETUSRGETLCLGRP pNetUserGetLocalGroups = (PNETUSRGETLCLGRP)::GetProcAddress(hInstDll, "NetUserGetLocalGroups");
388 if( !pNetUserGetLocalGroups )
389 {
390 ::FreeLibrary( hInstDll );
391 return false;
392 }
393
394 //-- ユーザー名取得
395 char userA[256];
396 wchar_t userW[256];
397 DWORD tmp = 256;
398 ::GetUserName( userA, &tmp );
399 ::MultiByteToWideChar( CP_ACP, 0, userA, -1, userW, 255 );
400
401 //-- 本筋
402 LOCALGROUP_USERS_INFO_0* pBuf;
403 DWORD entry;
404 char buf[256];
405
406 if( 0 == pNetUserGetLocalGroups(NULL,userW,0,0,(BYTE**)&pBuf,-1,&entry,&tmp) )
407 {
408 for( unsigned int i=0; i<entry; i++ )
409 {
410 ::WideCharToMultiByte( CP_ACP, 0, pBuf[i].lgrui0_name, -1, buf, 256, NULL, NULL );
411
412 if( 0 == ::lstrcmp( buf, "Administrators" ) )
413 {
414 isadmin=true;
415 break;
416 }
417 }
418
419 //-- メモリ解放
420 typedef NET_API_STATUS (NET_API_FUNCTION * PNETAPIBUFFERFREE)(void*);
421 PNETAPIBUFFERFREE pNetApiBufferFree = (PNETAPIBUFFERFREE)::GetProcAddress( hInstDll, "NetApiBufferFree" );
422 if( pNetApiBufferFree )
423 pNetApiBufferFree( pBuf );
424 }
425
426 //-- DLL解放
427 ::FreeLibrary( hInstDll );
428 return isadmin;
429 }
430
431 // レジストリへの書き込み権限判定…うまくいかないらしい
432 //
433 //bool IsRegWritable()
434 //{
435 // HKEY key;
436 // if( ERROR_SUCCESS != // 適当なクラスキーへの書き込み権限を調べる
437 // ::RegOpenKeyEx( HKEY_CLASSES_ROOT, "ttffile", 0, KEY_WRITE, &key ) )
438 // return false;
439 // ::RegCloseKey( key );
440 // return true;
441 //}
442
443 //** bool Init()
444 //**
445 //** 設定画面用に起動するときは最初にコレを呼ぶこと。
446 //** false が返ってきたときは、諸事情により利用できないことを示す。
447 bool WINAPI Init()
448 {
449 ::wsprintf( g_szAsIcon, "%s,%%d", g_szDLL );
450 ::wsprintf( g_szAsCmd , "%s -x \"%%1\"", g_szNoah );
451
452 if( g_isNT )
453 if( !IsAdmin() )
454 // if( !IsRegWritable() )
455 return false;
456
457 return true;
458 }
459
460 //** void LoadSE( bool* a, bool* x )
461 //**
462 //** シェルエクステンションの設定を返す。
463 //** a: [ここに圧縮]がONか否か x: [ここに解凍]がONか否か
464 void WINAPI LoadSE( bool* a, bool* x )
465 {
466 *a = kiRegKey::exist( HKEY_CLASSES_ROOT, "CLSID\\{953AFAE9-C2A9-4674-9811-D7E281B001E1}\\CShl" );
467 *x = kiRegKey::exist( HKEY_CLASSES_ROOT, "CLSID\\{953AFAE9-C2A9-4674-9811-D7E281B001E1}\\MShl" );
468 }
469
470 //** void SaveSE( bool a, bool x )
471 //**
472 //** シェルエクステンションの設定を保存する。
473 //** a: [ここに圧縮]がONか否か x: [ここに解凍]がONか否か
474 void WINAPI SaveSE( bool a, bool x )
475 {
476 kiRegKey key, key2;
477
478 if( !a && !x )
479 {
480 kiRegKey::delSubKey( HKEY_CLASSES_ROOT, "CLSID\\{953AFAE9-C2A9-4674-9811-D7E281B001E1}" );
481 kiRegKey::delSubKey( HKEY_CLASSES_ROOT, "Folder\\shellex\\DragDropHandlers\\NoahXt" );
482 kiRegKey::delSubKey( HKEY_CLASSES_ROOT, "Drive\\shellex\\DragDropHandlers\\NoahXt" );
483 if( key.open( HKEY_CLASSES_ROOT, "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved", KEY_SET_VALUE ) )
484 key.del( "{953AFAE9-C2A9-4674-9811-D7E281B001E1}" );
485 }
486 else
487 {
488 // CLSID 登録
489 key.create( HKEY_CLASSES_ROOT, "CLSID\\{953AFAE9-C2A9-4674-9811-D7E281B001E1}", KEY_WRITE );
490 key.set( "", ProgID_NoahXt );
491 key2.create( key, "InprocServer32", KEY_WRITE );
492 key2.set( "", g_szDLL );
493 key2.set( "ThreadingModel", "Apartment" );
494 if(a)key2.create( key, "CShl", KEY_READ );
495 else kiRegKey::delSubKey( key, "CShl" );
496 if(x)key2.create( key, "MShl", KEY_READ );
497 else kiRegKey::delSubKey( key, "MShl" );
498
499 // Folder の DnD Handler として登録
500 key.create( HKEY_CLASSES_ROOT, "Folder\\shellex\\DragDropHandlers\\NoahXt", KEY_WRITE );
501 key.set( "", "{953AFAE9-C2A9-4674-9811-D7E281B001E1}" );
502 // Drive の DnD Handler として登録
503 key.create( HKEY_CLASSES_ROOT, "Drive\\shellex\\DragDropHandlers\\NoahXt", KEY_WRITE );
504 key.set( "", "{953AFAE9-C2A9-4674-9811-D7E281B001E1}" );
505
506 // NT系用に、Approved List に書いておく
507 if( g_isNT && key.open( HKEY_CLASSES_ROOT, "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved", KEY_SET_VALUE ) )
508 key.set( "{953AFAE9-C2A9-4674-9811-D7E281B001E1}", ProgID_NoahXt );
509 }
510 }
511
512 void asso_on( const char* ext, const int no );
513 void asso_off( const char* ext, const int no );
514 bool is_asso_on( const char* ext );
515
516 enum { A_BEGIN, LZH=0, ZIP, CAB, RAR, TAR, YZ1, GCA, ARJ, BGA, ACE, CPT, JAK, A_END,
517 OTH=A_END, SvnZ=CPT };
518 static const char* ext_list[] = {
519 "lzh\0lzs\0lha\0",
520 "zip\0",
521 "cab\0",
522 "rar\0",
523 "tar\0tgz\0tbz\0taz\0gz\0bz2\0z\0xz\0lzma\0",
524 "yz1\0",
525 "gca\0",
526 "arj\0",
527 "gza\0bza\0",
528 "ace\0",
529 "cpt\0",
530 "jak\0",
531 };
532
533 //** void LoadAS( bool asso[] )
534 //**
535 //** 標準の関連付けの設定を返す。
536 //** LZH=0, ZIP, CAB, RAR, TAR, YZ1, GCA, ARJ, BGA, ACE, CPT, JAK
537 void WINAPI LoadAS( bool asso[] )
538 {
539 for( int i=A_BEGIN; i<A_END; i++ )
540 asso[i] = is_asso_on( ext_list[i] );
541 }
542
543 //** void SaveAS( bool asso[] )
544 //**
545 //** 標準の関連付けの設定を保存。
546 //** LZH=0, ZIP, CAB, RAR, TAR, YZ1, GCA, ARJ, BGA, ACE, CPT, JAK
547 void WINAPI SaveAS( bool asso[] )
548 {
549 for( int i=A_BEGIN; i<A_END; i++ )
550 {
551 int icon_type = i;
552 if( i==CPT ) icon_type = OTH; // v3.195: cptは、"その他"アイコン
553
554 if( asso[i] )
555 asso_on( ext_list[i], icon_type );
556 else
557 asso_off( ext_list[i], icon_type );
558 }
559 }
560
561 //** void LoadASEx( const char* ext, bool* x )
562 //**
563 //** 指定した拡張子がNoahに関連付けられているかどうかを返す
564 void WINAPI LoadASEx( const char* ext, bool* x )
565 {
566 *x = is_asso_on( ext );
567 }
568
569 //** void SaveASEx( const char* ext, bool x )
570 //**
571 //** 指定した拡張子をNoahに関連付けたり解除したり
572 void WINAPI SaveASEx( const char* ext, bool x )
573 {
574 int icon_type = OTH; // デフォルトは"その他"アイコン
575 if( 0==lstrcmp(ext,"7z") ) icon_type = SvnZ; // v3.195: 7zに限り、7z専用アイコン
576
577 if( x ) asso_on( ext, icon_type );
578 else asso_off( ext, icon_type );
579 }
580
581 //---------------------------------------------------------------
582
583
584 #define step(_x) (_x+=::lstrlen(_x)+1)
585 #define MltCmd (g_bJpn ? "解凍(&E)" : "&Extract")
586 #define JntCmd (g_bJpn ? "結合(&E)" : "Combin&e")
587 #define MltTyp (g_bJpn ? "書庫(%s)" : "Archive(%s)")
588 #define JntTyp (g_bJpn ? "分割ファイル(%s)" : "RipperedFile(%s)")
589 #define CmdName(_n) (_n==JAK ? JntCmd : MltCmd)
590 #define TypName(_n) (_n==JAK ? JntTyp : MltTyp)
591
592 static void recover_zip()
593 {
594 if( kiRegKey::exist( HKEY_CLASSES_ROOT, "CompressedFolder" ) )
595 {
596 kiRegKey key, key2;
597 if( key.create( HKEY_CLASSES_ROOT, ".zip", KEY_WRITE ) )
598 {
599 key.set( "", "CompressedFolder" );
600 if( key2.create( key, "ShellNew", KEY_WRITE ) )
601 key2.set( "NullFIle", "" );
602 }
603 }
604 }
605 static void recover_cab()
606 {
607 if( kiRegKey::exist( HKEY_CLASSES_ROOT, "CLSID\\{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}" ) )
608 {
609 kiRegKey key;
610 if( key.create( HKEY_CLASSES_ROOT, ".cab", KEY_WRITE ) )
611 key.set( "", "CLSID\\{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}" );
612 }
613 }
614
615 void asso_on( const char* ext, const int no )
616 {
617 if( is_asso_on( ext ) )
618 return;
619 g_bChanged = true;
620
621 kiRegKey key, key2, key3, key4;
622 char str[500],asc[20]="NoahXt.";
623 ::lstrcpy( asc+7, ext );
624
625 for( const char* p=ext; *p; step(p) )
626 {
627 //-- "HKCR/.lzh" = "NoahXt.lzh", "HKCR/.lzs" = "NoahXt.lzh" ...
628 str[0]='.', ::lstrcpy( str+1, p );
629 if( key.create( HKEY_CLASSES_ROOT, str, KEY_WRITE ) )
630 {
631 key.set( "", asc );
632 kiRegKey::delSubKey( key, "ShellNew" );
633 }
634 }
635
636 if( key.create( HKEY_CLASSES_ROOT, asc, KEY_WRITE ) )
637 {
638 //-- "HKCR/NoahXt.lzh" = "書庫( lzh )"
639 ::wsprintf( str, TypName(no), ext );
640 key.set( "", str );
641 key.del( "EditFlags" );
642
643 if( key2.create( key, "DefaultIcon", KEY_WRITE ) )
644 {
645 //-- "HKCR/NoahXt.lzh/DefaultIcon" = "...Noah.exe, 1"
646 ::wsprintf( str, g_szAsIcon, no );
647 key2.set( "", str );
648 }
649
650 if( key2.create( key, "Shell", KEY_WRITE ) )
651 {
652 //-- "HKCR/NoahXt.lzh/Shell" = "Open"
653 key2.set( "", "Open" );
654 if( key3.create( key2, "Open", KEY_WRITE ) )
655 {
656 //-- "HKCR/NoahXt.lzh/Shell/Open" = "解凍(&X)"
657 key3.set( "", CmdName(no) );
658 if( key4.create( key3, "Command", KEY_WRITE ) )
659 //-- "HKCR/NoahXt.lzh/Shell/Open/Command" = "...Noah.exe -x "%1""
660 key4.set( "", g_szAsCmd );
661 }
662 }
663 }
664 }
665
666 void asso_off( const char* ext, const int no )
667 {
668 if( !is_asso_on( ext ) )
669 return;
670 g_bChanged = true;
671
672 //-- delete "HKCR/NoahXt.lzh"
673 char str[20] = "NoahXt.";
674 ::lstrcpy( str+7, ext );
675 kiRegKey::delSubKey( HKEY_CLASSES_ROOT, str );
676
677 //-- delete "HKCR/.lzh" "HKCR/.lzs" ...
678 for( const char* p=ext; *p; step(p) )
679 {
680 str[0]='.', ::lstrcpy( str+1, p );
681 kiRegKey::delSubKey( HKEY_CLASSES_ROOT, str );
682 }
683
684 switch( no )
685 {
686 // CAB, ZIP to Windows Default Association
687 case CAB: recover_cab(); break;
688 case ZIP: recover_zip(); break;
689 }
690 }
691
692 bool is_asso_on( const char* ext )
693 {
694 //-- "HKCR/.lzh" exists ?
695 char str[20] = ".";
696 ::lstrcpy( str+1, ext );
697 kiRegKey key;
698 if( !key.open( HKEY_CLASSES_ROOT, str, KEY_READ ) )
699 return false;
700 if( !key.get( "", str, 20 ) )
701 return false;
702
703 //-- the value of "HKCR/.lzh" is "NoahXt.lzh" ?
704 char asc[20] = "NoahXt.";
705 ::lstrcpy( asc+7, ext );
706 return ( 0==::lstrcmp( str, asc ) );
707 }