]> git.saurik.com Git - apple/mdnsresponder.git/blob - Clients/ExplorerPlugin/ExplorerPlugin.cpp
5de124db0c86d288a1325f826b44e7d3ea70cc7c
[apple/mdnsresponder.git] / Clients / ExplorerPlugin / ExplorerPlugin.cpp
1 /*
2 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22
23 Change History (most recent first):
24
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
28 Bug #: 3721611
29
30 Revision 1.4 2004/07/13 21:24:21 rpantos
31 Fix for <rdar://problem/3701120>.
32
33 Revision 1.3 2004/06/26 14:12:07 shersche
34 Register the toolbar button
35
36 Revision 1.2 2004/06/24 20:09:39 shersche
37 Change text
38 Submitted by: herscher
39
40 Revision 1.1 2004/06/18 04:34:59 rpantos
41 Move to Clients from mDNSWindows
42
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.
45
46 */
47
48 #include "StdAfx.h"
49
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.
54
55 #define INITGUID
56 #include <initguid.h>
57 #include "ExplorerPlugin.h"
58
59 #include <comcat.h>
60 #include <Shlwapi.h>
61
62 #include "CommonServices.h"
63 #include "DebugServices.h"
64
65 #include "ClassFactory.h"
66 #include "Resource.h"
67
68 // MFC Debugging
69
70 #ifdef _DEBUG
71 #define new DEBUG_NEW
72 #undef THIS_FILE
73 static char THIS_FILE[] = __FILE__;
74 #endif
75
76 #if 0
77 #pragma mark == Prototypes ==
78 #endif
79
80 //===========================================================================================================================
81 // Prototypes
82 //===========================================================================================================================
83
84 // DLL Exports
85
86 extern "C" BOOL WINAPI DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved );
87
88 // MFC Support
89
90 DEBUG_LOCAL OSStatus MFCDLLProcessAttach( HINSTANCE inInstance );
91 DEBUG_LOCAL void MFCDLLProcessDetach( HINSTANCE inInstance );
92 DEBUG_LOCAL void MFCDLLThreadDetach( HINSTANCE inInstance );
93
94 // Utilities
95
96 DEBUG_LOCAL OSStatus RegisterServer( HINSTANCE inInstance, CLSID inCLSID, LPCTSTR inName );
97 DEBUG_LOCAL OSStatus RegisterCOMCategory( CLSID inCLSID, CATID inCategoryID, BOOL inRegister );
98
99 #if 0
100 #pragma mark == Globals ==
101 #endif
102
103 //===========================================================================================================================
104 // Globals
105 //===========================================================================================================================
106
107 HINSTANCE gInstance = NULL;
108 int gDLLRefCount = 0;
109 CWinApp gApp;
110
111 #if 0
112 #pragma mark -
113 #pragma mark == DLL Exports ==
114 #endif
115
116 //===========================================================================================================================
117 // DllMain
118 //===========================================================================================================================
119
120 BOOL WINAPI DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved )
121 {
122 BOOL ok;
123 OSStatus err;
124
125 DEBUG_UNUSED( inReserved );
126
127 ok = TRUE;
128 switch( inReason )
129 {
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" );
135
136 err = MFCDLLProcessAttach( inInstance );
137 ok = ( err == kNoErr );
138 require_noerr( err, exit );
139 break;
140
141 case DLL_PROCESS_DETACH:
142 dlog( kDebugLevelTrace, "DllMain: process detach\n" );
143 MFCDLLProcessDetach( inInstance );
144 break;
145
146 case DLL_THREAD_ATTACH:
147 dlog( kDebugLevelTrace, "DllMain: thread attach\n" );
148 break;
149
150 case DLL_THREAD_DETACH:
151 dlog( kDebugLevelTrace, "DllMain: thread detach\n" );
152 MFCDLLThreadDetach( inInstance );
153 break;
154
155 default:
156 dlog( kDebugLevelTrace, "DllMain: unknown reason code (%d)\n",inReason );
157 break;
158 }
159
160 exit:
161 return( ok );
162 }
163
164 //===========================================================================================================================
165 // DllCanUnloadNow
166 //===========================================================================================================================
167
168 STDAPI DllCanUnloadNow( void )
169 {
170 dlog( kDebugLevelTrace, "DllCanUnloadNow (refCount=%d)\n", gDLLRefCount );
171
172 return( gDLLRefCount == 0 );
173 }
174
175 //===========================================================================================================================
176 // DllGetClassObject
177 //===========================================================================================================================
178
179 STDAPI DllGetClassObject( REFCLSID inCLSID, REFIID inIID, LPVOID *outResult )
180 {
181 HRESULT err;
182 BOOL ok;
183 ClassFactory * factory;
184
185 dlog( kDebugLevelTrace, "DllGetClassObject\n" );
186
187 *outResult = NULL;
188
189 // Check if the class ID is supported.
190
191 ok = IsEqualCLSID( inCLSID, CLSID_ExplorerBar );
192 require_action_quiet( ok, exit, err = CLASS_E_CLASSNOTAVAILABLE );
193
194 // Create the ClassFactory object.
195
196 factory = NULL;
197 try
198 {
199 factory = new ClassFactory( inCLSID );
200 }
201 catch( ... )
202 {
203 // Do not let exception escape.
204 }
205 require_action( factory, exit, err = E_OUTOFMEMORY );
206
207 // Query for the specified interface. Release the factory since QueryInterface retains it.
208
209 err = factory->QueryInterface( inIID, outResult );
210 factory->Release();
211
212 exit:
213 return( err );
214 }
215
216 //===========================================================================================================================
217 // DllRegisterServer
218 //===========================================================================================================================
219
220 STDAPI DllRegisterServer( void )
221 {
222 HRESULT err;
223 BOOL ok;
224 CString s;
225
226 dlog( kDebugLevelTrace, "DllRegisterServer\n" );
227
228 ok = s.LoadString( IDS_NAME );
229 require_action( ok, exit, err = E_UNEXPECTED );
230
231 err = RegisterServer( gInstance, CLSID_ExplorerBar, s );
232 require_noerr( err, exit );
233
234 err = RegisterCOMCategory( CLSID_ExplorerBar, CATID_InfoBand, TRUE );
235 require_noerr( err, exit );
236
237 exit:
238 return( err );
239 }
240
241 //===========================================================================================================================
242 // DllUnregisterServer
243 //===========================================================================================================================
244
245 STDAPI DllUnregisterServer( void )
246 {
247 HRESULT err;
248
249 dlog( kDebugLevelTrace, "DllUnregisterServer\n" );
250
251 err = RegisterCOMCategory( CLSID_ExplorerBar, CATID_InfoBand, FALSE );
252 require_noerr( err, exit );
253
254 exit:
255 return( err );
256 }
257
258 #if 0
259 #pragma mark -
260 #pragma mark == MFC Support ==
261 #endif
262
263 //===========================================================================================================================
264 // MFCDLLProcessAttach
265 //===========================================================================================================================
266
267 DEBUG_LOCAL OSStatus MFCDLLProcessAttach( HINSTANCE inInstance )
268 {
269 OSStatus err;
270 _AFX_THREAD_STATE * threadState;
271 AFX_MODULE_STATE * previousModuleState;
272 BOOL ok;
273 CWinApp * app;
274
275 app = NULL;
276
277 // Simulate what is done in dllmodul.cpp.
278
279 threadState = AfxGetThreadState();
280 check( threadState );
281 previousModuleState = threadState->m_pPrevModuleState;
282
283 ok = AfxWinInit( inInstance, NULL, TEXT( "" ), 0 );
284 require_action( ok, exit, err = kUnknownErr );
285
286 app = AfxGetApp();
287 require_action( ok, exit, err = kNotInitializedErr );
288
289 ok = app->InitInstance();
290 require_action( ok, exit, err = kUnknownErr );
291
292 threadState->m_pPrevModuleState = previousModuleState;
293 threadState = NULL;
294 AfxInitLocalData( inInstance );
295 err = kNoErr;
296
297 exit:
298 if( err )
299 {
300 if( app )
301 {
302 app->ExitInstance();
303 }
304 AfxWinTerm();
305 }
306 if( threadState )
307 {
308 threadState->m_pPrevModuleState = previousModuleState;
309 }
310 return( err );
311 }
312
313 //===========================================================================================================================
314 // MFCDLLProcessDetach
315 //===========================================================================================================================
316
317 DEBUG_LOCAL void MFCDLLProcessDetach( HINSTANCE inInstance )
318 {
319 CWinApp * app;
320
321 // Simulate what is done in dllmodul.cpp.
322
323 app = AfxGetApp();
324 if( app )
325 {
326 app->ExitInstance();
327 }
328
329 #if( DEBUG )
330 if( AfxGetModuleThreadState()->m_nTempMapLock != 0 )
331 {
332 dlog( kDebugLevelWarning, "Warning: Temp map lock count non-zero (%ld).\n", AfxGetModuleThreadState()->m_nTempMapLock );
333 }
334 #endif
335
336 AfxLockTempMaps();
337 AfxUnlockTempMaps( -1 );
338
339 // Terminate the library before destructors are called.
340
341 AfxWinTerm();
342 AfxTermLocalData( inInstance, TRUE );
343 }
344
345 //===========================================================================================================================
346 // MFCDLLFinalize
347 //===========================================================================================================================
348
349 DEBUG_LOCAL void MFCDLLThreadDetach( HINSTANCE inInstance )
350 {
351 // Simulate what is done in dllmodul.cpp.
352
353 #if( DEBUG )
354 if( AfxGetModuleThreadState()->m_nTempMapLock != 0 )
355 {
356 dlog( kDebugLevelWarning, "Warning: Temp map lock count non-zero (%ld).\n", AfxGetModuleThreadState()->m_nTempMapLock );
357 }
358 #endif
359
360 AfxLockTempMaps();
361 AfxUnlockTempMaps( -1 );
362 AfxTermThread( inInstance );
363 }
364
365 #if 0
366 #pragma mark -
367 #pragma mark == Utilities ==
368 #endif
369
370 //===========================================================================================================================
371 // RegisterServer
372 //===========================================================================================================================
373
374 DEBUG_LOCAL OSStatus RegisterServer( HINSTANCE inInstance, CLSID inCLSID, LPCTSTR inName )
375 {
376 typedef struct RegistryBuilder RegistryBuilder;
377 struct RegistryBuilder
378 {
379 HKEY rootKey;
380 LPCTSTR subKey;
381 LPCTSTR valueName;
382 LPCTSTR data;
383 };
384
385 OSStatus err;
386 LPWSTR clsidWideString;
387 TCHAR clsidString[ 64 ];
388 DWORD nChars;
389 size_t n;
390 size_t i;
391 HKEY key;
392 TCHAR keyName[ MAX_PATH ];
393 TCHAR moduleName[ MAX_PATH ] = TEXT( "" );
394 TCHAR data[ MAX_PATH ];
395 RegistryBuilder entries[] =
396 {
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" ) }
400 };
401 DWORD size;
402 OSVERSIONINFO versionInfo;
403
404 // Convert the CLSID to a string based on the encoding of this code (ANSI or Unicode).
405
406 err = StringFromIID( inCLSID, &clsidWideString );
407 require_noerr( err, exit );
408 require_action( clsidWideString, exit, err = kNoMemoryErr );
409
410 #ifdef UNICODE
411 lstrcpyn( clsidString, clsidWideString, sizeof_array( clsidString ) );
412 CoTaskMemFree( clsidWideString );
413 #else
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 );
418 #endif
419
420 // Register the CLSID entries.
421
422 nChars = GetModuleFileName( inInstance, moduleName, sizeof_array( moduleName ) );
423 err = translate_errno( nChars > 0, (OSStatus) GetLastError(), kUnknownErr );
424 require_noerr( err, exit );
425
426 n = sizeof_array( entries );
427 for( i = 0; i < n; ++i )
428 {
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 );
432
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 );
435 RegCloseKey( key );
436 require_noerr( err, exit );
437 }
438
439 // If running on NT, register the extension as approved.
440
441 versionInfo.dwOSVersionInfoSize = sizeof( versionInfo );
442 GetVersionEx( &versionInfo );
443 if( versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
444 {
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 );
448
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 );
452 RegCloseKey( key );
453 }
454
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 );
459
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 );
463
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 );
467
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 );
471
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 );
475
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 ) )
480 {
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);
484
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);
488 }
489 else
490 {
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);
494
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);
498 }
499
500 RegCloseKey( key );
501
502 exit:
503 return( err );
504 }
505
506 //===========================================================================================================================
507 // RegisterCOMCategory
508 //===========================================================================================================================
509
510 DEBUG_LOCAL OSStatus RegisterCOMCategory( CLSID inCLSID, CATID inCategoryID, BOOL inRegister )
511 {
512 HRESULT err;
513 ICatRegister * cat;
514
515 err = CoInitialize( NULL );
516 require( SUCCEEDED( err ), exit );
517
518 err = CoCreateInstance( CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (LPVOID *) &cat );
519 check( SUCCEEDED( err ) );
520 if( SUCCEEDED( err ) )
521 {
522 if( inRegister )
523 {
524 err = cat->RegisterClassImplCategories( inCLSID, 1, &inCategoryID );
525 check_noerr( err );
526 }
527 else
528 {
529 err = cat->UnRegisterClassImplCategories( inCLSID, 1, &inCategoryID );
530 check_noerr( err );
531 }
532 cat->Release();
533 }
534 CoUninitialize();
535
536 exit:
537 return( err );
538 }