Artifact Content

Not logged in

Artifact 179bfff141b849a3ddb62db7d60012358c5b7b34


     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  }