2d06444004eefa325b9dc274d1e42ab914f40ae3
[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 static const IID IID_IShellExt2 =
42     { 0xdc515c27, 0x6cac, 0x11d1, { 0xba, 0xe7, 0x0, 0xc0, 0x4f, 0xd1, 0x40, 0xd3 } };
43
44 #else
45
46 // 64-bit
47 static const IID IID_IShellExt =
48     { 0x5f820ca1, 0x3dde, 0x11db, {0xb2, 0xce, 0x00, 0x15, 0x58, 0x09, 0x2d, 0xb5} };
49 static const IID IID_IShellExt2 =
50     { 0x5f820ca1, 0x3dde, 0x11db, {0xb2, 0xce, 0x00, 0x15, 0x58, 0x09, 0x2d, 0xb6} };
51
52 #endif
53
54 /////////////////////////////////////////////////////////////////////////////
55 // CAfsShlExt
56
57 BEGIN_MESSAGE_MAP(CAfsShlExt, CWinApp)
58     //{{AFX_MSG_MAP(CAfsShlExt)
59     // NOTE - the ClassWizard will add and remove mapping macros here.
60     //    DO NOT EDIT what you see in these blocks of generated code!
61     //}}AFX_MSG_MAP
62 END_MESSAGE_MAP()
63
64 /////////////////////////////////////////////////////////////////////////////
65 // CAfsShlExt construction
66
67 CAfsShlExt::CAfsShlExt()
68 {
69     /* Start up sockets */
70     WSADATA WSAjunk;
71     WSAStartup(0x0101, &WSAjunk);
72 }
73
74 /////////////////////////////////////////////////////////////////////////////
75 // The one and only CAfsShlExt object
76
77 CAfsShlExt theApp;
78
79 /////////////////////////////////////////////////////////////////////////////
80 // CAfsShlExt initialization
81 HINSTANCE g_hInstance;
82
83 BOOL CAfsShlExt::InitInstance()
84 {
85     extern EXPORTED HINSTANCE TaLocale_LoadCorrespondingModuleByName (HINSTANCE hInstance, LPSTR pszFilename, WORD wSearchPriority = MODULE_PRIORITY_BOOSTED);
86
87     // Load our translated resources
88     TaLocale_LoadCorrespondingModuleByName (m_hInstance, "afs_shl_ext.dll");
89
90     // Register all OLE server (factories) as running.  This enables the
91     //  OLE libraries to create objects from other applications.
92     COleObjectFactory::RegisterAll();
93
94     SetHelpPath(m_pszHelpFilePath);
95
96     return TRUE;
97 }
98
99 /////////////////////////////////////////////////////////////////////////////
100 // Special entry points required for inproc servers
101
102 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
103 {
104     AFX_MANAGE_STATE(AfxGetStaticModuleState());
105     return AfxDllGetClassObject(rclsid, riid, ppv);
106 }       
107
108 STDAPI DllCanUnloadNow(void)
109 {
110     AFX_MANAGE_STATE(AfxGetStaticModuleState());
111
112 #ifdef COMMENT
113     // This test is correct and we really do want to allow the extension to be loaded and 
114     // unloaded as needed.   Unfortunately, the extension is being unloaded and never loaded
115     // again which is disconcerting for many folks.  For now we will prevent the unloading 
116     // until someone has time to figure out how to debug this.   
117     // Jeffrey Altman - 2 Oct 2005
118
119     if (!nCMRefCount && !nSERefCount && !nICRefCount && !nTPRefCount && !nXPRefCount)
120         return S_OK;
121 #endif
122     return S_FALSE;
123 }
124
125 int WideCharToLocal(LPTSTR pLocal, LPCWSTR pWide, DWORD dwChars)
126 {
127 #ifdef UNICODE
128     StringCchCopy(pLocal, dwChars, pWide);
129 #else
130     *pLocal = 0;
131     WideCharToMultiByte( CP_ACP, 0, pWide, -1, pLocal, dwChars, NULL, NULL);
132 #endif
133     return lstrlen(pLocal);
134 }
135
136 LRESULT DoRegCLSID(HKEY hKey,PTCHAR szSubKey,PTCHAR szData,PTCHAR szValue=NULL)
137 {
138     DWORD    dwDisp;
139     LRESULT  lResult;
140     HKEY     thKey;
141     lResult = RegCreateKeyEx(hKey, szSubKey, 0, NULL,
142                               REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
143                               &thKey, &dwDisp);
144     if(NOERROR == lResult)
145     {
146         lResult = RegSetValueEx(thKey, szValue, 0, REG_SZ,
147                                  (LPBYTE)szData, (lstrlen(szData) + 1) 
148                                  * sizeof(TCHAR));
149         RegCloseKey(thKey);
150     }
151     RegCloseKey(hKey);
152     return lResult;
153 }
154
155 // by exporting DllRegisterServer, you can use regsvr.exe
156 STDAPI DllRegisterServer(void)
157 {
158     HKEY     hKey;
159     LRESULT  lResult;
160     DWORD    dwDisp;
161     TCHAR    szSubKey[MAX_PATH];
162     TCHAR    szCLSID[MAX_PATH];
163     TCHAR    szModule[MAX_PATH];
164     LPWSTR   pwsz;
165     AFX_MANAGE_STATE(AfxGetStaticModuleState());
166     COleObjectFactory::UpdateRegistryAll();
167
168     StringFromIID(IID_IShellExt, &pwsz);
169     if(pwsz)
170     {
171 #ifdef UNICODE
172         StringCbCopy(szCLSID, sizeof(szCLSID), pwsz);
173 #else
174         WideCharToMultiByte( CP_ACP, 0,pwsz, -1, szCLSID, sizeof(szCLSID), NULL, NULL);
175 #endif
176         CoTaskMemFree(pwsz);
177     } else {
178         return E_FAIL;
179     }
180     
181     /*
182     [HKEY_CLASSES_ROOT\CLSID\{$CLSID}\InprocServer32]
183     @="Y:\\DEST\\root.client\\usr\\vice\\etc\\afs_shl_ext.dll"
184     "ThreadingModel"="Apartment"
185     */
186     HMODULE hModule=GetModuleHandle(TEXT("afs_shl_ext.dll"));
187     DWORD z=GetModuleFileName(hModule,szModule,sizeof(szModule));
188     wsprintf(szSubKey, TEXT("CLSID\\%s\\InprocServer32"),szCLSID);
189     if ((lResult=DoRegCLSID(HKEY_CLASSES_ROOT,szSubKey,szModule))!=NOERROR)
190         return lResult;
191
192     wsprintf(szSubKey, TEXT("CLSID\\%s\\InprocServer32"),szCLSID);
193     if ((lResult=DoRegCLSID(HKEY_CLASSES_ROOT,szSubKey,
194                             TEXT("Apartment"),TEXT("ThreadingModel")))!=NOERROR)
195         return lResult;
196
197     /*
198     [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\AFS Client Shell Extension]
199     @="{EA3775F2-28BE-11D3-9C8D-00105A24ED29}"
200     */
201
202     wsprintf(szSubKey, TEXT("%s\\%s"), STR_REG_PATH, STR_EXT_TITLE);
203     if ((lResult=DoRegCLSID(HKEY_LOCAL_MACHINE,szSubKey,szCLSID))!=NOERROR)
204         return lResult;
205         
206     //If running on NT, register the extension as approved.
207     /*
208     [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
209     "{$(CLSID)}"="AFS Client Shell Extension"
210
211     [HKEY_CLASSES_ROOT\Folder\shellex\ContextMenuHandlers\AFS Client Shell Extension]
212     @="{$(CLSID)}"
213     */
214
215     OSVERSIONINFO  osvi;
216     osvi.dwOSVersionInfoSize = sizeof(osvi);
217     GetVersionEx(&osvi);
218     if(VER_PLATFORM_WIN32_NT == osvi.dwPlatformId)
219     {
220         wsprintf(szSubKey, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"));
221         if ((lResult=DoRegCLSID(HKEY_LOCAL_MACHINE,szSubKey,_TEXT(STR_EXT_TITLE),szCLSID))!=NOERROR)
222             return lResult;
223     }
224     wsprintf(szSubKey, TEXT("*\\shellex\\ContextMenuHandlers\\%s"),STR_EXT_TITLE);
225     if ((lResult=DoRegCLSID(HKEY_CLASSES_ROOT,szSubKey,szCLSID))!=NOERROR)
226         return lResult;
227     wsprintf(szSubKey, TEXT("Folder\\shellex\\ContextMenuHandlers\\%s"),STR_EXT_TITLE);
228     if ((lResult=DoRegCLSID(HKEY_CLASSES_ROOT,szSubKey,szCLSID))!=NOERROR)
229         return lResult;
230     wsprintf(szSubKey, TEXT("Directory\\Background\\shellex\\ContextMenuHandlers\\%s"),STR_EXT_TITLE);
231     if ((lResult=DoRegCLSID(HKEY_CLASSES_ROOT,szSubKey,szCLSID))!=NOERROR)
232         return lResult;
233     wsprintf(szSubKey, TEXT("LibraryFolder\\background\\shellex\\ContextMenuHandlers\\%s"),STR_EXT_TITLE);
234     if ((lResult=DoRegCLSID(HKEY_CLASSES_ROOT,szSubKey,szCLSID))!=NOERROR)
235         return lResult;
236
237     /*
238     Register InfoTip
239
240     [HKEY_CLASSES_ROOT\Folder\shellex\{00021500-0000-0000-C000-000000000046}]
241     @="{$(CLSID)}"
242     */
243
244     wsprintf(szSubKey, TEXT("Folder\\shellex\\{00021500-0000-0000-C000-000000000046}"));
245     if ((lResult=DoRegCLSID(HKEY_CLASSES_ROOT,szSubKey,szCLSID))!=NOERROR)
246         return lResult;
247
248         
249     /* Below needs to be merged with above */
250     wsprintf(szSubKey, TEXT("%s\\%s"), STR_REG_PATH, STR_EXT_TITLE);
251     lResult = RegCreateKeyEx(  HKEY_LOCAL_MACHINE,
252                               szSubKey,
253                               0,
254                               NULL,
255                               REG_OPTION_NON_VOLATILE,
256                               KEY_WRITE,
257                               NULL,
258                               &hKey,
259                               &dwDisp);
260
261     if(NOERROR == lResult)
262     {
263         //Create the value string.
264         lResult = RegSetValueEx( hKey,
265                                  NULL,
266                                  0,
267                                  REG_SZ,
268                                  (LPBYTE)szCLSID,
269                                  (lstrlen(szCLSID) + 1) * sizeof(TCHAR));
270         RegCloseKey(hKey);
271     }
272     else
273         return SELFREG_E_CLASS;
274
275     //If running on NT, register the extension as approved.
276     osvi.dwOSVersionInfoSize = sizeof(osvi);
277     GetVersionEx(&osvi);
278     if(VER_PLATFORM_WIN32_NT == osvi.dwPlatformId)
279     {
280         lstrcpy( szSubKey, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"));
281
282         lResult = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
283                                   szSubKey,
284                                   0,
285                                   NULL,
286                                   REG_OPTION_NON_VOLATILE,
287                                   KEY_WRITE,
288                                   NULL,
289                                   &hKey,
290                                   &dwDisp);
291
292         if(NOERROR == lResult)
293         {
294             TCHAR szData[MAX_PATH];
295
296             //Create the value string.
297             lstrcpy(szData, _TEXT(STR_EXT_TITLE));
298
299             lResult = RegSetValueEx( hKey,
300                                      szCLSID,
301                                      0,
302                                      REG_SZ,
303                                      (LPBYTE)szData,
304                                      (lstrlen(szData) + 1) * sizeof(TCHAR));
305
306             RegCloseKey(hKey);
307         } else
308             return SELFREG_E_CLASS;
309     }
310
311     StringFromIID(IID_IShellExt2, &pwsz);
312     if(pwsz)
313     {
314 #ifdef UNICODE
315         StringCbCopy(szCLSID, sizeof(szCLSID), pwsz);
316 #else
317         WideCharToMultiByte( CP_ACP, 0,pwsz, -1, szCLSID, sizeof(szCLSID), NULL, NULL);
318 #endif
319         CoTaskMemFree(pwsz);
320     } else {
321         return E_FAIL;
322     }
323
324     /*
325     [HKEY_CLASSES_ROOT\CLSID\{$CLSID}\InprocServer32]
326     @="Y:\\DEST\\root.client\\usr\\vice\\etc\\afs_shl_ext.dll"
327     "ThreadingModel"="Apartment"
328     */
329     hModule=GetModuleHandle(TEXT("afs_shl_ext.dll"));
330     z=GetModuleFileName(hModule,szModule,sizeof(szModule));
331     wsprintf(szSubKey, TEXT("CLSID\\%s\\InprocServer32"),szCLSID);
332     if ((lResult=DoRegCLSID(HKEY_CLASSES_ROOT,szSubKey,szModule))!=NOERROR)
333         return lResult;
334
335     wsprintf(szSubKey, TEXT("CLSID\\%s\\InprocServer32"),szCLSID);
336     if ((lResult=DoRegCLSID(HKEY_CLASSES_ROOT,szSubKey,
337                             TEXT("Apartment"),TEXT("ThreadingModel")))!=NOERROR)
338         return lResult;
339
340     /*
341     [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\AFS Client Shell Extension]
342     @="{EA3775F2-28BE-11D3-9C8D-00105A24ED29}"
343     */
344
345     wsprintf(szSubKey, TEXT("%s\\%s"), STR_REG_PATH, STR_EXT_TITLE2);
346     if ((lResult=DoRegCLSID(HKEY_LOCAL_MACHINE,szSubKey,szCLSID))!=NOERROR)
347         return lResult;
348
349     //If running on NT, register the extension as approved.
350     /*
351     [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
352     "{$(CLSID)}"="AFS Client Shell Extension"
353
354     [HKEY_CLASSES_ROOT\Folder\shellex\ContextMenuHandlers\AFS Client Shell Extension]
355     @="{$(CLSID)}"
356     */
357
358     osvi.dwOSVersionInfoSize = sizeof(osvi);
359     GetVersionEx(&osvi);
360     if(VER_PLATFORM_WIN32_NT == osvi.dwPlatformId)
361     {
362         wsprintf(szSubKey, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"));
363         if ((lResult=DoRegCLSID(HKEY_LOCAL_MACHINE,szSubKey,_TEXT(STR_EXT_TITLE2),szCLSID))!=NOERROR)
364             return lResult;
365     }
366
367
368     return S_OK;
369 }
370
371 //returnValue = RegOpenKeyEx (HKEY_CLASSES_ROOT, keyName, 0, KEY_ALL_ACCESS, &registryKey);
372
373 LRESULT DoValueDelete(HKEY hKey,PTCHAR pszSubKey,PTCHAR szValue=NULL)
374 {
375     LRESULT  lResult;
376     HKEY     thKey;
377     if (szValue==NULL) {
378         lResult=RegDeleteKey(hKey, pszSubKey);
379         return lResult;
380     }
381     lResult = RegOpenKeyEx( hKey,
382                             pszSubKey,
383                             0,
384                             (IsWow64()?KEY_WOW64_64KEY:0)|KEY_ALL_ACCESS,
385                             &thKey);
386     if(NOERROR == lResult)
387     {
388         lResult=RegDeleteValue(hKey, szValue);
389         RegCloseKey(thKey);
390     }
391     return lResult;
392 }
393
394 STDAPI DllUnregisterServer(void)
395 {
396     TCHAR    szSubKey[MAX_PATH];
397     TCHAR    szCLSID[MAX_PATH];
398     LPWSTR   pwsz;
399     AFX_MANAGE_STATE(AfxGetStaticModuleState());
400     COleObjectFactory::UpdateRegistryAll(FALSE);
401     StringFromIID(IID_IShellExt, &pwsz);
402     if(pwsz)
403     {
404 #ifdef UNICODE
405         StringCbCopy(szCLSID, sizeof(szCLSID), pwsz);
406 #else
407         WideCharToMultiByte( CP_ACP, 0,pwsz, -1, szCLSID, sizeof(szCLSID), NULL, NULL);
408 #endif
409         CoTaskMemFree(pwsz);
410     } else {
411         return E_FAIL;
412     }
413     wsprintf(szSubKey, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"));
414     DoValueDelete(HKEY_LOCAL_MACHINE,szSubKey,szCLSID);
415     wsprintf(szSubKey, TEXT("*\\shellex\\ContextMenuHandlers\\%s"),STR_EXT_TITLE);
416     DoValueDelete(HKEY_CLASSES_ROOT, szSubKey);
417     wsprintf(szSubKey, TEXT("Folder\\shellex\\{00021500-0000-0000-C000-000000000046}"));
418     DoValueDelete(HKEY_CLASSES_ROOT, szSubKey);
419     wsprintf(szSubKey, TEXT("Folder\\shellex\\ContextMenuHandlers\\%s"),STR_EXT_TITLE);
420     DoValueDelete(HKEY_CLASSES_ROOT, szSubKey);
421     wsprintf(szSubKey, TEXT("%s\\%s"), STR_REG_PATH, STR_EXT_TITLE);
422     DoValueDelete(HKEY_LOCAL_MACHINE, szSubKey);
423
424     StringFromIID(IID_IShellExt2, &pwsz);
425     if(pwsz)
426     {
427 #ifdef UNICODE
428         StringCbCopy(szCLSID, sizeof(szCLSID), pwsz);
429 #else
430         WideCharToMultiByte( CP_ACP, 0,pwsz, -1, szCLSID, sizeof(szCLSID), NULL, NULL);
431 #endif
432         CoTaskMemFree(pwsz);
433     } else {
434         return E_FAIL;
435     }
436     wsprintf(szSubKey, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"));
437     DoValueDelete(HKEY_LOCAL_MACHINE,szSubKey,szCLSID);
438
439     return S_OK;
440 }       
441
442