1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 // The following 2 includes have to be in this order and INITGUID must be defined here, before including the file
21 // that specifies the GUID(s), and nowhere else. The reason for this is that initguid.h doesn't provide separate
22 // define and declare macros for GUIDs so you have to #define INITGUID in the single file where you want to define
23 // your GUID then in all the other files that just need the GUID declared, INITGUID must not be defined.
27 #include "ExplorerPlugin.h"
32 #include "CommonServices.h"
33 #include "DebugServices.h"
35 #include "ClassFactory.h"
38 #include "loclibrary.h"
45 static char THIS_FILE
[] = __FILE__
;
49 #pragma mark == Prototypes ==
52 //===========================================================================================================================
54 //===========================================================================================================================
58 DEBUG_LOCAL OSStatus
RegisterServer( HINSTANCE inInstance
, CLSID inCLSID
, LPCTSTR inName
);
59 DEBUG_LOCAL OSStatus
RegisterCOMCategory( CLSID inCLSID
, CATID inCategoryID
, BOOL inRegister
);
60 DEBUG_LOCAL OSStatus
UnregisterServer( CLSID inCLSID
);
61 DEBUG_LOCAL OSStatus
MyRegDeleteKey( HKEY hKeyRoot
, LPTSTR lpSubKey
);
63 // Stash away pointers to our resource DLLs
65 static HINSTANCE g_nonLocalizedResources
= NULL
;
66 static CString g_nonLocalizedResourcesName
;
67 static HINSTANCE g_localizedResources
= NULL
;
70 GetNonLocalizedResources()
72 return g_nonLocalizedResources
;
76 GetLocalizedResources()
78 return g_localizedResources
;
81 // This is the class GUID for an undocumented hook into IE that will allow us to register
82 // and have IE notice our new ExplorerBar without rebooting.
83 // {8C7461EF-2B13-11d2-BE35-3078302C2030}
85 DEFINE_GUID(CLSID_CompCatCacheDaemon
,
86 0x8C7461EF, 0x2b13, 0x11d2, 0xbe, 0x35, 0x30, 0x78, 0x30, 0x2c, 0x20, 0x30);
90 #pragma mark == Globals ==
93 //===========================================================================================================================
95 //===========================================================================================================================
97 HINSTANCE gInstance
= NULL
;
99 CExplorerPluginApp gApp
;
103 #pragma mark == DLL Exports ==
106 //===========================================================================================================================
107 // CExplorerPluginApp::CExplorerPluginApp
108 //===========================================================================================================================
110 IMPLEMENT_DYNAMIC(CExplorerPluginApp
, CWinApp
);
112 CExplorerPluginApp::CExplorerPluginApp()
117 //===========================================================================================================================
118 // CExplorerPluginApp::~CExplorerPluginApp
119 //===========================================================================================================================
121 CExplorerPluginApp::~CExplorerPluginApp()
126 //===========================================================================================================================
127 // CExplorerPluginApp::InitInstance
128 //===========================================================================================================================
131 CExplorerPluginApp::InitInstance()
133 wchar_t resource
[MAX_PATH
];
136 HINSTANCE inInstance
;
138 inInstance
= AfxGetInstanceHandle();
139 gInstance
= inInstance
;
141 debug_initialize( kDebugOutputTypeWindowsEventLog
, "DNSServices Bar", inInstance
);
142 debug_set_property( kDebugPropertyTagPrintLevel
, kDebugLevelTrace
);
143 dlog( kDebugLevelTrace
, "\nCCPApp::InitInstance\n" );
145 res
= PathForResource( inInstance
, L
"ExplorerPluginResources.dll", resource
, MAX_PATH
);
147 err
= translate_errno( res
!= 0, kUnknownErr
, kUnknownErr
);
148 require_noerr( err
, exit
);
150 g_nonLocalizedResources
= LoadLibrary( resource
);
151 translate_errno( g_nonLocalizedResources
, GetLastError(), kUnknownErr
);
152 require_noerr( err
, exit
);
154 g_nonLocalizedResourcesName
= resource
;
156 res
= PathForResource( inInstance
, L
"ExplorerPluginLocalized.dll", resource
, MAX_PATH
);
157 err
= translate_errno( res
!= 0, kUnknownErr
, kUnknownErr
);
158 require_noerr( err
, exit
);
160 g_localizedResources
= LoadLibrary( resource
);
161 translate_errno( g_localizedResources
, GetLastError(), kUnknownErr
);
162 require_noerr( err
, exit
);
164 AfxSetResourceHandle( g_localizedResources
);
172 //===========================================================================================================================
173 // CExplorerPluginApp::ExitInstance
174 //===========================================================================================================================
177 CExplorerPluginApp::ExitInstance()
184 //===========================================================================================================================
186 //===========================================================================================================================
188 STDAPI
DllCanUnloadNow( void )
190 dlog( kDebugLevelTrace
, "DllCanUnloadNow (refCount=%d)\n", gDLLRefCount
);
192 return( gDLLRefCount
== 0 );
195 //===========================================================================================================================
197 //===========================================================================================================================
199 STDAPI
DllGetClassObject( REFCLSID inCLSID
, REFIID inIID
, LPVOID
*outResult
)
203 ClassFactory
* factory
;
205 dlog( kDebugLevelTrace
, "DllGetClassObject\n" );
209 // Check if the class ID is supported.
211 ok
= IsEqualCLSID( inCLSID
, CLSID_ExplorerBar
);
212 require_action_quiet( ok
, exit
, err
= CLASS_E_CLASSNOTAVAILABLE
);
214 // Create the ClassFactory object.
219 factory
= new ClassFactory( inCLSID
);
223 // Do not let exception escape.
225 require_action( factory
, exit
, err
= E_OUTOFMEMORY
);
227 // Query for the specified interface. Release the factory since QueryInterface retains it.
229 err
= factory
->QueryInterface( inIID
, outResult
);
236 //===========================================================================================================================
238 //===========================================================================================================================
240 STDAPI
DllRegisterServer( void )
242 IRunnableTask
* pTask
= NULL
;
247 dlog( kDebugLevelTrace
, "DllRegisterServer\n" );
249 ok
= s
.LoadString( IDS_NAME
);
250 require_action( ok
, exit
, err
= E_UNEXPECTED
);
252 err
= RegisterServer( gInstance
, CLSID_ExplorerBar
, s
);
253 require_noerr( err
, exit
);
255 err
= RegisterCOMCategory( CLSID_ExplorerBar
, CATID_InfoBand
, TRUE
);
256 require_noerr( err
, exit
);
258 // <rdar://problem/4130635> Clear IE cache so it will rebuild the cache when it runs next. This
259 // will allow us to install and not reboot
261 err
= CoCreateInstance(CLSID_CompCatCacheDaemon
, NULL
, CLSCTX_INPROC
, IID_IRunnableTask
, (void**) &pTask
);
262 require_noerr( err
, exit
);
271 //===========================================================================================================================
272 // DllUnregisterServer
273 //===========================================================================================================================
275 STDAPI
DllUnregisterServer( void )
279 dlog( kDebugLevelTrace
, "DllUnregisterServer\n" );
281 err
= RegisterCOMCategory( CLSID_ExplorerBar
, CATID_InfoBand
, FALSE
);
282 require_noerr( err
, exit
);
284 err
= UnregisterServer( CLSID_ExplorerBar
);
285 require_noerr( err
, exit
);
294 #pragma mark == Utilities ==
297 //===========================================================================================================================
299 //===========================================================================================================================
301 DEBUG_LOCAL OSStatus
RegisterServer( HINSTANCE inInstance
, CLSID inCLSID
, LPCTSTR inName
)
303 typedef struct RegistryBuilder RegistryBuilder
;
304 struct RegistryBuilder
313 LPWSTR clsidWideString
;
314 TCHAR clsidString
[ 64 ];
319 TCHAR keyName
[ MAX_PATH
];
320 TCHAR moduleName
[ MAX_PATH
] = TEXT( "" );
321 TCHAR data
[ MAX_PATH
];
322 RegistryBuilder entries
[] =
324 { HKEY_CLASSES_ROOT
, TEXT( "CLSID\\%s" ), NULL
, inName
},
325 { HKEY_CLASSES_ROOT
, TEXT( "CLSID\\%s\\InprocServer32" ), NULL
, moduleName
},
326 { HKEY_CLASSES_ROOT
, TEXT( "CLSID\\%s\\InprocServer32" ), TEXT( "ThreadingModel" ), TEXT( "Apartment" ) }
329 OSVERSIONINFO versionInfo
;
331 // Convert the CLSID to a string based on the encoding of this code (ANSI or Unicode).
333 err
= StringFromIID( inCLSID
, &clsidWideString
);
334 require_noerr( err
, exit
);
335 require_action( clsidWideString
, exit
, err
= kNoMemoryErr
);
338 lstrcpyn( clsidString
, clsidWideString
, sizeof_array( clsidString
) );
339 CoTaskMemFree( clsidWideString
);
341 nChars
= WideCharToMultiByte( CP_ACP
, 0, clsidWideString
, -1, clsidString
, sizeof_array( clsidString
), NULL
, NULL
);
342 err
= translate_errno( nChars
> 0, (OSStatus
) GetLastError(), kUnknownErr
);
343 CoTaskMemFree( clsidWideString
);
344 require_noerr( err
, exit
);
347 // Register the CLSID entries.
349 nChars
= GetModuleFileName( inInstance
, moduleName
, sizeof_array( moduleName
) );
350 err
= translate_errno( nChars
> 0, (OSStatus
) GetLastError(), kUnknownErr
);
351 require_noerr( err
, exit
);
353 n
= sizeof_array( entries
);
354 for( i
= 0; i
< n
; ++i
)
356 wsprintf( keyName
, entries
[ i
].subKey
, clsidString
);
357 err
= RegCreateKeyEx( entries
[ i
].rootKey
, keyName
, 0, NULL
, REG_OPTION_NON_VOLATILE
, KEY_WRITE
, NULL
, &key
, NULL
);
358 require_noerr( err
, exit
);
360 size
= (DWORD
)( ( lstrlen( entries
[ i
].data
) + 1 ) * sizeof( TCHAR
) );
361 err
= RegSetValueEx( key
, entries
[ i
].valueName
, 0, REG_SZ
, (LPBYTE
) entries
[ i
].data
, size
);
363 require_noerr( err
, exit
);
366 // If running on NT, register the extension as approved.
368 versionInfo
.dwOSVersionInfoSize
= sizeof( versionInfo
);
369 GetVersionEx( &versionInfo
);
370 if( versionInfo
.dwPlatformId
== VER_PLATFORM_WIN32_NT
)
372 lstrcpyn( keyName
, TEXT( "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved" ), sizeof_array( keyName
) );
373 err
= RegCreateKeyEx( HKEY_LOCAL_MACHINE
, keyName
, 0, NULL
, REG_OPTION_NON_VOLATILE
, KEY_WRITE
, NULL
, &key
, NULL
);
374 require_noerr( err
, exit
);
376 lstrcpyn( data
, inName
, sizeof_array( data
) );
377 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
378 err
= RegSetValueEx( key
, clsidString
, 0, REG_SZ
, (LPBYTE
) data
, size
);
382 // register toolbar button
383 lstrcpyn( keyName
, TEXT( "SOFTWARE\\Microsoft\\Internet Explorer\\Extensions\\{7F9DB11C-E358-4ca6-A83D-ACC663939424}"), sizeof_array( keyName
) );
384 err
= RegCreateKeyEx( HKEY_LOCAL_MACHINE
, keyName
, 0, NULL
, REG_OPTION_NON_VOLATILE
, KEY_WRITE
, NULL
, &key
, NULL
);
385 require_noerr( err
, exit
);
387 lstrcpyn( data
, L
"Yes", sizeof_array( data
) );
388 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
389 RegSetValueEx( key
, L
"Default Visible", 0, REG_SZ
, (LPBYTE
) data
, size
);
391 lstrcpyn( data
, inName
, sizeof_array( data
) );
392 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
393 RegSetValueEx( key
, L
"ButtonText", 0, REG_SZ
, (LPBYTE
) data
, size
);
395 lstrcpyn( data
, L
"{E0DD6CAB-2D10-11D2-8F1A-0000F87ABD16}", sizeof_array( data
) );
396 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
397 RegSetValueEx( key
, L
"CLSID", 0, REG_SZ
, (LPBYTE
) data
, size
);
399 lstrcpyn( data
, clsidString
, sizeof_array( data
) );
400 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
401 RegSetValueEx( key
, L
"BandCLSID", 0, REG_SZ
, (LPBYTE
) data
, size
);
403 // check if we're running XP or later
404 if ( ( versionInfo
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) &&
405 ( versionInfo
.dwMajorVersion
== 5 ) &&
406 ( versionInfo
.dwMinorVersion
>= 1 ) )
408 wsprintf( data
, L
"%s,%d", (LPCTSTR
) g_nonLocalizedResourcesName
, IDI_BUTTON_XP
);
409 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
410 RegSetValueEx( key
, L
"Icon", 0, REG_SZ
, (LPBYTE
) data
, size
);
412 wsprintf( data
, L
"%s,%d", (LPCTSTR
) g_nonLocalizedResourcesName
, IDI_BUTTON_XP
);
413 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
414 RegSetValueEx( key
, L
"HotIcon", 0, REG_SZ
, (LPBYTE
) data
, size
);
418 wsprintf( data
, L
"%s,%d", (LPCTSTR
) g_nonLocalizedResourcesName
, IDI_BUTTON_2K
);
419 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
420 RegSetValueEx( key
, L
"Icon", 0, REG_SZ
, (LPBYTE
) data
, size
);
422 wsprintf( data
, L
"%s,%d", (LPCTSTR
) g_nonLocalizedResourcesName
, IDI_BUTTON_2K
);
423 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
424 RegSetValueEx( key
, L
"HotIcon", 0, REG_SZ
, (LPBYTE
) data
, size
);
433 //===========================================================================================================================
434 // RegisterCOMCategory
435 //===========================================================================================================================
437 DEBUG_LOCAL OSStatus
RegisterCOMCategory( CLSID inCLSID
, CATID inCategoryID
, BOOL inRegister
)
442 err
= CoInitialize( NULL
);
443 require( SUCCEEDED( err
), exit
);
445 err
= CoCreateInstance( CLSID_StdComponentCategoriesMgr
, NULL
, CLSCTX_INPROC_SERVER
, IID_ICatRegister
, (LPVOID
*) &cat
);
446 check( SUCCEEDED( err
) );
447 if( SUCCEEDED( err
) )
451 err
= cat
->RegisterClassImplCategories( inCLSID
, 1, &inCategoryID
);
456 err
= cat
->UnRegisterClassImplCategories( inCLSID
, 1, &inCategoryID
);
468 //===========================================================================================================================
470 //===========================================================================================================================
472 DEBUG_LOCAL OSStatus
UnregisterServer( CLSID inCLSID
)
475 LPWSTR clsidWideString
;
476 TCHAR clsidString
[ 64 ];
478 TCHAR keyName
[ MAX_PATH
* 2 ];
479 OSVERSIONINFO versionInfo
;
481 // Convert the CLSID to a string based on the encoding of this code (ANSI or Unicode).
483 err
= StringFromIID( inCLSID
, &clsidWideString
);
484 require_noerr( err
, exit
);
485 require_action( clsidWideString
, exit
, err
= kNoMemoryErr
);
488 lstrcpyn( clsidString
, clsidWideString
, sizeof_array( clsidString
) );
489 CoTaskMemFree( clsidWideString
);
491 nChars
= WideCharToMultiByte( CP_ACP
, 0, clsidWideString
, -1, clsidString
, sizeof_array( clsidString
), NULL
, NULL
);
492 err
= translate_errno( nChars
> 0, (OSStatus
) GetLastError(), kUnknownErr
);
493 CoTaskMemFree( clsidWideString
);
494 require_noerr( err
, exit
);
497 wsprintf( keyName
, L
"CLSID\\%s", clsidString
);
498 MyRegDeleteKey( HKEY_CLASSES_ROOT
, keyName
);
500 // If running on NT, de-register the extension as approved.
502 versionInfo
.dwOSVersionInfoSize
= sizeof( versionInfo
);
503 GetVersionEx( &versionInfo
);
504 if( versionInfo
.dwPlatformId
== VER_PLATFORM_WIN32_NT
)
506 lstrcpyn( keyName
, TEXT( "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved" ), sizeof_array( keyName
) );
507 err
= RegCreateKeyEx( HKEY_LOCAL_MACHINE
, keyName
, 0, NULL
, REG_OPTION_NON_VOLATILE
, KEY_WRITE
, NULL
, &key
, NULL
);
508 require_noerr( err
, exit
);
510 RegDeleteValue( key
, clsidString
);
512 err
= RegCloseKey( key
);
513 require_noerr( err
, exit
);
516 // de-register toolbar button
518 lstrcpyn( keyName
, TEXT( "SOFTWARE\\Microsoft\\Internet Explorer\\Extensions\\{7F9DB11C-E358-4ca6-A83D-ACC663939424}"), sizeof_array( keyName
) );
519 MyRegDeleteKey( HKEY_LOCAL_MACHINE
, keyName
);
527 //===========================================================================================================================
529 //===========================================================================================================================
531 DEBUG_LOCAL OSStatus
MyRegDeleteKey( HKEY hKeyRoot
, LPTSTR lpSubKey
)
536 TCHAR szName
[MAX_PATH
];
540 // First, see if we can delete the key without having to recurse.
542 err
= RegDeleteKey( hKeyRoot
, lpSubKey
);
549 err
= RegOpenKeyEx( hKeyRoot
, lpSubKey
, 0, KEY_READ
, &hKey
);
550 require_noerr( err
, exit
);
552 // Check for an ending slash and add one if it is missing.
554 lpEnd
= lpSubKey
+ lstrlen(lpSubKey
);
556 if ( *( lpEnd
- 1 ) != TEXT( '\\' ) )
563 // Enumerate the keys
566 err
= RegEnumKeyEx(hKey
, 0, szName
, &dwSize
, NULL
, NULL
, NULL
, &ftWrite
);
572 lstrcpy (lpEnd
, szName
);
574 if ( !MyRegDeleteKey( hKeyRoot
, lpSubKey
) )
581 err
= RegEnumKeyEx( hKey
, 0, szName
, &dwSize
, NULL
, NULL
, NULL
, &ftWrite
);
592 // Try again to delete the key.
594 err
= RegDeleteKey(hKeyRoot
, lpSubKey
);
595 require_noerr( err
, exit
);