1/* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2007 Apple 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
19#include "ControlPanelExe.h"
20#include "ConfigDialog.h"
21#include "ConfigPropertySheet.h"
22#include "resource.h"
23
24#include <DebugServices.h>
25#include "loclibrary.h"
26
27
28#ifdef _DEBUG
29#define new DEBUG_NEW
30#undef THIS_FILE
31static char THIS_FILE[] = __FILE__;
32#endif
33
34#ifndef HeapEnableTerminationOnCorruption
35#	define HeapEnableTerminationOnCorruption (HEAP_INFORMATION_CLASS) 1
36#endif
37
38
39// Stash away pointers to our resource DLLs
40
41static HINSTANCE g_nonLocalizedResources	= NULL;
42static HINSTANCE g_localizedResources		= NULL;
43
44
45HINSTANCE	GetNonLocalizedResources()
46{
47	return g_nonLocalizedResources;
48}
49
50
51HINSTANCE	GetLocalizedResources()
52{
53	return g_localizedResources;
54}
55
56
57//---------------------------------------------------------------------------------------------------------------------------
58//	Static Declarations
59//---------------------------------------------------------------------------------------------------------------------------
60DEFINE_GUID(CLSID_ControlPanel,
61
620x1207552c, 0xe59, 0x4d9f, 0x85, 0x54, 0xf1, 0xf8, 0x6, 0xcd, 0x7f, 0xa9);
63
64static LPCTSTR g_controlPanelGUID			=	TEXT( "{1207552C-0E59-4d9f-8554-F1F806CD7FA9}" );
65static LPCTSTR g_controlPanelName			=	TEXT( "Bonjour" );
66static LPCTSTR g_controlPanelCanonicalName	=	TEXT( "Apple.Bonjour" );
67static LPCTSTR g_controlPanelCategory		=	TEXT( "3,8" );
68
69static CCPApp theApp;
70
71//===========================================================================================================================
72//	MyRegDeleteKey
73//===========================================================================================================================
74
75DEBUG_LOCAL OSStatus MyRegDeleteKey( HKEY hKeyRoot, LPTSTR lpSubKey )
76{
77    LPTSTR lpEnd;
78    OSStatus err;
79    DWORD dwSize;
80    TCHAR szName[MAX_PATH];
81    HKEY hKey;
82    FILETIME ftWrite;
83
84    // First, see if we can delete the key without having to recurse.
85
86    err = RegDeleteKey( hKeyRoot, lpSubKey );
87
88    if ( !err )
89	{
90		goto exit;
91	}
92
93    err = RegOpenKeyEx( hKeyRoot, lpSubKey, 0, KEY_READ, &hKey );
94	require_noerr( err, exit );
95
96    // Check for an ending slash and add one if it is missing.
97
98    lpEnd = lpSubKey + lstrlen(lpSubKey);
99
100    if ( *( lpEnd - 1 ) != TEXT( '\\' ) )
101    {
102        *lpEnd =  TEXT('\\');
103        lpEnd++;
104        *lpEnd =  TEXT('\0');
105    }
106
107    // Enumerate the keys
108
109    dwSize = MAX_PATH;
110    err = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL, NULL, NULL, &ftWrite);
111
112    if ( !err )
113    {
114        do
115		{
116            lstrcpy (lpEnd, szName);
117
118            if ( !MyRegDeleteKey( hKeyRoot, lpSubKey ) )
119			{
120                break;
121            }
122
123            dwSize = MAX_PATH;
124
125            err = RegEnumKeyEx( hKey, 0, szName, &dwSize, NULL, NULL, NULL, &ftWrite );
126
127        }
128		while ( !err );
129    }
130
131    lpEnd--;
132    *lpEnd = TEXT('\0');
133
134    RegCloseKey( hKey );
135
136    // Try again to delete the key.
137
138    err = RegDeleteKey(hKeyRoot, lpSubKey);
139	require_noerr( err, exit );
140
141exit:
142
143	return err;
144}
145
146
147
148//---------------------------------------------------------------------------------------------------------------------------
149//	CCPApp::CCPApp
150//---------------------------------------------------------------------------------------------------------------------------
151IMPLEMENT_DYNAMIC(CCPApp, CWinApp);
152
153CCPApp::CCPApp()
154{
155	debug_initialize( kDebugOutputTypeWindowsEventLog, "DNS-SD Control Panel", GetModuleHandle( NULL ) );
156	debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelInfo );
157}
158
159
160//---------------------------------------------------------------------------------------------------------------------------
161//	CCPApp::~CCPApp
162//---------------------------------------------------------------------------------------------------------------------------
163
164CCPApp::~CCPApp()
165{
166}
167
168
169void
170CCPApp::Register( LPCTSTR inClsidString, LPCTSTR inName, LPCTSTR inCanonicalName, LPCTSTR inCategory, LPCTSTR inLocalizedName, LPCTSTR inInfoTip, LPCTSTR inIconPath, LPCTSTR inExePath )
171{
172	typedef struct	RegistryBuilder		RegistryBuilder;
173
174	struct	RegistryBuilder
175	{
176		HKEY		rootKey;
177		LPCTSTR		subKey;
178		LPCTSTR		valueName;
179		DWORD		valueType;
180		LPCTSTR		data;
181	};
182
183	OSStatus			err;
184	size_t				n;
185	size_t				i;
186	HKEY				key;
187	TCHAR				keyName[ MAX_PATH ];
188	RegistryBuilder		entries[] =
189	{
190		{ HKEY_LOCAL_MACHINE,	TEXT( "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace\\%s" ),	NULL,									REG_SZ,		inName },
191		{ HKEY_CLASSES_ROOT,	TEXT( "CLSID\\%s" ),																			NULL,									NULL,		NULL },
192		{ HKEY_CLASSES_ROOT,	TEXT( "CLSID\\%s" ),																			TEXT( "System.ApplicationName" ),		REG_SZ,		inCanonicalName },
193		{ HKEY_CLASSES_ROOT,	TEXT( "CLSID\\%s" ),																			TEXT( "System.ControlPanel.Category" ),	REG_SZ,		inCategory },
194		{ HKEY_CLASSES_ROOT,	TEXT( "CLSID\\%s" ),																			TEXT( "LocalizedString" ),				REG_SZ,		inLocalizedName },
195		{ HKEY_CLASSES_ROOT,	TEXT( "CLSID\\%s" ),																			TEXT( "InfoTip" ),						REG_SZ,		inInfoTip },
196		{ HKEY_CLASSES_ROOT,	TEXT( "CLSID\\%s\\DefaultIcon" ),																NULL,									REG_SZ,		inIconPath },
197		{ HKEY_CLASSES_ROOT,	TEXT( "CLSID\\%s\\Shell" ),																		NULL,									NULL,		NULL },
198		{ HKEY_CLASSES_ROOT,	TEXT( "CLSID\\%s\\Shell\\Open" ),																NULL,									NULL,		NULL },
199		{ HKEY_CLASSES_ROOT,	TEXT( "CLSID\\%s\\Shell\\Open\\Command" ),														NULL,									REG_SZ,		inExePath }
200	};
201	DWORD				size;
202
203	// Register the registry entries.
204
205	n = sizeof_array( entries );
206	for( i = 0; i < n; ++i )
207	{
208		wsprintf( keyName, entries[ i ].subKey, inClsidString );
209		err = RegCreateKeyEx( entries[ i ].rootKey, keyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, NULL );
210		require_noerr( err, exit );
211
212		if ( entries[ i ].data )
213		{
214			size = (DWORD)( ( lstrlen( entries[ i ].data ) + 1 ) * sizeof( TCHAR ) );
215			err = RegSetValueEx( key, entries[ i ].valueName, 0, entries[ i ].valueType, (LPBYTE) entries[ i ].data, size );
216			require_noerr( err, exit );
217		}
218
219		RegCloseKey( key );
220	}
221
222exit:
223	return;
224}
225
226
227//-----------------------------------------------------------
228//	CCPApp::Unregister
229//-----------------------------------------------------------
230void
231CCPApp::Unregister( LPCTSTR clsidString )
232{
233	TCHAR keyName[ MAX_PATH * 2 ];
234
235	wsprintf( keyName, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace\\%s", clsidString );
236	MyRegDeleteKey( HKEY_LOCAL_MACHINE, keyName );
237
238	wsprintf( keyName, L"CLSID\\%s", clsidString );
239	MyRegDeleteKey( HKEY_CLASSES_ROOT, keyName );
240}
241
242
243
244//-----------------------------------------------------------
245//	CCPApp::InitInstance
246//-----------------------------------------------------------
247
248BOOL
249CCPApp::InitInstance()
250{
251	CCommandLineInfo	commandLine;
252	wchar_t				resource[MAX_PATH];
253	CString				errorMessage;
254	CString				errorCaption;
255	int					res;
256	OSStatus			err = kNoErr;
257
258	HeapSetInformation( NULL, HeapEnableTerminationOnCorruption, NULL, 0 );
259
260	//
261	// initialize the debugging framework
262	//
263	debug_initialize( kDebugOutputTypeWindowsDebugger, "ControlPanel", NULL );
264	debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelTrace );
265
266	// Before we load the resources, let's load the error string
267
268	errorMessage.LoadString( IDS_REINSTALL );
269	errorCaption.LoadString( IDS_REINSTALL_CAPTION );
270
271	res = PathForResource( NULL, L"ControlPanelResources.dll", resource, MAX_PATH );
272	err = translate_errno( res != 0, kUnknownErr, kUnknownErr );
273	require_noerr( err, exit );
274
275	g_nonLocalizedResources = LoadLibrary( resource );
276	translate_errno( g_nonLocalizedResources, GetLastError(), kUnknownErr );
277	require_noerr( err, exit );
278
279	res = PathForResource( NULL, L"ControlPanelLocalized.dll", resource, MAX_PATH );
280	err = translate_errno( res != 0, kUnknownErr, kUnknownErr );
281	require_noerr( err, exit );
282
283	g_localizedResources = LoadLibrary( resource );
284	translate_errno( g_localizedResources, GetLastError(), kUnknownErr );
285	require_noerr( err, exit );
286
287	AfxSetResourceHandle( g_localizedResources );
288
289	// InitCommonControls() is required on Windows XP if an application
290	// manifest specifies use of ComCtl32.dll version 6 or later to enable
291	// visual styles.  Otherwise, any window creation will fail.
292
293	InitCommonControls();
294
295	CWinApp::InitInstance();
296
297	AfxEnableControlContainer();
298
299	ParseCommandLine( commandLine );
300
301	if ( commandLine.m_nShellCommand == CCommandLineInfo::AppRegister )
302	{
303		CString		localizedName;
304		CString		toolTip;
305		TCHAR		iconPath[ MAX_PATH + 12 ]	= TEXT( "" );
306		TCHAR		exePath[ MAX_PATH ]			= TEXT( "" );
307		DWORD		nChars;
308		OSStatus	err;
309
310		nChars = GetModuleFileName( NULL, exePath, sizeof_array( exePath ) );
311
312		err = translate_errno( nChars > 0, (OSStatus) GetLastError(), kUnknownErr );
313
314		require_noerr( err, exit );
315
316		wsprintf( iconPath, L"%s,-%d", exePath, IDR_APPLET );
317
318		localizedName.LoadString( IDS_APPLET_NAME );
319		toolTip.LoadString( IDS_APPLET_TOOLTIP );
320
321		Register( g_controlPanelGUID, g_controlPanelName, g_controlPanelCanonicalName, g_controlPanelCategory, localizedName, toolTip, iconPath, exePath );
322	}
323	else if ( commandLine.m_nShellCommand == CCommandLineInfo::AppUnregister )
324	{
325		Unregister( g_controlPanelGUID );
326	}
327	else
328	{
329		CString					name;
330		CConfigPropertySheet	dlg;
331
332		name.LoadString( IDR_APPLET );
333		dlg.Construct( name, NULL, 0 );
334
335		m_pMainWnd = &dlg;
336
337		try
338		{
339			INT_PTR nResponse = dlg.DoModal();
340
341			if (nResponse == IDOK)
342			{
343				// TODO: Place code here to handle when the dialog is
344				//  dismissed with OK
345			}
346			else if (nResponse == IDCANCEL)
347			{
348				// TODO: Place code here to handle when the dialog is
349				//  dismissed with Cancel
350			}
351		}
352		catch (...)
353		{
354			MessageBox(NULL, L"", L"", MB_OK|MB_ICONEXCLAMATION);
355		}
356	}
357
358	if ( err )
359	{
360		MessageBox( NULL, L"", L"", MB_ICONERROR | MB_OK );
361	}
362
363exit:
364
365	if ( err )
366	{
367		MessageBox( NULL, errorMessage, errorCaption, MB_ICONERROR | MB_OK );
368	}
369
370	// Since the dialog has been closed, return FALSE so that we exit the
371	//  application, rather than start the application's message pump.
372	return FALSE;
373}
374