]> git.saurik.com Git - apple/mdnsresponder.git/blob - Clients/ExplorerPlugin/ExplorerPlugin.cpp
mDNSResponder-98.tar.gz
[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.6 2005/01/25 17:56:45 shersche
27 <rdar://problem/3911084> Load resource DLLs, get icons and bitmaps from resource DLLs
28 Bug #: 3911084
29
30 Revision 1.5 2004/09/15 10:33:54 shersche
31 <rdar://problem/3721611> Install XP toolbar button (8 bit mask) if running on XP platform, otherwise install 1 bit mask toolbar button
32 Bug #: 3721611
33
34 Revision 1.4 2004/07/13 21:24:21 rpantos
35 Fix for <rdar://problem/3701120>.
36
37 Revision 1.3 2004/06/26 14:12:07 shersche
38 Register the toolbar button
39
40 Revision 1.2 2004/06/24 20:09:39 shersche
41 Change text
42 Submitted by: herscher
43
44 Revision 1.1 2004/06/18 04:34:59 rpantos
45 Move to Clients from mDNSWindows
46
47 Revision 1.1 2004/01/30 03:01:56 bradley
48 Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
49
50 */
51
52 #include "StdAfx.h"
53
54 // The following 2 includes have to be in this order and INITGUID must be defined here, before including the file
55 // that specifies the GUID(s), and nowhere else. The reason for this is that initguid.h doesn't provide separate
56 // define and declare macros for GUIDs so you have to #define INITGUID in the single file where you want to define
57 // your GUID then in all the other files that just need the GUID declared, INITGUID must not be defined.
58
59 #define INITGUID
60 #include <initguid.h>
61 #include "ExplorerPlugin.h"
62
63 #include <comcat.h>
64 #include <Shlwapi.h>
65
66 #include "CommonServices.h"
67 #include "DebugServices.h"
68
69 #include "ClassFactory.h"
70 #include "Resource.h"
71
72 #include "loclibrary.h"
73
74 // MFC Debugging
75
76 #ifdef _DEBUG
77 #define new DEBUG_NEW
78 #undef THIS_FILE
79 static char THIS_FILE[] = __FILE__;
80 #endif
81
82 #if 0
83 #pragma mark == Prototypes ==
84 #endif
85
86 //===========================================================================================================================
87 // Prototypes
88 //===========================================================================================================================
89
90 // DLL Exports
91
92 extern "C" BOOL WINAPI DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved );
93
94 // MFC Support
95
96 DEBUG_LOCAL OSStatus MFCDLLProcessAttach( HINSTANCE inInstance );
97 DEBUG_LOCAL void MFCDLLProcessDetach( HINSTANCE inInstance );
98 DEBUG_LOCAL void MFCDLLThreadDetach( HINSTANCE inInstance );
99
100 // Utilities
101
102 DEBUG_LOCAL OSStatus RegisterServer( HINSTANCE inInstance, CLSID inCLSID, LPCTSTR inName );
103 DEBUG_LOCAL OSStatus RegisterCOMCategory( CLSID inCLSID, CATID inCategoryID, BOOL inRegister );
104
105 // Stash away pointers to our resource DLLs
106
107 static HINSTANCE g_nonLocalizedResources = NULL;
108 static CString g_nonLocalizedResourcesName;
109 static HINSTANCE g_localizedResources = NULL;
110
111 HINSTANCE
112 GetNonLocalizedResources()
113 {
114 return g_nonLocalizedResources;
115 }
116
117 HINSTANCE
118 GetLocalizedResources()
119 {
120 return g_localizedResources;
121 }
122
123 #if 0
124 #pragma mark == Globals ==
125 #endif
126
127 //===========================================================================================================================
128 // Globals
129 //===========================================================================================================================
130
131 HINSTANCE gInstance = NULL;
132 int gDLLRefCount = 0;
133 CWinApp gApp;
134
135 #if 0
136 #pragma mark -
137 #pragma mark == DLL Exports ==
138 #endif
139
140 //===========================================================================================================================
141 // DllMain
142 //===========================================================================================================================
143
144 BOOL WINAPI DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved )
145 {
146 BOOL ok;
147 OSStatus err;
148
149 DEBUG_UNUSED( inReserved );
150
151 ok = TRUE;
152 switch( inReason )
153 {
154 case DLL_PROCESS_ATTACH:
155 gInstance = inInstance;
156 debug_initialize( kDebugOutputTypeWindowsEventLog, "DNSServices Bar", inInstance );
157 debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelTrace );
158 dlog( kDebugLevelTrace, "\nDllMain: process attach\n" );
159
160 err = MFCDLLProcessAttach( inInstance );
161 ok = ( err == kNoErr );
162 require_noerr( err, exit );
163 break;
164
165 case DLL_PROCESS_DETACH:
166 dlog( kDebugLevelTrace, "DllMain: process detach\n" );
167 MFCDLLProcessDetach( inInstance );
168 break;
169
170 case DLL_THREAD_ATTACH:
171 dlog( kDebugLevelTrace, "DllMain: thread attach\n" );
172 break;
173
174 case DLL_THREAD_DETACH:
175 dlog( kDebugLevelTrace, "DllMain: thread detach\n" );
176 MFCDLLThreadDetach( inInstance );
177 break;
178
179 default:
180 dlog( kDebugLevelTrace, "DllMain: unknown reason code (%d)\n",inReason );
181 break;
182 }
183
184 exit:
185 return( ok );
186 }
187
188 //===========================================================================================================================
189 // DllCanUnloadNow
190 //===========================================================================================================================
191
192 STDAPI DllCanUnloadNow( void )
193 {
194 dlog( kDebugLevelTrace, "DllCanUnloadNow (refCount=%d)\n", gDLLRefCount );
195
196 return( gDLLRefCount == 0 );
197 }
198
199 //===========================================================================================================================
200 // DllGetClassObject
201 //===========================================================================================================================
202
203 STDAPI DllGetClassObject( REFCLSID inCLSID, REFIID inIID, LPVOID *outResult )
204 {
205 HRESULT err;
206 BOOL ok;
207 ClassFactory * factory;
208
209 dlog( kDebugLevelTrace, "DllGetClassObject\n" );
210
211 *outResult = NULL;
212
213 // Check if the class ID is supported.
214
215 ok = IsEqualCLSID( inCLSID, CLSID_ExplorerBar );
216 require_action_quiet( ok, exit, err = CLASS_E_CLASSNOTAVAILABLE );
217
218 // Create the ClassFactory object.
219
220 factory = NULL;
221 try
222 {
223 factory = new ClassFactory( inCLSID );
224 }
225 catch( ... )
226 {
227 // Do not let exception escape.
228 }
229 require_action( factory, exit, err = E_OUTOFMEMORY );
230
231 // Query for the specified interface. Release the factory since QueryInterface retains it.
232
233 err = factory->QueryInterface( inIID, outResult );
234 factory->Release();
235
236 exit:
237 return( err );
238 }
239
240 //===========================================================================================================================
241 // DllRegisterServer
242 //===========================================================================================================================
243
244 STDAPI DllRegisterServer( void )
245 {
246 HRESULT err;
247 BOOL ok;
248 CString s;
249
250 dlog( kDebugLevelTrace, "DllRegisterServer\n" );
251
252 ok = s.LoadString( IDS_NAME );
253 require_action( ok, exit, err = E_UNEXPECTED );
254
255 err = RegisterServer( gInstance, CLSID_ExplorerBar, s );
256 require_noerr( err, exit );
257
258 err = RegisterCOMCategory( CLSID_ExplorerBar, CATID_InfoBand, TRUE );
259 require_noerr( err, exit );
260
261 exit:
262 return( err );
263 }
264
265 //===========================================================================================================================
266 // DllUnregisterServer
267 //===========================================================================================================================
268
269 STDAPI DllUnregisterServer( void )
270 {
271 HRESULT err;
272
273 dlog( kDebugLevelTrace, "DllUnregisterServer\n" );
274
275 err = RegisterCOMCategory( CLSID_ExplorerBar, CATID_InfoBand, FALSE );
276 require_noerr( err, exit );
277
278 exit:
279 return( err );
280 }
281
282 #if 0
283 #pragma mark -
284 #pragma mark == MFC Support ==
285 #endif
286
287 //===========================================================================================================================
288 // MFCDLLProcessAttach
289 //===========================================================================================================================
290
291 DEBUG_LOCAL OSStatus MFCDLLProcessAttach( HINSTANCE inInstance )
292 {
293 wchar_t resource[MAX_PATH];
294 OSStatus err;
295 _AFX_THREAD_STATE * threadState;
296 AFX_MODULE_STATE * previousModuleState;
297 BOOL ok;
298 int res;
299 CWinApp * app;
300
301 app = NULL;
302
303 // Simulate what is done in dllmodul.cpp.
304
305 threadState = AfxGetThreadState();
306 check( threadState );
307 previousModuleState = threadState->m_pPrevModuleState;
308
309 ok = AfxWinInit( inInstance, NULL, TEXT( "" ), 0 );
310 require_action( ok, exit, err = kUnknownErr );
311
312 app = AfxGetApp();
313 require_action( ok, exit, err = kNotInitializedErr );
314
315 // Before we load the resources, let's load the error string
316
317 // errorMessage.LoadString( IDS_REINSTALL );
318 // errorCaption.LoadString( IDS_REINSTALL_CAPTION );
319
320 // Load Resources
321
322 res = PathForResource( inInstance, L"ExplorerPluginResources.dll", resource, MAX_PATH );
323
324 err = translate_errno( res != 0, kUnknownErr, kUnknownErr );
325 require_noerr( err, exit );
326
327 g_nonLocalizedResources = LoadLibrary( resource );
328 translate_errno( g_nonLocalizedResources, GetLastError(), kUnknownErr );
329 require_noerr( err, exit );
330
331 g_nonLocalizedResourcesName = resource;
332
333 res = PathForResource( inInstance, L"ExplorerPluginLocalized.dll", resource, MAX_PATH );
334 err = translate_errno( res != 0, kUnknownErr, kUnknownErr );
335 require_noerr( err, exit );
336
337 g_localizedResources = LoadLibrary( resource );
338 translate_errno( g_localizedResources, GetLastError(), kUnknownErr );
339 require_noerr( err, exit );
340
341 AfxSetResourceHandle( g_localizedResources );
342
343 ok = app->InitInstance();
344 require_action( ok, exit, err = kUnknownErr );
345
346 threadState->m_pPrevModuleState = previousModuleState;
347 threadState = NULL;
348 AfxInitLocalData( inInstance );
349 err = kNoErr;
350
351 exit:
352 if( err )
353 {
354 if( app )
355 {
356 app->ExitInstance();
357 }
358 AfxWinTerm();
359 }
360 if( threadState )
361 {
362 threadState->m_pPrevModuleState = previousModuleState;
363 }
364 return( err );
365 }
366
367 //===========================================================================================================================
368 // MFCDLLProcessDetach
369 //===========================================================================================================================
370
371 DEBUG_LOCAL void MFCDLLProcessDetach( HINSTANCE inInstance )
372 {
373 CWinApp * app;
374
375 // Simulate what is done in dllmodul.cpp.
376
377 app = AfxGetApp();
378 if( app )
379 {
380 app->ExitInstance();
381 }
382
383 #if( DEBUG )
384 if( AfxGetModuleThreadState()->m_nTempMapLock != 0 )
385 {
386 dlog( kDebugLevelWarning, "Warning: Temp map lock count non-zero (%ld).\n", AfxGetModuleThreadState()->m_nTempMapLock );
387 }
388 #endif
389
390 AfxLockTempMaps();
391 AfxUnlockTempMaps( -1 );
392
393 // Terminate the library before destructors are called.
394
395 AfxWinTerm();
396 AfxTermLocalData( inInstance, TRUE );
397 }
398
399 //===========================================================================================================================
400 // MFCDLLFinalize
401 //===========================================================================================================================
402
403 DEBUG_LOCAL void MFCDLLThreadDetach( HINSTANCE inInstance )
404 {
405 // Simulate what is done in dllmodul.cpp.
406
407 #if( DEBUG )
408 if( AfxGetModuleThreadState()->m_nTempMapLock != 0 )
409 {
410 dlog( kDebugLevelWarning, "Warning: Temp map lock count non-zero (%ld).\n", AfxGetModuleThreadState()->m_nTempMapLock );
411 }
412 #endif
413
414 AfxLockTempMaps();
415 AfxUnlockTempMaps( -1 );
416 AfxTermThread( inInstance );
417 }
418
419 #if 0
420 #pragma mark -
421 #pragma mark == Utilities ==
422 #endif
423
424 //===========================================================================================================================
425 // RegisterServer
426 //===========================================================================================================================
427
428 DEBUG_LOCAL OSStatus RegisterServer( HINSTANCE inInstance, CLSID inCLSID, LPCTSTR inName )
429 {
430 typedef struct RegistryBuilder RegistryBuilder;
431 struct RegistryBuilder
432 {
433 HKEY rootKey;
434 LPCTSTR subKey;
435 LPCTSTR valueName;
436 LPCTSTR data;
437 };
438
439 OSStatus err;
440 LPWSTR clsidWideString;
441 TCHAR clsidString[ 64 ];
442 DWORD nChars;
443 size_t n;
444 size_t i;
445 HKEY key;
446 TCHAR keyName[ MAX_PATH ];
447 TCHAR moduleName[ MAX_PATH ] = TEXT( "" );
448 TCHAR data[ MAX_PATH ];
449 RegistryBuilder entries[] =
450 {
451 { HKEY_CLASSES_ROOT, TEXT( "CLSID\\%s" ), NULL, inName },
452 { HKEY_CLASSES_ROOT, TEXT( "CLSID\\%s\\InprocServer32" ), NULL, moduleName },
453 { HKEY_CLASSES_ROOT, TEXT( "CLSID\\%s\\InprocServer32" ), TEXT( "ThreadingModel" ), TEXT( "Apartment" ) }
454 };
455 DWORD size;
456 OSVERSIONINFO versionInfo;
457
458 // Convert the CLSID to a string based on the encoding of this code (ANSI or Unicode).
459
460 err = StringFromIID( inCLSID, &clsidWideString );
461 require_noerr( err, exit );
462 require_action( clsidWideString, exit, err = kNoMemoryErr );
463
464 #ifdef UNICODE
465 lstrcpyn( clsidString, clsidWideString, sizeof_array( clsidString ) );
466 CoTaskMemFree( clsidWideString );
467 #else
468 nChars = WideCharToMultiByte( CP_ACP, 0, clsidWideString, -1, clsidString, sizeof_array( clsidString ), NULL, NULL );
469 err = translate_errno( nChars > 0, (OSStatus) GetLastError(), kUnknownErr );
470 CoTaskMemFree( clsidWideString );
471 require_noerr( err, exit );
472 #endif
473
474 // Register the CLSID entries.
475
476 nChars = GetModuleFileName( inInstance, moduleName, sizeof_array( moduleName ) );
477 err = translate_errno( nChars > 0, (OSStatus) GetLastError(), kUnknownErr );
478 require_noerr( err, exit );
479
480 n = sizeof_array( entries );
481 for( i = 0; i < n; ++i )
482 {
483 wsprintf( keyName, entries[ i ].subKey, clsidString );
484 err = RegCreateKeyEx( entries[ i ].rootKey, keyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, NULL );
485 require_noerr( err, exit );
486
487 size = (DWORD)( ( lstrlen( entries[ i ].data ) + 1 ) * sizeof( TCHAR ) );
488 err = RegSetValueEx( key, entries[ i ].valueName, 0, REG_SZ, (LPBYTE) entries[ i ].data, size );
489 RegCloseKey( key );
490 require_noerr( err, exit );
491 }
492
493 // If running on NT, register the extension as approved.
494
495 versionInfo.dwOSVersionInfoSize = sizeof( versionInfo );
496 GetVersionEx( &versionInfo );
497 if( versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
498 {
499 lstrcpyn( keyName, TEXT( "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved" ), sizeof_array( keyName ) );
500 err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, keyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, NULL );
501 require_noerr( err, exit );
502
503 lstrcpyn( data, inName, sizeof_array( data ) );
504 size = (DWORD)( ( lstrlen( data ) + 1 ) * sizeof( TCHAR ) );
505 err = RegSetValueEx( key, clsidString, 0, REG_SZ, (LPBYTE) data, size );
506 RegCloseKey( key );
507 }
508
509 // register toolbar button
510 lstrcpyn( keyName, TEXT( "SOFTWARE\\Microsoft\\Internet Explorer\\Extensions\\{7F9DB11C-E358-4ca6-A83D-ACC663939424}"), sizeof_array( keyName ) );
511 err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, keyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, NULL );
512 require_noerr( err, exit );
513
514 lstrcpyn( data, L"Yes", sizeof_array( data ) );
515 size = (DWORD)( ( lstrlen( data ) + 1 ) * sizeof( TCHAR ) );
516 RegSetValueEx( key, L"Default Visible", 0, REG_SZ, (LPBYTE) data, size );
517
518 lstrcpyn( data, inName, sizeof_array( data ) );
519 size = (DWORD)( ( lstrlen( data ) + 1 ) * sizeof( TCHAR ) );
520 RegSetValueEx( key, L"ButtonText", 0, REG_SZ, (LPBYTE) data, size );
521
522 lstrcpyn( data, L"{E0DD6CAB-2D10-11D2-8F1A-0000F87ABD16}", sizeof_array( data ) );
523 size = (DWORD)( ( lstrlen( data ) + 1 ) * sizeof( TCHAR ) );
524 RegSetValueEx( key, L"CLSID", 0, REG_SZ, (LPBYTE) data, size );
525
526 lstrcpyn( data, clsidString, sizeof_array( data ) );
527 size = (DWORD)( ( lstrlen( data ) + 1 ) * sizeof( TCHAR ) );
528 RegSetValueEx( key, L"BandCLSID", 0, REG_SZ, (LPBYTE) data, size );
529
530 // check if we're running XP or later
531 if ( ( versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ) &&
532 ( versionInfo.dwMajorVersion == 5 ) &&
533 ( versionInfo.dwMinorVersion >= 1 ) )
534 {
535 wsprintf( data, L"%s,%d", (LPCTSTR) g_nonLocalizedResourcesName, IDI_BUTTON_XP );
536 size = (DWORD)( ( lstrlen( data ) + 1 ) * sizeof( TCHAR ) );
537 RegSetValueEx( key, L"Icon", 0, REG_SZ, (LPBYTE) data, size);
538
539 wsprintf( data, L"%s,%d", (LPCTSTR) g_nonLocalizedResourcesName, IDI_BUTTON_XP );
540 size = (DWORD)( ( lstrlen( data ) + 1 ) * sizeof( TCHAR ) );
541 RegSetValueEx( key, L"HotIcon", 0, REG_SZ, (LPBYTE) data, size);
542 }
543 else
544 {
545 wsprintf( data, L"%s,%d", (LPCTSTR) g_nonLocalizedResourcesName, IDI_BUTTON_2K );
546 size = (DWORD)( ( lstrlen( data ) + 1 ) * sizeof( TCHAR ) );
547 RegSetValueEx( key, L"Icon", 0, REG_SZ, (LPBYTE) data, size);
548
549 wsprintf( data, L"%s,%d", (LPCTSTR) g_nonLocalizedResourcesName, IDI_BUTTON_2K );
550 size = (DWORD)( ( lstrlen( data ) + 1 ) * sizeof( TCHAR ) );
551 RegSetValueEx( key, L"HotIcon", 0, REG_SZ, (LPBYTE) data, size);
552 }
553
554 RegCloseKey( key );
555
556 exit:
557 return( err );
558 }
559
560 //===========================================================================================================================
561 // RegisterCOMCategory
562 //===========================================================================================================================
563
564 DEBUG_LOCAL OSStatus RegisterCOMCategory( CLSID inCLSID, CATID inCategoryID, BOOL inRegister )
565 {
566 HRESULT err;
567 ICatRegister * cat;
568
569 err = CoInitialize( NULL );
570 require( SUCCEEDED( err ), exit );
571
572 err = CoCreateInstance( CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (LPVOID *) &cat );
573 check( SUCCEEDED( err ) );
574 if( SUCCEEDED( err ) )
575 {
576 if( inRegister )
577 {
578 err = cat->RegisterClassImplCategories( inCLSID, 1, &inCategoryID );
579 check_noerr( err );
580 }
581 else
582 {
583 err = cat->UnRegisterClassImplCategories( inCLSID, 1, &inCategoryID );
584 check_noerr( err );
585 }
586 cat->Release();
587 }
588 CoUninitialize();
589
590 exit:
591 return( err );
592 }