2 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
25 $Log: ExplorerPlugin.cpp,v $
26 Revision 1.5 2004/09/15 10:33:54 shersche
27 <rdar://problem/3721611> Install XP toolbar button (8 bit mask) if running on XP platform, otherwise install 1 bit mask toolbar button
30 Revision 1.4 2004/07/13 21:24:21 rpantos
31 Fix for <rdar://problem/3701120>.
33 Revision 1.3 2004/06/26 14:12:07 shersche
34 Register the toolbar button
36 Revision 1.2 2004/06/24 20:09:39 shersche
38 Submitted by: herscher
40 Revision 1.1 2004/06/18 04:34:59 rpantos
41 Move to Clients from mDNSWindows
43 Revision 1.1 2004/01/30 03:01:56 bradley
44 Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
50 // The following 2 includes have to be in this order and INITGUID must be defined here, before including the file
51 // that specifies the GUID(s), and nowhere else. The reason for this is that initguid.h doesn't provide separate
52 // define and declare macros for GUIDs so you have to #define INITGUID in the single file where you want to define
53 // your GUID then in all the other files that just need the GUID declared, INITGUID must not be defined.
57 #include "ExplorerPlugin.h"
62 #include "CommonServices.h"
63 #include "DebugServices.h"
65 #include "ClassFactory.h"
73 static char THIS_FILE
[] = __FILE__
;
77 #pragma mark == Prototypes ==
80 //===========================================================================================================================
82 //===========================================================================================================================
86 extern "C" BOOL WINAPI
DllMain( HINSTANCE inInstance
, DWORD inReason
, LPVOID inReserved
);
90 DEBUG_LOCAL OSStatus
MFCDLLProcessAttach( HINSTANCE inInstance
);
91 DEBUG_LOCAL
void MFCDLLProcessDetach( HINSTANCE inInstance
);
92 DEBUG_LOCAL
void MFCDLLThreadDetach( HINSTANCE inInstance
);
96 DEBUG_LOCAL OSStatus
RegisterServer( HINSTANCE inInstance
, CLSID inCLSID
, LPCTSTR inName
);
97 DEBUG_LOCAL OSStatus
RegisterCOMCategory( CLSID inCLSID
, CATID inCategoryID
, BOOL inRegister
);
100 #pragma mark == Globals ==
103 //===========================================================================================================================
105 //===========================================================================================================================
107 HINSTANCE gInstance
= NULL
;
108 int gDLLRefCount
= 0;
113 #pragma mark == DLL Exports ==
116 //===========================================================================================================================
118 //===========================================================================================================================
120 BOOL WINAPI
DllMain( HINSTANCE inInstance
, DWORD inReason
, LPVOID inReserved
)
125 DEBUG_UNUSED( inReserved
);
130 case DLL_PROCESS_ATTACH
:
131 gInstance
= inInstance
;
132 debug_initialize( kDebugOutputTypeWindowsEventLog
, "DNSServices Bar", inInstance
);
133 debug_set_property( kDebugPropertyTagPrintLevel
, kDebugLevelTrace
);
134 dlog( kDebugLevelTrace
, "\nDllMain: process attach\n" );
136 err
= MFCDLLProcessAttach( inInstance
);
137 ok
= ( err
== kNoErr
);
138 require_noerr( err
, exit
);
141 case DLL_PROCESS_DETACH
:
142 dlog( kDebugLevelTrace
, "DllMain: process detach\n" );
143 MFCDLLProcessDetach( inInstance
);
146 case DLL_THREAD_ATTACH
:
147 dlog( kDebugLevelTrace
, "DllMain: thread attach\n" );
150 case DLL_THREAD_DETACH
:
151 dlog( kDebugLevelTrace
, "DllMain: thread detach\n" );
152 MFCDLLThreadDetach( inInstance
);
156 dlog( kDebugLevelTrace
, "DllMain: unknown reason code (%d)\n",inReason
);
164 //===========================================================================================================================
166 //===========================================================================================================================
168 STDAPI
DllCanUnloadNow( void )
170 dlog( kDebugLevelTrace
, "DllCanUnloadNow (refCount=%d)\n", gDLLRefCount
);
172 return( gDLLRefCount
== 0 );
175 //===========================================================================================================================
177 //===========================================================================================================================
179 STDAPI
DllGetClassObject( REFCLSID inCLSID
, REFIID inIID
, LPVOID
*outResult
)
183 ClassFactory
* factory
;
185 dlog( kDebugLevelTrace
, "DllGetClassObject\n" );
189 // Check if the class ID is supported.
191 ok
= IsEqualCLSID( inCLSID
, CLSID_ExplorerBar
);
192 require_action_quiet( ok
, exit
, err
= CLASS_E_CLASSNOTAVAILABLE
);
194 // Create the ClassFactory object.
199 factory
= new ClassFactory( inCLSID
);
203 // Do not let exception escape.
205 require_action( factory
, exit
, err
= E_OUTOFMEMORY
);
207 // Query for the specified interface. Release the factory since QueryInterface retains it.
209 err
= factory
->QueryInterface( inIID
, outResult
);
216 //===========================================================================================================================
218 //===========================================================================================================================
220 STDAPI
DllRegisterServer( void )
226 dlog( kDebugLevelTrace
, "DllRegisterServer\n" );
228 ok
= s
.LoadString( IDS_NAME
);
229 require_action( ok
, exit
, err
= E_UNEXPECTED
);
231 err
= RegisterServer( gInstance
, CLSID_ExplorerBar
, s
);
232 require_noerr( err
, exit
);
234 err
= RegisterCOMCategory( CLSID_ExplorerBar
, CATID_InfoBand
, TRUE
);
235 require_noerr( err
, exit
);
241 //===========================================================================================================================
242 // DllUnregisterServer
243 //===========================================================================================================================
245 STDAPI
DllUnregisterServer( void )
249 dlog( kDebugLevelTrace
, "DllUnregisterServer\n" );
251 err
= RegisterCOMCategory( CLSID_ExplorerBar
, CATID_InfoBand
, FALSE
);
252 require_noerr( err
, exit
);
260 #pragma mark == MFC Support ==
263 //===========================================================================================================================
264 // MFCDLLProcessAttach
265 //===========================================================================================================================
267 DEBUG_LOCAL OSStatus
MFCDLLProcessAttach( HINSTANCE inInstance
)
270 _AFX_THREAD_STATE
* threadState
;
271 AFX_MODULE_STATE
* previousModuleState
;
277 // Simulate what is done in dllmodul.cpp.
279 threadState
= AfxGetThreadState();
280 check( threadState
);
281 previousModuleState
= threadState
->m_pPrevModuleState
;
283 ok
= AfxWinInit( inInstance
, NULL
, TEXT( "" ), 0 );
284 require_action( ok
, exit
, err
= kUnknownErr
);
287 require_action( ok
, exit
, err
= kNotInitializedErr
);
289 ok
= app
->InitInstance();
290 require_action( ok
, exit
, err
= kUnknownErr
);
292 threadState
->m_pPrevModuleState
= previousModuleState
;
294 AfxInitLocalData( inInstance
);
308 threadState
->m_pPrevModuleState
= previousModuleState
;
313 //===========================================================================================================================
314 // MFCDLLProcessDetach
315 //===========================================================================================================================
317 DEBUG_LOCAL
void MFCDLLProcessDetach( HINSTANCE inInstance
)
321 // Simulate what is done in dllmodul.cpp.
330 if( AfxGetModuleThreadState()->m_nTempMapLock
!= 0 )
332 dlog( kDebugLevelWarning
, "Warning: Temp map lock count non-zero (%ld).\n", AfxGetModuleThreadState()->m_nTempMapLock
);
337 AfxUnlockTempMaps( -1 );
339 // Terminate the library before destructors are called.
342 AfxTermLocalData( inInstance
, TRUE
);
345 //===========================================================================================================================
347 //===========================================================================================================================
349 DEBUG_LOCAL
void MFCDLLThreadDetach( HINSTANCE inInstance
)
351 // Simulate what is done in dllmodul.cpp.
354 if( AfxGetModuleThreadState()->m_nTempMapLock
!= 0 )
356 dlog( kDebugLevelWarning
, "Warning: Temp map lock count non-zero (%ld).\n", AfxGetModuleThreadState()->m_nTempMapLock
);
361 AfxUnlockTempMaps( -1 );
362 AfxTermThread( inInstance
);
367 #pragma mark == Utilities ==
370 //===========================================================================================================================
372 //===========================================================================================================================
374 DEBUG_LOCAL OSStatus
RegisterServer( HINSTANCE inInstance
, CLSID inCLSID
, LPCTSTR inName
)
376 typedef struct RegistryBuilder RegistryBuilder
;
377 struct RegistryBuilder
386 LPWSTR clsidWideString
;
387 TCHAR clsidString
[ 64 ];
392 TCHAR keyName
[ MAX_PATH
];
393 TCHAR moduleName
[ MAX_PATH
] = TEXT( "" );
394 TCHAR data
[ MAX_PATH
];
395 RegistryBuilder entries
[] =
397 { HKEY_CLASSES_ROOT
, TEXT( "CLSID\\%s" ), NULL
, inName
},
398 { HKEY_CLASSES_ROOT
, TEXT( "CLSID\\%s\\InprocServer32" ), NULL
, moduleName
},
399 { HKEY_CLASSES_ROOT
, TEXT( "CLSID\\%s\\InprocServer32" ), TEXT( "ThreadingModel" ), TEXT( "Apartment" ) }
402 OSVERSIONINFO versionInfo
;
404 // Convert the CLSID to a string based on the encoding of this code (ANSI or Unicode).
406 err
= StringFromIID( inCLSID
, &clsidWideString
);
407 require_noerr( err
, exit
);
408 require_action( clsidWideString
, exit
, err
= kNoMemoryErr
);
411 lstrcpyn( clsidString
, clsidWideString
, sizeof_array( clsidString
) );
412 CoTaskMemFree( clsidWideString
);
414 nChars
= WideCharToMultiByte( CP_ACP
, 0, clsidWideString
, -1, clsidString
, sizeof_array( clsidString
), NULL
, NULL
);
415 err
= translate_errno( nChars
> 0, (OSStatus
) GetLastError(), kUnknownErr
);
416 CoTaskMemFree( clsidWideString
);
417 require_noerr( err
, exit
);
420 // Register the CLSID entries.
422 nChars
= GetModuleFileName( inInstance
, moduleName
, sizeof_array( moduleName
) );
423 err
= translate_errno( nChars
> 0, (OSStatus
) GetLastError(), kUnknownErr
);
424 require_noerr( err
, exit
);
426 n
= sizeof_array( entries
);
427 for( i
= 0; i
< n
; ++i
)
429 wsprintf( keyName
, entries
[ i
].subKey
, clsidString
);
430 err
= RegCreateKeyEx( entries
[ i
].rootKey
, keyName
, 0, NULL
, REG_OPTION_NON_VOLATILE
, KEY_WRITE
, NULL
, &key
, NULL
);
431 require_noerr( err
, exit
);
433 size
= (DWORD
)( ( lstrlen( entries
[ i
].data
) + 1 ) * sizeof( TCHAR
) );
434 err
= RegSetValueEx( key
, entries
[ i
].valueName
, 0, REG_SZ
, (LPBYTE
) entries
[ i
].data
, size
);
436 require_noerr( err
, exit
);
439 // If running on NT, register the extension as approved.
441 versionInfo
.dwOSVersionInfoSize
= sizeof( versionInfo
);
442 GetVersionEx( &versionInfo
);
443 if( versionInfo
.dwPlatformId
== VER_PLATFORM_WIN32_NT
)
445 lstrcpyn( keyName
, TEXT( "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved" ), sizeof_array( keyName
) );
446 err
= RegCreateKeyEx( HKEY_LOCAL_MACHINE
, keyName
, 0, NULL
, REG_OPTION_NON_VOLATILE
, KEY_WRITE
, NULL
, &key
, NULL
);
447 require_noerr( err
, exit
);
449 lstrcpyn( data
, inName
, sizeof_array( data
) );
450 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
451 err
= RegSetValueEx( key
, clsidString
, 0, REG_SZ
, (LPBYTE
) data
, size
);
455 // register toolbar button
456 lstrcpyn( keyName
, TEXT( "SOFTWARE\\Microsoft\\Internet Explorer\\Extensions\\{7F9DB11C-E358-4ca6-A83D-ACC663939424}"), sizeof_array( keyName
) );
457 err
= RegCreateKeyEx( HKEY_LOCAL_MACHINE
, keyName
, 0, NULL
, REG_OPTION_NON_VOLATILE
, KEY_WRITE
, NULL
, &key
, NULL
);
458 require_noerr( err
, exit
);
460 lstrcpyn( data
, L
"Yes", sizeof_array( data
) );
461 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
462 RegSetValueEx( key
, L
"Default Visible", 0, REG_SZ
, (LPBYTE
) data
, size
);
464 lstrcpyn( data
, inName
, sizeof_array( data
) );
465 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
466 RegSetValueEx( key
, L
"ButtonText", 0, REG_SZ
, (LPBYTE
) data
, size
);
468 lstrcpyn( data
, L
"{E0DD6CAB-2D10-11D2-8F1A-0000F87ABD16}", sizeof_array( data
) );
469 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
470 RegSetValueEx( key
, L
"CLSID", 0, REG_SZ
, (LPBYTE
) data
, size
);
472 lstrcpyn( data
, clsidString
, sizeof_array( data
) );
473 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
474 RegSetValueEx( key
, L
"BandCLSID", 0, REG_SZ
, (LPBYTE
) data
, size
);
476 // check if we're running XP or later
477 if ( ( versionInfo
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) &&
478 ( versionInfo
.dwMajorVersion
== 5 ) &&
479 ( versionInfo
.dwMinorVersion
>= 1 ) )
481 wsprintf( data
, L
"%s,%d", moduleName
, IDI_BUTTON_XP
);
482 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
483 RegSetValueEx( key
, L
"Icon", 0, REG_SZ
, (LPBYTE
) data
, size
);
485 wsprintf( data
, L
"%s,%d", moduleName
, IDI_BUTTON_XP
);
486 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
487 RegSetValueEx( key
, L
"HotIcon", 0, REG_SZ
, (LPBYTE
) data
, size
);
491 wsprintf( data
, L
"%s,%d", moduleName
, IDI_BUTTON_2K
);
492 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
493 RegSetValueEx( key
, L
"Icon", 0, REG_SZ
, (LPBYTE
) data
, size
);
495 wsprintf( data
, L
"%s,%d", moduleName
, IDI_BUTTON_2K
);
496 size
= (DWORD
)( ( lstrlen( data
) + 1 ) * sizeof( TCHAR
) );
497 RegSetValueEx( key
, L
"HotIcon", 0, REG_SZ
, (LPBYTE
) data
, size
);
506 //===========================================================================================================================
507 // RegisterCOMCategory
508 //===========================================================================================================================
510 DEBUG_LOCAL OSStatus
RegisterCOMCategory( CLSID inCLSID
, CATID inCategoryID
, BOOL inRegister
)
515 err
= CoInitialize( NULL
);
516 require( SUCCEEDED( err
), exit
);
518 err
= CoCreateInstance( CLSID_StdComponentCategoriesMgr
, NULL
, CLSCTX_INPROC_SERVER
, IID_ICatRegister
, (LPVOID
*) &cat
);
519 check( SUCCEEDED( err
) );
520 if( SUCCEEDED( err
) )
524 err
= cat
->RegisterClassImplCategories( inCLSID
, 1, &inCategoryID
);
529 err
= cat
->UnRegisterClassImplCategories( inCLSID
, 1, &inCategoryID
);