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.
17 Change History (most recent first):
19 $Log: ExplorerPlugin.cpp,v $
20 Revision 1.10 2009/03/30 18:51:04 herscher
21 <rdar://problem/5925472> Current Bonjour code does not compile on Windows
22 <rdar://problem/5187308> Move build train to Visual Studio 2005
24 Revision 1.9 2006/08/14 23:24:00 cheshire
25 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
27 Revision 1.8 2005/06/30 18:01:54 shersche
28 <rdar://problem/4130635> Cause IE to rebuild cache so we don't have to reboot following an install.
30 Revision 1.7 2005/02/23 02:00:45 shersche
31 <rdar://problem/4014479> Delete all the registry entries when component is unregistered
33 Revision 1.6 2005/01/25 17:56:45 shersche
34 <rdar://problem/3911084> Load resource DLLs, get icons and bitmaps from resource DLLs
37 Revision 1.5 2004/09/15 10:33:54 shersche
38 <rdar://problem/3721611> Install XP toolbar button (8 bit mask) if running on XP platform, otherwise install 1 bit mask toolbar button
41 Revision 1.4 2004/07/13 21:24:21 rpantos
42 Fix for <rdar://problem/3701120>.
44 Revision 1.3 2004/06/26 14:12:07 shersche
45 Register the toolbar button
47 Revision 1.2 2004/06/24 20:09:39 shersche
49 Submitted by: herscher
51 Revision 1.1 2004/06/18 04:34:59 rpantos
52 Move to Clients from mDNSWindows
54 Revision 1.1 2004/01/30 03:01:56 bradley
55 Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
61 // The following 2 includes have to be in this order and INITGUID must be defined here, before including the file
62 // that specifies the GUID(s), and nowhere else. The reason for this is that initguid.h doesn't provide separate
63 // define and declare macros for GUIDs so you have to #define INITGUID in the single file where you want to define
64 // your GUID then in all the other files that just need the GUID declared, INITGUID must not be defined.
68 #include "ExplorerPlugin.h"
73 #include "CommonServices.h"
74 #include "DebugServices.h"
76 #include "ClassFactory.h"
79 #include "loclibrary.h"
86 static char THIS_FILE
[] = __FILE__
;
90 #pragma mark == Prototypes ==
93 //===========================================================================================================================
95 //===========================================================================================================================
99 DEBUG_LOCAL OSStatus
RegisterServer( HINSTANCE inInstance
, CLSID inCLSID
, LPCTSTR inName
);
100 DEBUG_LOCAL OSStatus
RegisterCOMCategory( CLSID inCLSID
, CATID inCategoryID
, BOOL inRegister
);
101 DEBUG_LOCAL OSStatus
UnregisterServer( CLSID inCLSID
);
102 DEBUG_LOCAL OSStatus
MyRegDeleteKey( HKEY hKeyRoot
, LPTSTR lpSubKey
);
104 // Stash away pointers to our resource DLLs
106 static HINSTANCE g_nonLocalizedResources
= NULL
;
107 static CString g_nonLocalizedResourcesName
;
108 static HINSTANCE g_localizedResources
= NULL
;
111 GetNonLocalizedResources()
113 return g_nonLocalizedResources
;
117 GetLocalizedResources()
119 return g_localizedResources
;
122 // This is the class GUID for an undocumented hook into IE that will allow us to register
123 // and have IE notice our new ExplorerBar without rebooting.
124 // {8C7461EF-2B13-11d2-BE35-3078302C2030}
126 DEFINE_GUID(CLSID_CompCatCacheDaemon
,
127 0x8C7461EF, 0x2b13, 0x11d2, 0xbe, 0x35, 0x30, 0x78, 0x30, 0x2c, 0x20, 0x30);
131 #pragma mark == Globals ==
134 //===========================================================================================================================
136 //===========================================================================================================================
138 HINSTANCE gInstance
= NULL
;
139 int gDLLRefCount
= 0;
140 CExplorerPluginApp gApp
;
144 #pragma mark == DLL Exports ==
147 //===========================================================================================================================
148 // CExplorerPluginApp::CExplorerPluginApp
149 //===========================================================================================================================
151 IMPLEMENT_DYNAMIC(CExplorerPluginApp
, CWinApp
);
153 CExplorerPluginApp::CExplorerPluginApp()
158 //===========================================================================================================================
159 // CExplorerPluginApp::~CExplorerPluginApp
160 //===========================================================================================================================
162 CExplorerPluginApp::~CExplorerPluginApp()
167 //===========================================================================================================================
168 // CExplorerPluginApp::InitInstance
169 //===========================================================================================================================
172 CExplorerPluginApp::InitInstance()
174 wchar_t resource
[MAX_PATH
];
177 HINSTANCE inInstance
;
179 inInstance
= AfxGetInstanceHandle();
180 gInstance
= inInstance
;
182 debug_initialize( kDebugOutputTypeWindowsEventLog
, "DNSServices Bar", inInstance
);
183 debug_set_property( kDebugPropertyTagPrintLevel
, kDebugLevelTrace
);
184 dlog( kDebugLevelTrace
, "\nCCPApp::InitInstance\n" );
186 res
= PathForResource( inInstance
, L
"ExplorerPluginResources.dll", resource
, MAX_PATH
);
188 err
= translate_errno( res
!= 0, kUnknownErr
, kUnknownErr
);
189 require_noerr( err
, exit
);
191 g_nonLocalizedResources
= LoadLibrary( resource
);
192 translate_errno( g_nonLocalizedResources
, GetLastError(), kUnknownErr
);
193 require_noerr( err
, exit
);
195 g_nonLocalizedResourcesName
= resource
;
197 res
= PathForResource( inInstance
, L
"ExplorerPluginLocalized.dll", resource
, MAX_PATH
);
198 err
= translate_errno( res
!= 0, kUnknownErr
, kUnknownErr
);
199 require_noerr( err
, exit
);
201 g_localizedResources
= LoadLibrary( resource
);
202 translate_errno( g_localizedResources
, GetLastError(), kUnknownErr
);
203 require_noerr( err
, exit
);
205 AfxSetResourceHandle( g_localizedResources
);
213 //===========================================================================================================================
214 // CExplorerPluginApp::ExitInstance
215 //===========================================================================================================================
218 CExplorerPluginApp::ExitInstance()
225 //===========================================================================================================================
227 //===========================================================================================================================
229 STDAPI
DllCanUnloadNow( void )
231 dlog( kDebugLevelTrace
, "DllCanUnloadNow (refCount=%d)\n", gDLLRefCount
);
233 return( gDLLRefCount
== 0 );
236 //===========================================================================================================================
238 //===========================================================================================================================
240 STDAPI
DllGetClassObject( REFCLSID inCLSID
, REFIID inIID
, LPVOID
*outResult
)
244 ClassFactory
* factory
;
246 dlog( kDebugLevelTrace
, "DllGetClassObject\n" );
250 // Check if the class ID is supported.
252 ok
= IsEqualCLSID( inCLSID
, CLSID_ExplorerBar
);
253 require_action_quiet( ok
, exit
, err
= CLASS_E_CLASSNOTAVAILABLE
);
255 // Create the ClassFactory object.
260 factory
= new ClassFactory( inCLSID
);
264 // Do not let exception escape.
266 require_action( factory
, exit
, err
= E_OUTOFMEMORY
);
268 // Query for the specified interface. Release the factory since QueryInterface retains it.
270 err
= factory
->QueryInterface( inIID
, outResult
);
277 //===========================================================================================================================
279 //===========================================================================================================================
281 STDAPI
DllRegisterServer( void )
283 IRunnableTask
* pTask
= NULL
;
288 dlog( kDebugLevelTrace
, "DllRegisterServer\n" );
290 ok
= s
.LoadString( IDS_NAME
);
291 require_action( ok
, exit
, err
= E_UNEXPECTED
);
293 err
= RegisterServer( gInstance
, CLSID_ExplorerBar
, s
);
294 require_noerr( err
, exit
);
296 err
= RegisterCOMCategory( CLSID_ExplorerBar
, CATID_InfoBand
, TRUE
);
297 require_noerr( err
, exit
);
299 // <rdar://problem/4130635> Clear IE cache so it will rebuild the cache when it runs next. This
300 // will allow us to install and not reboot
302 err
= CoCreateInstance(CLSID_CompCatCacheDaemon
, NULL
, CLSCTX_INPROC
, IID_IRunnableTask
, (void**) &pTask
);
303 require_noerr( err
, exit
);
312 //===========================================================================================================================
313 // DllUnregisterServer
314 //===========================================================================================================================
316 STDAPI
DllUnregisterServer( void )
320 dlog( kDebugLevelTrace
, "DllUnregisterServer\n" );
322 err
= RegisterCOMCategory( CLSID_ExplorerBar
, CATID_InfoBand
, FALSE
);
323 require_noerr( err
, exit
);
325 err
= UnregisterServer( CLSID_ExplorerBar
);
326 require_noerr( err
, exit
);
335 #pragma mark == Utilities ==
338 //===========================================================================================================================
340 //===========================================================================================================================
342 DEBUG_LOCAL OSStatus
RegisterServer( HINSTANCE inInstance
, CLSID inCLSID
, LPCTSTR inName
)
344 typedef struct RegistryBuilder RegistryBuilder
;
345 struct RegistryBuilder
354 LPWSTR clsidWideString
;
355 TCHAR clsidString
[ 64 ];
360 TCHAR keyName
[ MAX_PATH
];
361 TCHAR moduleName
[ MAX_PATH
] = TEXT( "" );
362 TCHAR data
[ MAX_PATH
];
363 RegistryBuilder entries
[] =
365 { HKEY_CLASSES_ROOT
, TEXT( "CLSID\\%s" ), NULL
, inName
},
366 { HKEY_CLASSES_ROOT
, TEXT( "CLSID\\%s\\InprocServer32" ), NULL
, moduleName
},
367 { HKEY_CLASSES_ROOT
, TEXT( "CLSID\\%s\\InprocServer32" ), TEXT( "ThreadingModel" ), TEXT( "Apartment" ) }
370 OSVERSIONINFO versionInfo
;
372 // Convert the CLSID to a string based on the encoding of this code (ANSI or Unicode).
374 err
= StringFromIID( inCLSID
, &clsidWideString
);
375 require_noerr( err
, exit
);
376 require_action( clsidWideString
, exit
, err
= kNoMemoryErr
);
379 lstrcpyn( clsidString
, clsidWideString
, sizeof_array( clsidString
) );
380 CoTaskMemFree( clsidWideString
);
382 nChars
= WideCharToMultiByte( CP_ACP
, 0, clsidWideString
, -1, clsidString
, sizeof_array( clsidString
), NULL
, NULL
);
383 err
= translate_errno( nChars
> 0, (OSStatus
) GetLastError(), kUnknownErr
);
384 CoTaskMemFree( clsidWideString
);
385 require_noerr( err
, exit
);
388 // Register the CLSID entries.
390 nChars
= GetModuleFileName( inInstance
, moduleName
, sizeof_array( moduleName
) );
391 err
= translate_errno( nChars
> 0, (OSStatus
) GetLastError(), kUnknownErr
);
392 require_noerr( err
, exit
);
394 n
= sizeof_array( entries
);
395 for( i
= 0; i
< n
; ++i
)
397 wsprintf( keyName
, entries
[ i
].subKey
, clsidString
);
398 err
= RegCreateKeyEx( entries
[ i
].rootKey
, keyName
, 0, NULL
, REG_OPTION_NON_VOLATILE
, KEY_WRITE
, NULL
, &key
, NULL
);
399 require_noerr( err
, exit
);
401 size
= (DWORD
)( ( lstrlen( entries
[ i
].data
) + 1 ) * sizeof( TCHAR
) );
402 err
= RegSetValueEx( key
, entries
[ i
].valueName
, 0, REG_SZ
, (LPBYTE
) entries
[ i
].data
, size
);
404 require_noerr( err
, exit
);
407 // If running on NT, register the extension as approved.
409 versionInfo
.dwOSVersionInfoSize
= sizeof( versionInfo
);
410 GetVersionEx( &versionInfo
);
411 if( versionInfo
.dwPlatformId
== VER_PLATFORM_WIN32_NT
)
413 lstrcpyn( keyName
, TEXT( "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved" ), sizeof_array( keyName
) );
414 err
= RegCreateKeyEx( HKEY_LOCAL_MACHINE
, keyName
, 0, NULL
, REG_OPTION_NON_VOLATILE
, KEY_WRITE
, NULL
, &key
, NULL
);
415 require_noerr( err
, exit
);
417 lstrcpyn( data
, inName
, sizeof_array( data
) );
418 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
419 err
= RegSetValueEx( key
, clsidString
, 0, REG_SZ
, (LPBYTE
) data
, size
);
423 // register toolbar button
424 lstrcpyn( keyName
, TEXT( "SOFTWARE\\Microsoft\\Internet Explorer\\Extensions\\{7F9DB11C-E358-4ca6-A83D-ACC663939424}"), sizeof_array( keyName
) );
425 err
= RegCreateKeyEx( HKEY_LOCAL_MACHINE
, keyName
, 0, NULL
, REG_OPTION_NON_VOLATILE
, KEY_WRITE
, NULL
, &key
, NULL
);
426 require_noerr( err
, exit
);
428 lstrcpyn( data
, L
"Yes", sizeof_array( data
) );
429 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
430 RegSetValueEx( key
, L
"Default Visible", 0, REG_SZ
, (LPBYTE
) data
, size
);
432 lstrcpyn( data
, inName
, sizeof_array( data
) );
433 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
434 RegSetValueEx( key
, L
"ButtonText", 0, REG_SZ
, (LPBYTE
) data
, size
);
436 lstrcpyn( data
, L
"{E0DD6CAB-2D10-11D2-8F1A-0000F87ABD16}", sizeof_array( data
) );
437 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
438 RegSetValueEx( key
, L
"CLSID", 0, REG_SZ
, (LPBYTE
) data
, size
);
440 lstrcpyn( data
, clsidString
, sizeof_array( data
) );
441 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
442 RegSetValueEx( key
, L
"BandCLSID", 0, REG_SZ
, (LPBYTE
) data
, size
);
444 // check if we're running XP or later
445 if ( ( versionInfo
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) &&
446 ( versionInfo
.dwMajorVersion
== 5 ) &&
447 ( versionInfo
.dwMinorVersion
>= 1 ) )
449 wsprintf( data
, L
"%s,%d", (LPCTSTR
) g_nonLocalizedResourcesName
, IDI_BUTTON_XP
);
450 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
451 RegSetValueEx( key
, L
"Icon", 0, REG_SZ
, (LPBYTE
) data
, size
);
453 wsprintf( data
, L
"%s,%d", (LPCTSTR
) g_nonLocalizedResourcesName
, IDI_BUTTON_XP
);
454 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
455 RegSetValueEx( key
, L
"HotIcon", 0, REG_SZ
, (LPBYTE
) data
, size
);
459 wsprintf( data
, L
"%s,%d", (LPCTSTR
) g_nonLocalizedResourcesName
, IDI_BUTTON_2K
);
460 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
461 RegSetValueEx( key
, L
"Icon", 0, REG_SZ
, (LPBYTE
) data
, size
);
463 wsprintf( data
, L
"%s,%d", (LPCTSTR
) g_nonLocalizedResourcesName
, IDI_BUTTON_2K
);
464 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
465 RegSetValueEx( key
, L
"HotIcon", 0, REG_SZ
, (LPBYTE
) data
, size
);
474 //===========================================================================================================================
475 // RegisterCOMCategory
476 //===========================================================================================================================
478 DEBUG_LOCAL OSStatus
RegisterCOMCategory( CLSID inCLSID
, CATID inCategoryID
, BOOL inRegister
)
483 err
= CoInitialize( NULL
);
484 require( SUCCEEDED( err
), exit
);
486 err
= CoCreateInstance( CLSID_StdComponentCategoriesMgr
, NULL
, CLSCTX_INPROC_SERVER
, IID_ICatRegister
, (LPVOID
*) &cat
);
487 check( SUCCEEDED( err
) );
488 if( SUCCEEDED( err
) )
492 err
= cat
->RegisterClassImplCategories( inCLSID
, 1, &inCategoryID
);
497 err
= cat
->UnRegisterClassImplCategories( inCLSID
, 1, &inCategoryID
);
509 //===========================================================================================================================
511 //===========================================================================================================================
513 DEBUG_LOCAL OSStatus
UnregisterServer( CLSID inCLSID
)
516 LPWSTR clsidWideString
;
517 TCHAR clsidString
[ 64 ];
519 TCHAR keyName
[ MAX_PATH
* 2 ];
520 OSVERSIONINFO versionInfo
;
522 // Convert the CLSID to a string based on the encoding of this code (ANSI or Unicode).
524 err
= StringFromIID( inCLSID
, &clsidWideString
);
525 require_noerr( err
, exit
);
526 require_action( clsidWideString
, exit
, err
= kNoMemoryErr
);
529 lstrcpyn( clsidString
, clsidWideString
, sizeof_array( clsidString
) );
530 CoTaskMemFree( clsidWideString
);
532 nChars
= WideCharToMultiByte( CP_ACP
, 0, clsidWideString
, -1, clsidString
, sizeof_array( clsidString
), NULL
, NULL
);
533 err
= translate_errno( nChars
> 0, (OSStatus
) GetLastError(), kUnknownErr
);
534 CoTaskMemFree( clsidWideString
);
535 require_noerr( err
, exit
);
538 wsprintf( keyName
, L
"CLSID\\%s", clsidString
);
539 MyRegDeleteKey( HKEY_CLASSES_ROOT
, keyName
);
541 // If running on NT, de-register the extension as approved.
543 versionInfo
.dwOSVersionInfoSize
= sizeof( versionInfo
);
544 GetVersionEx( &versionInfo
);
545 if( versionInfo
.dwPlatformId
== VER_PLATFORM_WIN32_NT
)
547 lstrcpyn( keyName
, TEXT( "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved" ), sizeof_array( keyName
) );
548 err
= RegCreateKeyEx( HKEY_LOCAL_MACHINE
, keyName
, 0, NULL
, REG_OPTION_NON_VOLATILE
, KEY_WRITE
, NULL
, &key
, NULL
);
549 require_noerr( err
, exit
);
551 RegDeleteValue( key
, clsidString
);
553 err
= RegCloseKey( key
);
554 require_noerr( err
, exit
);
557 // de-register toolbar button
559 lstrcpyn( keyName
, TEXT( "SOFTWARE\\Microsoft\\Internet Explorer\\Extensions\\{7F9DB11C-E358-4ca6-A83D-ACC663939424}"), sizeof_array( keyName
) );
560 MyRegDeleteKey( HKEY_LOCAL_MACHINE
, keyName
);
568 //===========================================================================================================================
570 //===========================================================================================================================
572 DEBUG_LOCAL OSStatus
MyRegDeleteKey( HKEY hKeyRoot
, LPTSTR lpSubKey
)
577 TCHAR szName
[MAX_PATH
];
581 // First, see if we can delete the key without having to recurse.
583 err
= RegDeleteKey( hKeyRoot
, lpSubKey
);
590 err
= RegOpenKeyEx( hKeyRoot
, lpSubKey
, 0, KEY_READ
, &hKey
);
591 require_noerr( err
, exit
);
593 // Check for an ending slash and add one if it is missing.
595 lpEnd
= lpSubKey
+ lstrlen(lpSubKey
);
597 if ( *( lpEnd
- 1 ) != TEXT( '\\' ) )
604 // Enumerate the keys
607 err
= RegEnumKeyEx(hKey
, 0, szName
, &dwSize
, NULL
, NULL
, NULL
, &ftWrite
);
613 lstrcpy (lpEnd
, szName
);
615 if ( !MyRegDeleteKey( hKeyRoot
, lpSubKey
) )
622 err
= RegEnumKeyEx( hKey
, 0, szName
, &dwSize
, NULL
, NULL
, NULL
, &ftWrite
);
633 // Try again to delete the key.
635 err
= RegDeleteKey(hKeyRoot
, lpSubKey
);
636 require_noerr( err
, exit
);