windows-unicode-support-20080509
[openafs.git] / src / WINNT / client_exp / afs_shl_ext.cpp
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include "stdafx.h"
11 #include <winsock2.h>
12 #include <ws2tcpip.h>
13
14 extern "C" {
15 #include <afs/param.h>
16 #include <afs/stds.h>
17 }
18
19 #include "afs_shl_ext.h"
20 #include <winsock2.h>
21 #include "help.h"
22 #include "shell_ext.h"
23 #include <winreg.h>
24 extern "C" {
25 #include "WINNT\afsreg.h"
26 }
27 #define STRSAFE_NO_DEPRECATE
28 #include <strsafe.h>
29
30 #ifdef _DEBUG
31 #define new DEBUG_NEW
32 #undef THIS_FILE
33 static char THIS_FILE[] = __FILE__;
34 #endif
35
36 #ifndef _WIN64
37
38 // 32-bit
39 static const IID IID_IShellExt =
40     { 0xdc515c27, 0x6cac, 0x11d1, { 0xba, 0xe7, 0x0, 0xc0, 0x4f, 0xd1, 0x40, 0xd2 } };
41
42 #else
43
44 // 64-bit
45 static const IID IID_IShellExt =
46     { 0x5f820ca1, 0x3dde, 0x11db, {0xb2, 0xce, 0x00, 0x15, 0x58, 0x09, 0x2d, 0xb5} };
47
48 #endif
49
50 /////////////////////////////////////////////////////////////////////////////
51 // CAfsShlExt
52
53 BEGIN_MESSAGE_MAP(CAfsShlExt, CWinApp)
54     //{{AFX_MSG_MAP(CAfsShlExt)
55     // NOTE - the ClassWizard will add and remove mapping macros here.
56     //    DO NOT EDIT what you see in these blocks of generated code!
57     //}}AFX_MSG_MAP
58 END_MESSAGE_MAP()
59
60 /////////////////////////////////////////////////////////////////////////////
61 // CAfsShlExt construction
62
63 CAfsShlExt::CAfsShlExt()
64 {
65     /* Start up sockets */
66     WSADATA WSAjunk;
67     WSAStartup(0x0101, &WSAjunk);
68 }
69
70 /////////////////////////////////////////////////////////////////////////////
71 // The one and only CAfsShlExt object
72
73 CAfsShlExt theApp;
74
75 /////////////////////////////////////////////////////////////////////////////
76 // CAfsShlExt initialization
77 HINSTANCE g_hInstance;
78
79 BOOL CAfsShlExt::InitInstance()
80 {
81     extern EXPORTED HINSTANCE TaLocale_LoadCorrespondingModuleByName (HINSTANCE hInstance, LPSTR pszFilename, WORD wSearchPriority = MODULE_PRIORITY_BOOSTED);
82
83     // Load our translated resources
84     TaLocale_LoadCorrespondingModuleByName (m_hInstance, "afs_shl_ext.dll");
85
86     // Register all OLE server (factories) as running.  This enables the
87     //  OLE libraries to create objects from other applications.
88     COleObjectFactory::RegisterAll();
89
90     SetHelpPath(m_pszHelpFilePath);
91
92     return TRUE;
93 }
94
95 /////////////////////////////////////////////////////////////////////////////
96 // Special entry points required for inproc servers
97
98 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
99 {
100     AFX_MANAGE_STATE(AfxGetStaticModuleState());
101     return AfxDllGetClassObject(rclsid, riid, ppv);
102 }       
103
104 STDAPI DllCanUnloadNow(void)
105 {
106     AFX_MANAGE_STATE(AfxGetStaticModuleState());
107
108 #ifdef COMMENT
109     // This test is correct and we really do want to allow the extension to be loaded and 
110     // unloaded as needed.   Unfortunately, the extension is being unloaded and never loaded
111     // again which is disconcerting for many folks.  For now we will prevent the unloading 
112     // until someone has time to figure out how to debug this.   
113     // Jeffrey Altman - 2 Oct 2005
114
115     if (!nCMRefCount && !nSERefCount && !nICRefCount && !nTPRefCount && !nXPRefCount)
116         return S_OK;
117 #endif
118     return S_FALSE;
119 }
120
121 int WideCharToLocal(LPTSTR pLocal, LPCWSTR pWide, DWORD dwChars)
122 {
123 #ifdef UNICODE
124     StringCchCopy(pLocal, dwChars, pWide);
125 #else
126     *pLocal = 0;
127     WideCharToMultiByte( CP_ACP, 0, pWide, -1, pLocal, dwChars, NULL, NULL);
128 #endif
129     return lstrlen(pLocal);
130 }
131
132 LRESULT DoRegCLSID(HKEY hKey,PTCHAR szSubKey,PTCHAR szData,PTCHAR szValue=NULL)
133 {
134     DWORD    dwDisp;
135     LRESULT  lResult;
136     HKEY     thKey;
137     lResult = RegCreateKeyEx(hKey, szSubKey, 0, NULL,
138                               REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
139                               &thKey, &dwDisp);
140     if(NOERROR == lResult)
141     {
142         lResult = RegSetValueEx(thKey, szValue, 0, REG_SZ,
143                                  (LPBYTE)szData, (lstrlen(szData) + 1) 
144                                  * sizeof(TCHAR));
145         RegCloseKey(thKey);
146     }
147     RegCloseKey(hKey);
148     return lResult;
149 }
150
151 // by exporting DllRegisterServer, you can use regsvr.exe
152 STDAPI DllRegisterServer(void)
153 {
154     HKEY     hKey;
155     LRESULT  lResult;
156     DWORD    dwDisp;
157     TCHAR    szSubKey[MAX_PATH];
158     TCHAR    szCLSID[MAX_PATH];
159     TCHAR    szModule[MAX_PATH];
160     LPWSTR   pwsz;
161     AFX_MANAGE_STATE(AfxGetStaticModuleState());
162     COleObjectFactory::UpdateRegistryAll();
163
164     StringFromIID(IID_IShellExt, &pwsz);
165     if(pwsz)
166     {
167 #ifdef UNICODE
168         StringCbCopy(szCLSID, sizeof(szCLSID), pwsz);
169 #else
170         WideCharToMultiByte( CP_ACP, 0,pwsz, -1, szCLSID, sizeof(szCLSID), NULL, NULL);
171 #endif
172         CoTaskMemFree(pwsz);
173     } else {
174         return E_FAIL;
175     }
176     
177     /*
178     [HKEY_CLASSES_ROOT\CLSID\{$CLSID}\InprocServer32]
179     @="Y:\\DEST\\root.client\\usr\\vice\\etc\\afs_shl_ext.dll"
180     "ThreadingModel"="Apartment"
181     */
182     HMODULE hModule=GetModuleHandle(TEXT("afs_shl_ext.dll"));
183     DWORD z=GetModuleFileName(hModule,szModule,sizeof(szModule));
184     wsprintf(szSubKey, TEXT("CLSID\\%s\\InprocServer32"),szCLSID);
185     if ((lResult=DoRegCLSID(HKEY_CLASSES_ROOT,szSubKey,szModule))!=NOERROR)
186         return lResult;
187
188     wsprintf(szSubKey, TEXT("CLSID\\%s\\InprocServer32"),szCLSID);
189     if ((lResult=DoRegCLSID(HKEY_CLASSES_ROOT,szSubKey,
190                             TEXT("Apartment"),TEXT("ThreadingModel")))!=NOERROR)
191         return lResult;
192
193     /*
194     [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\AFS Client Shell Extension]
195     @="{EA3775F2-28BE-11D3-9C8D-00105A24ED29}"
196     */
197
198     wsprintf(szSubKey, TEXT("%s\\%s"), STR_REG_PATH, STR_EXT_TITLE);
199     if ((lResult=DoRegCLSID(HKEY_LOCAL_MACHINE,szSubKey,szCLSID))!=NOERROR)
200         return lResult;
201         
202     //If running on NT, register the extension as approved.
203     /*
204     [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
205     "{$(CLSID)}"="AFS Client Shell Extension"
206
207     [HKEY_CLASSES_ROOT\Folder\shellex\ContextMenuHandlers\AFS Client Shell Extension]
208     @="{$(CLSID)}"
209     */
210
211     OSVERSIONINFO  osvi;
212     osvi.dwOSVersionInfoSize = sizeof(osvi);
213     GetVersionEx(&osvi);
214     if(VER_PLATFORM_WIN32_NT == osvi.dwPlatformId)
215     {
216         wsprintf(szSubKey, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"));
217         if ((lResult=DoRegCLSID(HKEY_LOCAL_MACHINE,szSubKey,_TEXT(STR_EXT_TITLE),szCLSID))!=NOERROR)
218             return lResult;
219     }
220     wsprintf(szSubKey, TEXT("*\\shellex\\ContextMenuHandlers\\%s"),STR_EXT_TITLE);
221     if ((lResult=DoRegCLSID(HKEY_CLASSES_ROOT,szSubKey,szCLSID))!=NOERROR)
222         return lResult;
223     wsprintf(szSubKey, TEXT("Folder\\shellex\\ContextMenuHandlers\\%s"),STR_EXT_TITLE);
224     if ((lResult=DoRegCLSID(HKEY_CLASSES_ROOT,szSubKey,szCLSID))!=NOERROR)
225         return lResult;
226
227     /*
228     Register InfoTip
229
230     [HKEY_CLASSES_ROOT\Folder\shellex\{00021500-0000-0000-C000-000000000046}]
231     @="{$(CLSID)}"
232     */
233
234     wsprintf(szSubKey, TEXT("Folder\\shellex\\{00021500-0000-0000-C000-000000000046}"));
235     if ((lResult=DoRegCLSID(HKEY_CLASSES_ROOT,szSubKey,szCLSID))!=NOERROR)
236         return lResult;
237
238         
239     /* Below needs to be merged with above */
240     wsprintf(szSubKey, TEXT("%s\\%s"), STR_REG_PATH, STR_EXT_TITLE);
241     lResult = RegCreateKeyEx(  HKEY_LOCAL_MACHINE,
242                               szSubKey,
243                               0,
244                               NULL,
245                               REG_OPTION_NON_VOLATILE,
246                               KEY_WRITE,
247                               NULL,
248                               &hKey,
249                               &dwDisp);
250
251     if(NOERROR == lResult)
252     {
253         //Create the value string.
254         lResult = RegSetValueEx( hKey,
255                                  NULL,
256                                  0,
257                                  REG_SZ,
258                                  (LPBYTE)szCLSID,
259                                  (lstrlen(szCLSID) + 1) * sizeof(TCHAR));
260         RegCloseKey(hKey);
261     }
262     else
263         return SELFREG_E_CLASS;
264
265     //If running on NT, register the extension as approved.
266     osvi.dwOSVersionInfoSize = sizeof(osvi);
267     GetVersionEx(&osvi);
268     if(VER_PLATFORM_WIN32_NT == osvi.dwPlatformId)
269     {
270         lstrcpy( szSubKey, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"));
271
272         lResult = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
273                                   szSubKey,
274                                   0,
275                                   NULL,
276                                   REG_OPTION_NON_VOLATILE,
277                                   KEY_WRITE,
278                                   NULL,
279                                   &hKey,
280                                   &dwDisp);
281
282         if(NOERROR == lResult)
283         {
284             TCHAR szData[MAX_PATH];
285
286             //Create the value string.
287             lstrcpy(szData, _TEXT(STR_EXT_TITLE));
288
289             lResult = RegSetValueEx( hKey,
290                                      szCLSID,
291                                      0,
292                                      REG_SZ,
293                                      (LPBYTE)szData,
294                                      (lstrlen(szData) + 1) * sizeof(TCHAR));
295
296             RegCloseKey(hKey);
297         } else
298             return SELFREG_E_CLASS;
299     }   
300     return S_OK;
301 }
302
303 //returnValue = RegOpenKeyEx (HKEY_CLASSES_ROOT, keyName, 0, KEY_ALL_ACCESS, &registryKey);
304
305 LRESULT DoValueDelete(HKEY hKey,PTCHAR pszSubKey,PTCHAR szValue=NULL)
306 {
307     LRESULT  lResult;
308     HKEY     thKey;
309     if (szValue==NULL) {
310         lResult=RegDeleteKey(hKey, pszSubKey);
311         return lResult;
312     }
313     lResult = RegOpenKeyEx( hKey,
314                             pszSubKey,
315                             0,
316                             (IsWow64()?KEY_WOW64_64KEY:0)|KEY_ALL_ACCESS,
317                             &thKey);
318     if(NOERROR == lResult)
319     {
320         lResult=RegDeleteValue(hKey, szValue);
321         RegCloseKey(thKey);
322     }
323     return lResult;
324 }
325
326 STDAPI DllUnregisterServer(void)
327 {
328     TCHAR    szSubKey[MAX_PATH];
329     TCHAR    szCLSID[MAX_PATH];
330     LPWSTR   pwsz;
331     AFX_MANAGE_STATE(AfxGetStaticModuleState());
332     COleObjectFactory::UpdateRegistryAll(FALSE);
333     StringFromIID(IID_IShellExt, &pwsz);
334     if(pwsz)
335     {
336 #ifdef UNICODE
337         StringCbCopy(szCLSID, sizeof(szCLSID), pwsz);
338 #else
339         WideCharToMultiByte( CP_ACP, 0,pwsz, -1, szCLSID, sizeof(szCLSID), NULL, NULL);
340 #endif
341         CoTaskMemFree(pwsz);
342     } else {
343         return E_FAIL;
344     }
345     wsprintf(szSubKey, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"));
346     DoValueDelete(HKEY_LOCAL_MACHINE,szSubKey,szCLSID);
347     wsprintf(szSubKey, TEXT("*\\shellex\\ContextMenuHandlers\\%s"),STR_EXT_TITLE);
348     DoValueDelete(HKEY_CLASSES_ROOT, szSubKey);
349     wsprintf(szSubKey, TEXT("Folder\\shellex\\{00021500-0000-0000-C000-000000000046}"));
350     DoValueDelete(HKEY_CLASSES_ROOT, szSubKey);
351     wsprintf(szSubKey, TEXT("Folder\\shellex\\ContextMenuHandlers\\%s"),STR_EXT_TITLE);
352     DoValueDelete(HKEY_CLASSES_ROOT, szSubKey);
353     wsprintf(szSubKey, TEXT("%s\\%s"), STR_REG_PATH, STR_EXT_TITLE);
354     DoValueDelete(HKEY_LOCAL_MACHINE, szSubKey);
355     return S_OK;
356 }       
357
358