xref: /aosp_15_r20/external/lzma/CPP/7zip/UI/Explorer/DllExportsExplorer.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
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