1 // DLLExportsExplorer.cpp
2 //
3 // Notes:
4 // Win2000:
5 // If I register at HKCR\Folder\ShellEx then DLL is locked.
6 // otherwise it unloads after explorer closing.
7 // but if I call menu for desktop items it's locked all the time
8
9 #include "StdAfx.h"
10
11 #include "../../../Common/MyWindows.h"
12
13 #if defined(__clang__) && __clang_major__ >= 4
14 #pragma GCC diagnostic ignored "-Wnonportable-system-include-path"
15 #endif
16 // <olectl.h> : in new Windows Kit 10.0.2**** (NTDDI_WIN10_MN is defined)
17 // <OleCtl.h> : in another Windows Kit versions
18 #if defined(NTDDI_WIN10_MN) || defined(__MINGW32__) || defined(__MINGW64__)
19 #include <olectl.h>
20 #else
21 #include <OleCtl.h>
22 #endif
23
24 #if defined(__MINGW32__) || defined(__MINGW64__)
25 #include <shlguid.h>
26 #else
27 #include <ShlGuid.h>
28 #endif
29
30 #include "../../../Common/MyInitGuid.h"
31
32 #include "../../../Common/ComTry.h"
33
34 #include "../../../Windows/DLL.h"
35 #include "../../../Windows/ErrorMsg.h"
36 #include "../../../Windows/NtCheck.h"
37 #include "../../../Windows/Registry.h"
38
39 #include "../FileManager/IFolder.h"
40
41 #include "ContextMenu.h"
42
43 static LPCTSTR const k_ShellExtName = TEXT("7-Zip Shell Extension");
44 static LPCTSTR const k_Approved = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved");
45
46 // {23170F69-40C1-278A-1000-000100020000}
47 static LPCTSTR const k_Clsid = TEXT("{23170F69-40C1-278A-1000-000100020000}");
48
49 Z7_DEFINE_GUID(CLSID_CZipContextMenu,
50 k_7zip_GUID_Data1,
51 k_7zip_GUID_Data2,
52 k_7zip_GUID_Data3_Common,
53 0x10, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00);
54
55 using namespace NWindows;
56
57 extern
58 HINSTANCE g_hInstance;
59 HINSTANCE g_hInstance = NULL;
60
61 extern
62 HWND g_HWND;
63 HWND g_HWND = NULL;
64
65 extern
66 LONG g_DllRefCount;
67 LONG g_DllRefCount = 0; // Reference count of this DLL.
68
69 extern
70 bool g_DisableUserQuestions;
71 bool g_DisableUserQuestions;
72
73
74 // #define ODS(sz) OutputDebugStringW(L#sz)
75 #define ODS(sz)
76
77 class CShellExtClassFactory Z7_final:
78 public IClassFactory,
79 public CMyUnknownImp
80 {
81 Z7_COM_UNKNOWN_IMP_1_MT(IClassFactory)
82
83 STDMETHOD(CreateInstance)(LPUNKNOWN, REFIID, void**) Z7_override Z7_final;
84 STDMETHOD(LockServer)(BOOL) Z7_override Z7_final;
85 public:
CShellExtClassFactory()86 CShellExtClassFactory() { InterlockedIncrement(&g_DllRefCount); }
~CShellExtClassFactory()87 ~CShellExtClassFactory() { InterlockedDecrement(&g_DllRefCount); }
88 };
89
CreateInstance(LPUNKNOWN pUnkOuter,REFIID riid,void ** ppvObj)90 Z7_COMWF_B CShellExtClassFactory::CreateInstance(LPUNKNOWN pUnkOuter,
91 REFIID riid, void **ppvObj)
92 {
93 ODS("CShellExtClassFactory::CreateInstance()\r\n");
94 /*
95 char s[64];
96 ConvertUInt32ToHex(riid.Data1, s);
97 OutputDebugStringA(s);
98 */
99 *ppvObj = NULL;
100 if (pUnkOuter)
101 return CLASS_E_NOAGGREGATION;
102
103 CZipContextMenu *shellExt;
104 try
105 {
106 shellExt = new CZipContextMenu();
107 }
108 catch(...) { return E_OUTOFMEMORY; }
109 if (!shellExt)
110 return E_OUTOFMEMORY;
111
112 IContextMenu *ctxm = shellExt;
113 const HRESULT res = ctxm->QueryInterface(riid, ppvObj);
114 if (res != S_OK)
115 delete shellExt;
116 return res;
117 }
118
119
LockServer(BOOL)120 Z7_COMWF_B CShellExtClassFactory::LockServer(BOOL /* fLock */)
121 {
122 return S_OK; // Check it
123 }
124
125
126 #if defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE)
127 #define NT_CHECK_FAIL_ACTION return FALSE;
128 #endif
129
130 extern "C"
131 BOOL WINAPI DllMain(
132 #ifdef UNDER_CE
133 HANDLE hInstance
134 #else
135 HINSTANCE hInstance
136 #endif
137 , DWORD dwReason, LPVOID);
138
139 extern "C"
DllMain(HANDLE hInstance,DWORD dwReason,LPVOID)140 BOOL WINAPI DllMain(
141 #ifdef UNDER_CE
142 HANDLE hInstance
143 #else
144 HINSTANCE hInstance
145 #endif
146 , DWORD dwReason, LPVOID)
147 {
148 if (dwReason == DLL_PROCESS_ATTACH)
149 {
150 g_hInstance = (HINSTANCE)hInstance;
151 ODS("In DLLMain, DLL_PROCESS_ATTACH\r\n");
152 NT_CHECK
153 }
154 else if (dwReason == DLL_PROCESS_DETACH)
155 {
156 ODS("In DLLMain, DLL_PROCESS_DETACH\r\n");
157 }
158 return TRUE;
159 }
160
161
162 // Used to determine whether the DLL can be unloaded by OLE
163
DllCanUnloadNow(void)164 STDAPI DllCanUnloadNow(void)
165 {
166 ODS("In DLLCanUnloadNow\r\n");
167 /*
168 if (g_DllRefCount == 0)
169 ODS( "g_DllRefCount == 0");
170 else
171 ODS( "g_DllRefCount != 0");
172 */
173 return (g_DllRefCount == 0 ? S_OK : S_FALSE);
174 }
175
DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID * ppv)176 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
177 {
178 ODS("In DllGetClassObject\r\n");
179 *ppv = NULL;
180 if (IsEqualIID(rclsid, CLSID_CZipContextMenu))
181 {
182 CShellExtClassFactory *cf;
183 try
184 {
185 cf = new CShellExtClassFactory;
186 }
187 catch(...) { return E_OUTOFMEMORY; }
188 if (!cf)
189 return E_OUTOFMEMORY;
190 IClassFactory *cf2 = cf;
191 const HRESULT res = cf2->QueryInterface(riid, ppv);
192 if (res != S_OK)
193 delete cf;
194 return res;
195 }
196 return CLASS_E_CLASSNOTAVAILABLE;
197 // return _Module.GetClassObject(rclsid, riid, ppv);
198 }
199
200
RegisterServer()201 static BOOL RegisterServer()
202 {
203 ODS("RegisterServer\r\n");
204 FString modulePath;
205 if (!NDLL::MyGetModuleFileName(modulePath))
206 return FALSE;
207 const UString modulePathU = fs2us(modulePath);
208
209 CSysString s ("CLSID\\");
210 s += k_Clsid;
211
212 {
213 NRegistry::CKey key;
214 if (key.Create(HKEY_CLASSES_ROOT, s, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE) != NOERROR)
215 return FALSE;
216 key.SetValue(NULL, k_ShellExtName);
217 NRegistry::CKey keyInproc;
218 if (keyInproc.Create(key, TEXT("InprocServer32"), NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE) != NOERROR)
219 return FALSE;
220 keyInproc.SetValue(NULL, modulePathU);
221 keyInproc.SetValue(TEXT("ThreadingModel"), TEXT("Apartment"));
222 }
223
224 #if !defined(_WIN64) && !defined(UNDER_CE)
225 if (IsItWindowsNT())
226 #endif
227 {
228 NRegistry::CKey key;
229 if (key.Create(HKEY_LOCAL_MACHINE, k_Approved, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE) == NOERROR)
230 key.SetValue(k_Clsid, k_ShellExtName);
231 }
232
233 ODS("RegisterServer :: return TRUE");
234 return TRUE;
235 }
236
DllRegisterServer(void)237 STDAPI DllRegisterServer(void)
238 {
239 return RegisterServer() ? S_OK: SELFREG_E_CLASS;
240 }
241
UnregisterServer()242 static BOOL UnregisterServer()
243 {
244 CSysString s ("CLSID\\");
245 s += k_Clsid;
246
247 RegDeleteKey(HKEY_CLASSES_ROOT, s + TEXT("\\InprocServer32"));
248 RegDeleteKey(HKEY_CLASSES_ROOT, s);
249
250 #if !defined(_WIN64) && !defined(UNDER_CE)
251 if (IsItWindowsNT())
252 #endif
253 {
254 HKEY hKey;
255 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, k_Approved, 0, KEY_SET_VALUE, &hKey) == NOERROR)
256 {
257 RegDeleteValue(hKey, k_Clsid);
258 RegCloseKey(hKey);
259 }
260 }
261
262 return TRUE;
263 }
264
DllUnregisterServer(void)265 STDAPI DllUnregisterServer(void)
266 {
267 return UnregisterServer() ? S_OK: SELFREG_E_CLASS;
268 }
269