Windows: afs_shl_ext folder bkgrnd context menu
[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     wsprintf(szSubKey, TEXT("Directory\\Background\\shellex\\ContextMenuHandlers\\%s"),STR_EXT_TITLE);
227     if ((lResult=DoRegCLSID(HKEY_CLASSES_ROOT,szSubKey,szCLSID))!=NOERROR)
228         return lResult;
229     wsprintf(szSubKey, TEXT("LibraryFolder\\background\\shellex\\ContextMenuHandlers\\%s"),STR_EXT_TITLE);
230     if ((lResult=DoRegCLSID(HKEY_CLASSES_ROOT,szSubKey,szCLSID))!=NOERROR)
231         return lResult;
232
233     /*
234     Register InfoTip
235
236     [HKEY_CLASSES_ROOT\Folder\shellex\{00021500-0000-0000-C000-000000000046}]
237     @="{$(CLSID)}"
238     */
239
240     wsprintf(szSubKey, TEXT("Folder\\shellex\\{00021500-0000-0000-C000-000000000046}"));
241     if ((lResult=DoRegCLSID(HKEY_CLASSES_ROOT,szSubKey,szCLSID))!=NOERROR)
242         return lResult;
243
244         
245     /* Below needs to be merged with above */
246     wsprintf(szSubKey, TEXT("%s\\%s"), STR_REG_PATH, STR_EXT_TITLE);
247     lResult = RegCreateKeyEx(  HKEY_LOCAL_MACHINE,
248                               szSubKey,
249                               0,
250                               NULL,
251                               REG_OPTION_NON_VOLATILE,
252                               KEY_WRITE,
253                               NULL,
254                               &hKey,
255                               &dwDisp);
256
257     if(NOERROR == lResult)
258     {
259         //Create the value string.
260         lResult = RegSetValueEx( hKey,
261                                  NULL,
262                                  0,
263                                  REG_SZ,
264                                  (LPBYTE)szCLSID,
265                                  (lstrlen(szCLSID) + 1) * sizeof(TCHAR));
266         RegCloseKey(hKey);
267     }
268     else
269         return SELFREG_E_CLASS;
270
271     //If running on NT, register the extension as approved.
272     osvi.dwOSVersionInfoSize = sizeof(osvi);
273     GetVersionEx(&osvi);
274     if(VER_PLATFORM_WIN32_NT == osvi.dwPlatformId)
275     {
276         lstrcpy( szSubKey, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"));
277
278         lResult = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
279                                   szSubKey,
280                                   0,
281                                   NULL,
282                                   REG_OPTION_NON_VOLATILE,
283                                   KEY_WRITE,
284                                   NULL,
285                                   &hKey,
286                                   &dwDisp);
287
288         if(NOERROR == lResult)
289         {
290             TCHAR szData[MAX_PATH];
291
292             //Create the value string.
293             lstrcpy(szData, _TEXT(STR_EXT_TITLE));
294
295             lResult = RegSetValueEx( hKey,
296                                      szCLSID,
297                                      0,
298                                      REG_SZ,
299                                      (LPBYTE)szData,
300                                      (lstrlen(szData) + 1) * sizeof(TCHAR));
301
302             RegCloseKey(hKey);
303         } else
304             return SELFREG_E_CLASS;
305     }   
306     return S_OK;
307 }
308
309 //returnValue = RegOpenKeyEx (HKEY_CLASSES_ROOT, keyName, 0, KEY_ALL_ACCESS, &registryKey);
310
311 LRESULT DoValueDelete(HKEY hKey,PTCHAR pszSubKey,PTCHAR szValue=NULL)
312 {
313     LRESULT  lResult;
314     HKEY     thKey;
315     if (szValue==NULL) {
316         lResult=RegDeleteKey(hKey, pszSubKey);
317         return lResult;
318     }
319     lResult = RegOpenKeyEx( hKey,
320                             pszSubKey,
321                             0,
322                             (IsWow64()?KEY_WOW64_64KEY:0)|KEY_ALL_ACCESS,
323                             &thKey);
324     if(NOERROR == lResult)
325     {
326         lResult=RegDeleteValue(hKey, szValue);
327         RegCloseKey(thKey);
328     }
329     return lResult;
330 }
331
332 STDAPI DllUnregisterServer(void)
333 {
334     TCHAR    szSubKey[MAX_PATH];
335     TCHAR    szCLSID[MAX_PATH];
336     LPWSTR   pwsz;
337     AFX_MANAGE_STATE(AfxGetStaticModuleState());
338     COleObjectFactory::UpdateRegistryAll(FALSE);
339     StringFromIID(IID_IShellExt, &pwsz);
340     if(pwsz)
341     {
342 #ifdef UNICODE
343         StringCbCopy(szCLSID, sizeof(szCLSID), pwsz);
344 #else
345         WideCharToMultiByte( CP_ACP, 0,pwsz, -1, szCLSID, sizeof(szCLSID), NULL, NULL);
346 #endif
347         CoTaskMemFree(pwsz);
348     } else {
349         return E_FAIL;
350     }
351     wsprintf(szSubKey, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"));
352     DoValueDelete(HKEY_LOCAL_MACHINE,szSubKey,szCLSID);
353     wsprintf(szSubKey, TEXT("*\\shellex\\ContextMenuHandlers\\%s"),STR_EXT_TITLE);
354     DoValueDelete(HKEY_CLASSES_ROOT, szSubKey);
355     wsprintf(szSubKey, TEXT("Folder\\shellex\\{00021500-0000-0000-C000-000000000046}"));
356     DoValueDelete(HKEY_CLASSES_ROOT, szSubKey);
357     wsprintf(szSubKey, TEXT("Folder\\shellex\\ContextMenuHandlers\\%s"),STR_EXT_TITLE);
358     DoValueDelete(HKEY_CLASSES_ROOT, szSubKey);
359     wsprintf(szSubKey, TEXT("%s\\%s"), STR_REG_PATH, STR_EXT_TITLE);
360     DoValueDelete(HKEY_LOCAL_MACHINE, szSubKey);
361     return S_OK;
362 }       
363
364