xref: /reactos/dll/win32/shell32/shell32.cpp (revision 2aadf2eb)
1 /*
2  *                 Shell basics
3  *
4  * Copyright 1998 Marcus Meissner
5  * Copyright 1998 Juergen Schmied (jsch)  *  <juergen.schmied@metronet.de>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include "precomp.h"
23 
24 #include "shell32_version.h"
25 
26 WINE_DEFAULT_DEBUG_CHANNEL(shell);
27 
28 /*
29  * Implemented
30  */
31 EXTERN_C LPWSTR
32 WINAPI
AddCommasW(DWORD lValue,LPWSTR lpNumber)33 AddCommasW(DWORD lValue, LPWSTR lpNumber)
34 {
35     WCHAR szValue[MAX_PATH], szSeparator[8 + 1];
36     NUMBERFMTW numFormat;
37 
38     GetLocaleInfoW(LOCALE_USER_DEFAULT,
39                    LOCALE_STHOUSAND,
40                    szSeparator,
41                    _countof(szSeparator));
42 
43     numFormat.NumDigits     = 0;
44     numFormat.LeadingZero   = 0;
45     numFormat.Grouping      = 3; // FIXME! Use GetLocaleInfoW with LOCALE_SGROUPING and interpret the result.
46     numFormat.lpDecimalSep  = szSeparator;
47     numFormat.lpThousandSep = szSeparator;
48     numFormat.NegativeOrder = 0;
49 
50     swprintf(szValue, L"%lu", lValue);
51 
52     if (GetNumberFormatW(LOCALE_USER_DEFAULT,
53                          0,
54                          szValue,
55                          &numFormat,
56                          lpNumber,
57                          MAX_PATH) != 0)
58     {
59         return lpNumber;
60     }
61 
62     wcscpy(lpNumber, szValue);
63     return lpNumber;
64 }
65 
66 /*
67  * Implemented
68  */
69 EXTERN_C BOOL
70 WINAPI
RegenerateUserEnvironment(LPVOID * lpEnvironment,BOOL bUpdateSelf)71 RegenerateUserEnvironment(LPVOID *lpEnvironment, BOOL bUpdateSelf)
72 {
73     HANDLE hUserToken;
74     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ | TOKEN_WRITE, &hUserToken))
75         return FALSE;
76 
77     BOOL bResult = CreateEnvironmentBlock(lpEnvironment, hUserToken, TRUE);
78     if (!bResult || !lpEnvironment)
79     {
80         CloseHandle(hUserToken);
81         return FALSE;
82     }
83 
84     if (bUpdateSelf)
85     {
86         LPWSTR pszz = (LPWSTR)*lpEnvironment;
87         if (!pszz)
88             return FALSE;
89 
90         while (*pszz)
91         {
92             size_t cch = wcslen(pszz);
93             LPWSTR pchEqual = wcschr(pszz, L'=');
94             if (pchEqual)
95             {
96                 CStringW strName(pszz, pchEqual - pszz);
97                 SetEnvironmentVariableW(strName, pchEqual + 1);
98             }
99             pszz += cch + 1;
100         }
101     }
102 
103     CloseHandle(hUserToken);
104 
105     return bResult;
106 }
107 
108 /**************************************************************************
109  * Default ClassFactory types
110  */
111 typedef HRESULT (CALLBACK *LPFNCREATEINSTANCE)(IUnknown* pUnkOuter, REFIID riid, LPVOID* ppvObject);
112 HRESULT IDefClF_fnConstructor(LPFNCREATEINSTANCE lpfnCI, PLONG pcRefDll, const IID *riidInst, IClassFactory **theFactory);
113 
114 
115 /**************************************************************************
116  * Default ClassFactory Implementation
117  *
118  * SHCreateDefClassObject
119  *
120  * NOTES
121  *  Helper function for dlls without their own classfactory.
122  *  A generic classfactory is returned.
123  *  When the CreateInstance of the cf is called the callback is executed.
124  */
125 
126 class IDefClFImpl :
127     public CComObjectRootEx<CComMultiThreadModelNoCS>,
128     public IClassFactory
129 {
130 private:
131     CLSID                    *rclsid;
132     LPFNCREATEINSTANCE        lpfnCI;
133     const IID                *riidInst;
134     LONG                    *pcRefDll;        /* pointer to refcounter in external dll (ugrrr...) */
135 public:
136     IDefClFImpl();
137     HRESULT Initialize(LPFNCREATEINSTANCE lpfnCI, PLONG pcRefDll, const IID *riidInstx);
138 
139     // IClassFactory
140     STDMETHOD(CreateInstance)(IUnknown * pUnkOuter, REFIID riid, LPVOID *ppvObject) override;
141     STDMETHOD(LockServer)(BOOL fLock) override;
142 
143 BEGIN_COM_MAP(IDefClFImpl)
144     COM_INTERFACE_ENTRY_IID(IID_IClassFactory, IClassFactory)
145 END_COM_MAP()
146 };
147 
IDefClFImpl()148 IDefClFImpl::IDefClFImpl()
149 {
150     lpfnCI = NULL;
151     riidInst = NULL;
152     pcRefDll = NULL;
153     rclsid = NULL;
154 }
155 
Initialize(LPFNCREATEINSTANCE lpfnCIx,PLONG pcRefDllx,const IID * riidInstx)156 HRESULT IDefClFImpl::Initialize(LPFNCREATEINSTANCE lpfnCIx, PLONG pcRefDllx, const IID *riidInstx)
157 {
158     lpfnCI = lpfnCIx;
159     riidInst = riidInstx;
160     pcRefDll = pcRefDllx;
161 
162     if (pcRefDll)
163         InterlockedIncrement(pcRefDll);
164 
165     TRACE("(%p)%s\n", this, shdebugstr_guid(riidInst));
166     return S_OK;
167 }
168 
169 /******************************************************************************
170  * IDefClF_fnCreateInstance
171  */
CreateInstance(IUnknown * pUnkOuter,REFIID riid,LPVOID * ppvObject)172 HRESULT WINAPI IDefClFImpl::CreateInstance(IUnknown * pUnkOuter, REFIID riid, LPVOID *ppvObject)
173 {
174     TRACE("%p->(%p,%s,%p)\n", this, pUnkOuter, shdebugstr_guid(&riid), ppvObject);
175 
176     *ppvObject = NULL;
177 
178     if (riidInst == NULL || IsEqualCLSID(riid, *riidInst) || IsEqualCLSID(riid, IID_IUnknown))
179     {
180         return lpfnCI(pUnkOuter, riid, ppvObject);
181     }
182 
183     ERR("unknown IID requested %s\n", shdebugstr_guid(&riid));
184     return E_NOINTERFACE;
185 }
186 
187 /******************************************************************************
188  * IDefClF_fnLockServer
189  */
LockServer(BOOL fLock)190 HRESULT WINAPI IDefClFImpl::LockServer(BOOL fLock)
191 {
192     TRACE("%p->(0x%x), not implemented\n", this, fLock);
193     return E_NOTIMPL;
194 }
195 
196 /**************************************************************************
197  *  IDefClF_fnConstructor
198  */
199 
IDefClF_fnConstructor(LPFNCREATEINSTANCE lpfnCI,PLONG pcRefDll,const IID * riidInst,IClassFactory ** theFactory)200 HRESULT IDefClF_fnConstructor(LPFNCREATEINSTANCE lpfnCI, PLONG pcRefDll, const IID *riidInst, IClassFactory **theFactory)
201 {
202     return ShellObjectCreatorInit<IDefClFImpl>(lpfnCI, pcRefDll, riidInst, IID_PPV_ARG(IClassFactory, theFactory));
203 }
204 
205 /******************************************************************************
206  * SHCreateDefClassObject            [SHELL32.70]
207  */
SHCreateDefClassObject(REFIID riid,LPVOID * ppv,LPFNCREATEINSTANCE lpfnCI,LPDWORD pcRefDll,REFIID riidInst)208 HRESULT WINAPI SHCreateDefClassObject(
209     REFIID    riid,
210     LPVOID*    ppv,
211     LPFNCREATEINSTANCE lpfnCI,    /* [in] create instance callback entry */
212     LPDWORD    pcRefDll,        /* [in/out] ref count of the dll */
213     REFIID    riidInst)        /* [in] optional interface to the instance */
214 {
215     IClassFactory                *pcf;
216     HRESULT                        hResult;
217 
218     TRACE("%s %p %p %p %s\n", shdebugstr_guid(&riid), ppv, lpfnCI, pcRefDll, shdebugstr_guid(&riidInst));
219 
220     if (!IsEqualCLSID(riid, IID_IClassFactory))
221         return E_NOINTERFACE;
222     hResult = IDefClF_fnConstructor(lpfnCI, (PLONG)pcRefDll, &riidInst, &pcf);
223     if (FAILED(hResult))
224         return hResult;
225     *ppv = pcf;
226     return S_OK;
227 }
228 
229 /**************************************************************************
230  *  CStartMenuDummy
231  */
232 class CStartMenuDummy :
233     public CComCoClass<CStartMenuDummy, &CLSID_StartMenu>,
234     public CComObjectRootEx<CComMultiThreadModelNoCS>
235 {
236 private:
237     CStartMenuDummy();
238     virtual ~CStartMenuDummy();
239 
240 public:
241     DECLARE_REGISTRY_RESOURCEID(IDR_STARTMENU)
242 
243     class _CreatorClass
244     {
245     public:
CreateInstance(void * pv,REFIID riid,LPVOID * ppv)246         static STDMETHODIMP CreateInstance(void *pv, REFIID riid, LPVOID *ppv)
247         {
248             if (ppv == NULL)
249                 return E_POINTER;
250             *ppv = NULL;
251             if (pv != NULL)
252                 return CLASS_E_NOAGGREGATION;
253             return RSHELL_CStartMenu_CreateInstance(riid, ppv);
254         }
255     };
256 };
257 
258 /**************************************************************************
259  *  CShell32Module
260  */
261 class CShell32Module : public CComModule
262 {
263 public:
Term()264     void Term()
265     {
266         CComCreatorCentralInstance< ATL::CComObject< CDrivesFolder > >::Term();
267         CComCreatorCentralInstance< ATL::CComObject< CDesktopFolder > >::Term();
268         CComModule::Term();
269     }
270 };
271 
272 
273 BEGIN_OBJECT_MAP(ObjectMap)
274     OBJECT_ENTRY(CLSID_ActiveDesktop, CActiveDesktop)
275     OBJECT_ENTRY(CLSID_ShellFSFolder, CFSFolder)
276     OBJECT_ENTRY(CLSID_MyComputer, CDrivesFolder)
277     OBJECT_ENTRY(CLSID_ShellDesktop, CDesktopFolder)
278     OBJECT_ENTRY(CLSID_ShellFileDefExt, CFileDefExt)
279     OBJECT_ENTRY(CLSID_ShellDrvDefExt, CDrvDefExt)
280     OBJECT_ENTRY(CLSID_ShellItem, CShellItem)
281     OBJECT_ENTRY(CLSID_ShellLink, CShellLink)
282     OBJECT_ENTRY(CLSID_Shell, CShellDispatch)
283     OBJECT_ENTRY(CLSID_DragDropHelper, CDropTargetHelper)
284     OBJECT_ENTRY(CLSID_ControlPanel, CControlPanelFolder)
285     OBJECT_ENTRY(CLSID_OpenControlPanel, COpenControlPanel)
286     OBJECT_ENTRY(CLSID_MyDocuments, CMyDocsFolder)
287     OBJECT_ENTRY(CLSID_NetworkPlaces, CNetFolder)
288     OBJECT_ENTRY(CLSID_FontsFolderShortcut, CFontsFolder)
289     OBJECT_ENTRY(CLSID_Printers, CPrinterFolder)
290     OBJECT_ENTRY(CLSID_AdminFolderShortcut, CAdminToolsFolder)
291     OBJECT_ENTRY(CLSID_ShellFldSetExt, CFolderOptions)
292     OBJECT_ENTRY(CLSID_RecycleBin, CRecycleBin)
293     OBJECT_ENTRY(CLSID_OpenWithMenu, COpenWithMenu)
294     OBJECT_ENTRY(CLSID_NewMenu, CNewMenu)
295     OBJECT_ENTRY(CLSID_SendToMenu, CSendToMenu)
296     OBJECT_ENTRY(CLSID_CopyAsPathMenu, CCopyAsPathMenu)
297     OBJECT_ENTRY(CLSID_CopyToMenu, CCopyToMenu)
298     OBJECT_ENTRY(CLSID_MoveToMenu, CMoveToMenu)
299     OBJECT_ENTRY(CLSID_StartMenu, CStartMenuDummy)
300     OBJECT_ENTRY(CLSID_MenuBandSite, CMenuSite)
301     OBJECT_ENTRY(CLSID_MenuBand, CMenuBand)
302     OBJECT_ENTRY(CLSID_MenuDeskBar, CMenuDeskBar)
303     OBJECT_ENTRY(CLSID_MergedFolder, CMergedFolder)
304     OBJECT_ENTRY(CLSID_ExeDropHandler, CExeDropHandler)
305     OBJECT_ENTRY(CLSID_QueryAssociations, CQueryAssociations)
306     OBJECT_ENTRY(CLSID_UserNotification, CUserNotification)
307 END_OBJECT_MAP()
308 
309 CShell32Module  gModule;
310 
311 
312 /***********************************************************************
313  * DllGetVersion [SHELL32.@]
314  *
315  * Retrieves version information of the 'SHELL32.DLL'
316  *
317  * PARAMS
318  *     pdvi [O] pointer to version information structure.
319  *
320  * RETURNS
321  *     Success: S_OK
322  *     Failure: E_INVALIDARG
323  *
324  * NOTES
325  *     Returns version of a shell32.dll from IE4.01 SP1.
326  */
327 
DllGetVersion(DLLVERSIONINFO * pdvi)328 STDAPI DllGetVersion(DLLVERSIONINFO *pdvi)
329 {
330     /* FIXME: shouldn't these values come from the version resource? */
331     if (pdvi->cbSize == sizeof(DLLVERSIONINFO) ||
332         pdvi->cbSize == sizeof(DLLVERSIONINFO2))
333     {
334         pdvi->dwMajorVersion = WINE_FILEVERSION_MAJOR;
335         pdvi->dwMinorVersion = WINE_FILEVERSION_MINOR;
336         pdvi->dwBuildNumber = WINE_FILEVERSION_BUILD;
337         pdvi->dwPlatformID = WINE_FILEVERSION_PLATFORMID;
338         if (pdvi->cbSize == sizeof(DLLVERSIONINFO2))
339         {
340             DLLVERSIONINFO2 *pdvi2 = (DLLVERSIONINFO2 *)pdvi;
341 
342             pdvi2->dwFlags = 0;
343             pdvi2->ullVersion = MAKEDLLVERULL(WINE_FILEVERSION_MAJOR,
344                                               WINE_FILEVERSION_MINOR,
345                                               WINE_FILEVERSION_BUILD,
346                                               WINE_FILEVERSION_PLATFORMID);
347         }
348         TRACE("%u.%u.%u.%u\n",
349               pdvi->dwMajorVersion, pdvi->dwMinorVersion,
350               pdvi->dwBuildNumber, pdvi->dwPlatformID);
351         return S_OK;
352     }
353     else
354     {
355         WARN("wrong DLLVERSIONINFO size from app\n");
356         return E_INVALIDARG;
357     }
358 }
359 
360 /*************************************************************************
361  * global variables of the shell32.dll
362  * all are once per process
363  *
364  */
365 HINSTANCE   shell32_hInstance;
366 
367 /*************************************************************************
368  * SHELL32 DllMain
369  *
370  * NOTES
371  *  calling oleinitialize here breaks sone apps.
372  */
DllMain(HINSTANCE hInstance,DWORD dwReason,LPVOID fImpLoad)373 STDAPI_(BOOL) DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID fImpLoad)
374 {
375     TRACE("%p 0x%x %p\n", hInstance, dwReason, fImpLoad);
376     if (dwReason == DLL_PROCESS_ATTACH)
377     {
378         shell32_hInstance = hInstance;
379         gModule.Init(ObjectMap, hInstance, &LIBID_Shell32);
380 
381         DisableThreadLibraryCalls (hInstance);
382 
383         /* get full path to this DLL for IExtractIconW_fnGetIconLocation() */
384         GetModuleFileNameW(hInstance, swShell32Name, MAX_PATH);
385         swShell32Name[MAX_PATH - 1] = '\0';
386 
387         /* Initialize comctl32 */
388         INITCOMMONCONTROLSEX InitCtrls;
389         InitCtrls.dwSize = sizeof(INITCOMMONCONTROLSEX);
390         InitCtrls.dwICC = ICC_WIN95_CLASSES | ICC_DATE_CLASSES | ICC_USEREX_CLASSES;
391         InitCommonControlsEx(&InitCtrls);
392 
393         /* Bad idea, initialization in DllMain! */
394         InitChangeNotifications();
395     }
396     else if (dwReason == DLL_PROCESS_DETACH)
397     {
398         shell32_hInstance = NULL;
399         SIC_Destroy();
400         FreeChangeNotifications();
401         gModule.Term();
402     }
403     return TRUE;
404 }
405 
406 /***********************************************************************
407  *              DllCanUnloadNow (SHELL32.@)
408  */
DllCanUnloadNow()409 STDAPI DllCanUnloadNow()
410 {
411     return gModule.DllCanUnloadNow();
412 }
413 
414 /*************************************************************************
415  *              DllGetClassObject     [SHELL32.@]
416  *              SHDllGetClassObject   [SHELL32.128]
417  */
DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID * ppv)418 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
419 {
420     HRESULT                                hResult;
421 
422     TRACE("CLSID:%s,IID:%s\n", shdebugstr_guid(&rclsid), shdebugstr_guid(&riid));
423 
424     hResult = gModule.DllGetClassObject(rclsid, riid, ppv);
425     TRACE("-- pointer to class factory: %p\n", *ppv);
426     return hResult;
427 }
428 
429 /***********************************************************************
430  *              DllRegisterServer (SHELL32.@)
431  */
DllRegisterServer()432 STDAPI DllRegisterServer()
433 {
434     HRESULT hr;
435 
436     hr = gModule.DllRegisterServer(TRUE);
437     if (FAILED(hr))
438         return hr;
439 
440     hr = gModule.UpdateRegistryFromResource(IDR_FOLDEROPTIONS, TRUE, NULL);
441     if (FAILED(hr))
442         return hr;
443 
444     hr = SHELL_RegisterShellFolders();
445     if (FAILED(hr))
446         return hr;
447 
448     return S_OK;
449 }
450 
451 /***********************************************************************
452  *              DllUnregisterServer (SHELL32.@)
453  */
DllUnregisterServer()454 STDAPI DllUnregisterServer()
455 {
456     HRESULT hr;
457 
458     hr = gModule.DllUnregisterServer(TRUE);
459     if (FAILED(hr))
460         return hr;
461 
462     hr = gModule.UpdateRegistryFromResource(IDR_FOLDEROPTIONS, FALSE, NULL);
463     if (FAILED(hr))
464         return hr;
465 
466     return S_OK;
467 }
468 
469 /*************************************************************************
470  * DllInstall         [SHELL32.@]
471  *
472  * PARAMETERS
473  *
474  *    BOOL bInstall - TRUE for install, FALSE for uninstall
475  *    LPCWSTR pszCmdLine - command line (unused by shell32?)
476  */
477 
DllInstall(BOOL bInstall,LPCWSTR cmdline)478 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
479 {
480     FIXME("%s %s: stub\n", bInstall ? "TRUE":"FALSE", debugstr_w(cmdline));
481     return S_OK;        /* indicate success */
482 }
483