1/* -*- Mode: C; tab-width: 4 -*- 2 * 3 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved. 4 * 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 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 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. 16 */ 17 18#include "StdAfx.h" 19 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. 24 25#define INITGUID 26#include <initguid.h> 27#include "ExplorerPlugin.h" 28 29#include <comcat.h> 30#include <Shlwapi.h> 31 32#include "CommonServices.h" 33#include "DebugServices.h" 34 35#include "ClassFactory.h" 36#include "Resource.h" 37 38#include "loclibrary.h" 39 40// MFC Debugging 41 42#ifdef _DEBUG 43#define new DEBUG_NEW 44#undef THIS_FILE 45static char THIS_FILE[] = __FILE__; 46#endif 47 48#if 0 49#pragma mark == Prototypes == 50#endif 51 52//=========================================================================================================================== 53// Prototypes 54//=========================================================================================================================== 55 56// Utilities 57 58DEBUG_LOCAL OSStatus RegisterServer( HINSTANCE inInstance, CLSID inCLSID, LPCTSTR inName ); 59DEBUG_LOCAL OSStatus RegisterCOMCategory( CLSID inCLSID, CATID inCategoryID, BOOL inRegister ); 60DEBUG_LOCAL OSStatus UnregisterServer( CLSID inCLSID ); 61DEBUG_LOCAL OSStatus MyRegDeleteKey( HKEY hKeyRoot, LPTSTR lpSubKey ); 62 63// Stash away pointers to our resource DLLs 64 65static HINSTANCE g_nonLocalizedResources = NULL; 66static CString g_nonLocalizedResourcesName; 67static HINSTANCE g_localizedResources = NULL; 68 69HINSTANCE 70GetNonLocalizedResources() 71{ 72 return g_nonLocalizedResources; 73} 74 75HINSTANCE 76GetLocalizedResources() 77{ 78 return g_localizedResources; 79} 80 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} 84 85DEFINE_GUID(CLSID_CompCatCacheDaemon, 860x8C7461EF, 0x2b13, 0x11d2, 0xbe, 0x35, 0x30, 0x78, 0x30, 0x2c, 0x20, 0x30); 87 88 89#if 0 90#pragma mark == Globals == 91#endif 92 93//=========================================================================================================================== 94// Globals 95//=========================================================================================================================== 96 97HINSTANCE gInstance = NULL; 98int gDLLRefCount = 0; 99CExplorerPluginApp gApp; 100 101#if 0 102#pragma mark - 103#pragma mark == DLL Exports == 104#endif 105 106//=========================================================================================================================== 107// CExplorerPluginApp::CExplorerPluginApp 108//=========================================================================================================================== 109 110IMPLEMENT_DYNAMIC(CExplorerPluginApp, CWinApp); 111 112CExplorerPluginApp::CExplorerPluginApp() 113{ 114} 115 116 117//=========================================================================================================================== 118// CExplorerPluginApp::~CExplorerPluginApp 119//=========================================================================================================================== 120 121CExplorerPluginApp::~CExplorerPluginApp() 122{ 123} 124 125 126//=========================================================================================================================== 127// CExplorerPluginApp::InitInstance 128//=========================================================================================================================== 129 130BOOL 131CExplorerPluginApp::InitInstance() 132{ 133 wchar_t resource[MAX_PATH]; 134 OSStatus err; 135 int res; 136 HINSTANCE inInstance; 137 138 inInstance = AfxGetInstanceHandle(); 139 gInstance = inInstance; 140 141 debug_initialize( kDebugOutputTypeWindowsEventLog, "DNSServices Bar", inInstance ); 142 debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelTrace ); 143 dlog( kDebugLevelTrace, "\nCCPApp::InitInstance\n" ); 144 145 res = PathForResource( inInstance, L"ExplorerPluginResources.dll", resource, MAX_PATH ); 146 147 err = translate_errno( res != 0, kUnknownErr, kUnknownErr ); 148 require_noerr( err, exit ); 149 150 g_nonLocalizedResources = LoadLibrary( resource ); 151 translate_errno( g_nonLocalizedResources, GetLastError(), kUnknownErr ); 152 require_noerr( err, exit ); 153 154 g_nonLocalizedResourcesName = resource; 155 156 res = PathForResource( inInstance, L"ExplorerPluginLocalized.dll", resource, MAX_PATH ); 157 err = translate_errno( res != 0, kUnknownErr, kUnknownErr ); 158 require_noerr( err, exit ); 159 160 g_localizedResources = LoadLibrary( resource ); 161 translate_errno( g_localizedResources, GetLastError(), kUnknownErr ); 162 require_noerr( err, exit ); 163 164 AfxSetResourceHandle( g_localizedResources ); 165 166exit: 167 168 return TRUE; 169} 170 171 172//=========================================================================================================================== 173// CExplorerPluginApp::ExitInstance 174//=========================================================================================================================== 175 176int 177CExplorerPluginApp::ExitInstance() 178{ 179 return 0; 180} 181 182 183 184//=========================================================================================================================== 185// DllCanUnloadNow 186//=========================================================================================================================== 187 188STDAPI DllCanUnloadNow( void ) 189{ 190 dlog( kDebugLevelTrace, "DllCanUnloadNow (refCount=%d)\n", gDLLRefCount ); 191 192 return( gDLLRefCount == 0 ); 193} 194 195//=========================================================================================================================== 196// DllGetClassObject 197//=========================================================================================================================== 198 199STDAPI DllGetClassObject( REFCLSID inCLSID, REFIID inIID, LPVOID *outResult ) 200{ 201 HRESULT err; 202 BOOL ok; 203 ClassFactory * factory; 204 205 dlog( kDebugLevelTrace, "DllGetClassObject\n" ); 206 207 *outResult = NULL; 208 209 // Check if the class ID is supported. 210 211 ok = IsEqualCLSID( inCLSID, CLSID_ExplorerBar ); 212 require_action_quiet( ok, exit, err = CLASS_E_CLASSNOTAVAILABLE ); 213 214 // Create the ClassFactory object. 215 216 factory = NULL; 217 try 218 { 219 factory = new ClassFactory( inCLSID ); 220 } 221 catch( ... ) 222 { 223 // Do not let exception escape. 224 } 225 require_action( factory, exit, err = E_OUTOFMEMORY ); 226 227 // Query for the specified interface. Release the factory since QueryInterface retains it. 228 229 err = factory->QueryInterface( inIID, outResult ); 230 factory->Release(); 231 232exit: 233 return( err ); 234} 235 236//=========================================================================================================================== 237// DllRegisterServer 238//=========================================================================================================================== 239 240STDAPI DllRegisterServer( void ) 241{ 242 IRunnableTask * pTask = NULL; 243 HRESULT err; 244 BOOL ok; 245 CString s; 246 247 dlog( kDebugLevelTrace, "DllRegisterServer\n" ); 248 249 ok = s.LoadString( IDS_NAME ); 250 require_action( ok, exit, err = E_UNEXPECTED ); 251 252 err = RegisterServer( gInstance, CLSID_ExplorerBar, s ); 253 require_noerr( err, exit ); 254 255 err = RegisterCOMCategory( CLSID_ExplorerBar, CATID_InfoBand, TRUE ); 256 require_noerr( err, exit ); 257 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 260 261 err = CoCreateInstance(CLSID_CompCatCacheDaemon, NULL, CLSCTX_INPROC, IID_IRunnableTask, (void**) &pTask); 262 require_noerr( err, exit ); 263 264 pTask->Run(); 265 pTask->Release(); 266 267exit: 268 return( err ); 269} 270 271//=========================================================================================================================== 272// DllUnregisterServer 273//=========================================================================================================================== 274 275STDAPI DllUnregisterServer( void ) 276{ 277 HRESULT err; 278 279 dlog( kDebugLevelTrace, "DllUnregisterServer\n" ); 280 281 err = RegisterCOMCategory( CLSID_ExplorerBar, CATID_InfoBand, FALSE ); 282 require_noerr( err, exit ); 283 284 err = UnregisterServer( CLSID_ExplorerBar ); 285 require_noerr( err, exit ); 286 287exit: 288 return( err ); 289} 290 291 292#if 0 293#pragma mark - 294#pragma mark == Utilities == 295#endif 296 297//=========================================================================================================================== 298// RegisterServer 299//=========================================================================================================================== 300 301DEBUG_LOCAL OSStatus RegisterServer( HINSTANCE inInstance, CLSID inCLSID, LPCTSTR inName ) 302{ 303 typedef struct RegistryBuilder RegistryBuilder; 304 struct RegistryBuilder 305 { 306 HKEY rootKey; 307 LPCTSTR subKey; 308 LPCTSTR valueName; 309 LPCTSTR data; 310 }; 311 312 OSStatus err; 313 LPWSTR clsidWideString; 314 TCHAR clsidString[ 64 ]; 315 DWORD nChars; 316 size_t n; 317 size_t i; 318 HKEY key; 319 TCHAR keyName[ MAX_PATH ]; 320 TCHAR moduleName[ MAX_PATH ] = TEXT( "" ); 321 TCHAR data[ MAX_PATH ]; 322 RegistryBuilder entries[] = 323 { 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" ) } 327 }; 328 DWORD size; 329 OSVERSIONINFO versionInfo; 330 331 // Convert the CLSID to a string based on the encoding of this code (ANSI or Unicode). 332 333 err = StringFromIID( inCLSID, &clsidWideString ); 334 require_noerr( err, exit ); 335 require_action( clsidWideString, exit, err = kNoMemoryErr ); 336 337 #ifdef UNICODE 338 lstrcpyn( clsidString, clsidWideString, sizeof_array( clsidString ) ); 339 CoTaskMemFree( clsidWideString ); 340 #else 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 ); 345 #endif 346 347 // Register the CLSID entries. 348 349 nChars = GetModuleFileName( inInstance, moduleName, sizeof_array( moduleName ) ); 350 err = translate_errno( nChars > 0, (OSStatus) GetLastError(), kUnknownErr ); 351 require_noerr( err, exit ); 352 353 n = sizeof_array( entries ); 354 for( i = 0; i < n; ++i ) 355 { 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 ); 359 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 ); 362 RegCloseKey( key ); 363 require_noerr( err, exit ); 364 } 365 366 // If running on NT, register the extension as approved. 367 368 versionInfo.dwOSVersionInfoSize = sizeof( versionInfo ); 369 GetVersionEx( &versionInfo ); 370 if( versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ) 371 { 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 ); 375 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 ); 379 RegCloseKey( key ); 380 } 381 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 ); 386 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 ); 390 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 ); 394 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 ); 398 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 ); 402 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 ) ) 407 { 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); 411 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); 415 } 416 else 417 { 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); 421 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); 425 } 426 427 RegCloseKey( key ); 428 429exit: 430 return( err ); 431} 432 433//=========================================================================================================================== 434// RegisterCOMCategory 435//=========================================================================================================================== 436 437DEBUG_LOCAL OSStatus RegisterCOMCategory( CLSID inCLSID, CATID inCategoryID, BOOL inRegister ) 438{ 439 HRESULT err; 440 ICatRegister * cat; 441 442 err = CoInitialize( NULL ); 443 require( SUCCEEDED( err ), exit ); 444 445 err = CoCreateInstance( CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (LPVOID *) &cat ); 446 check( SUCCEEDED( err ) ); 447 if( SUCCEEDED( err ) ) 448 { 449 if( inRegister ) 450 { 451 err = cat->RegisterClassImplCategories( inCLSID, 1, &inCategoryID ); 452 check_noerr( err ); 453 } 454 else 455 { 456 err = cat->UnRegisterClassImplCategories( inCLSID, 1, &inCategoryID ); 457 check_noerr( err ); 458 } 459 cat->Release(); 460 } 461 CoUninitialize(); 462 463exit: 464 return( err ); 465} 466 467 468//=========================================================================================================================== 469// UnregisterServer 470//=========================================================================================================================== 471 472DEBUG_LOCAL OSStatus UnregisterServer( CLSID inCLSID ) 473{ 474 OSStatus err = 0; 475 LPWSTR clsidWideString; 476 TCHAR clsidString[ 64 ]; 477 HKEY key; 478 TCHAR keyName[ MAX_PATH * 2 ]; 479 OSVERSIONINFO versionInfo; 480 481 // Convert the CLSID to a string based on the encoding of this code (ANSI or Unicode). 482 483 err = StringFromIID( inCLSID, &clsidWideString ); 484 require_noerr( err, exit ); 485 require_action( clsidWideString, exit, err = kNoMemoryErr ); 486 487 #ifdef UNICODE 488 lstrcpyn( clsidString, clsidWideString, sizeof_array( clsidString ) ); 489 CoTaskMemFree( clsidWideString ); 490 #else 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 ); 495 #endif 496 497 wsprintf( keyName, L"CLSID\\%s", clsidString ); 498 MyRegDeleteKey( HKEY_CLASSES_ROOT, keyName ); 499 500 // If running on NT, de-register the extension as approved. 501 502 versionInfo.dwOSVersionInfoSize = sizeof( versionInfo ); 503 GetVersionEx( &versionInfo ); 504 if( versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ) 505 { 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 ); 509 510 RegDeleteValue( key, clsidString ); 511 512 err = RegCloseKey( key ); 513 require_noerr( err, exit ); 514 } 515 516 // de-register toolbar button 517 518 lstrcpyn( keyName, TEXT( "SOFTWARE\\Microsoft\\Internet Explorer\\Extensions\\{7F9DB11C-E358-4ca6-A83D-ACC663939424}"), sizeof_array( keyName ) ); 519 MyRegDeleteKey( HKEY_LOCAL_MACHINE, keyName ); 520 521exit: 522 return( err ); 523} 524 525 526 527//=========================================================================================================================== 528// MyRegDeleteKey 529//=========================================================================================================================== 530 531DEBUG_LOCAL OSStatus MyRegDeleteKey( HKEY hKeyRoot, LPTSTR lpSubKey ) 532{ 533 LPTSTR lpEnd; 534 OSStatus err; 535 DWORD dwSize; 536 TCHAR szName[MAX_PATH]; 537 HKEY hKey; 538 FILETIME ftWrite; 539 540 // First, see if we can delete the key without having to recurse. 541 542 err = RegDeleteKey( hKeyRoot, lpSubKey ); 543 544 if ( !err ) 545 { 546 goto exit; 547 } 548 549 err = RegOpenKeyEx( hKeyRoot, lpSubKey, 0, KEY_READ, &hKey ); 550 require_noerr( err, exit ); 551 552 // Check for an ending slash and add one if it is missing. 553 554 lpEnd = lpSubKey + lstrlen(lpSubKey); 555 556 if ( *( lpEnd - 1 ) != TEXT( '\\' ) ) 557 { 558 *lpEnd = TEXT('\\'); 559 lpEnd++; 560 *lpEnd = TEXT('\0'); 561 } 562 563 // Enumerate the keys 564 565 dwSize = MAX_PATH; 566 err = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL, NULL, NULL, &ftWrite); 567 568 if ( !err ) 569 { 570 do 571 { 572 lstrcpy (lpEnd, szName); 573 574 if ( !MyRegDeleteKey( hKeyRoot, lpSubKey ) ) 575 { 576 break; 577 } 578 579 dwSize = MAX_PATH; 580 581 err = RegEnumKeyEx( hKey, 0, szName, &dwSize, NULL, NULL, NULL, &ftWrite ); 582 583 } 584 while ( !err ); 585 } 586 587 lpEnd--; 588 *lpEnd = TEXT('\0'); 589 590 RegCloseKey( hKey ); 591 592 // Try again to delete the key. 593 594 err = RegDeleteKey(hKeyRoot, lpSubKey); 595 require_noerr( err, exit ); 596 597exit: 598 599 return err; 600} 601