xref: /reactos/dll/win32/shell32/shell32.cpp (revision 5ddbd373)
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
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  * Default ClassFactory types
68  */
69 typedef HRESULT (CALLBACK *LPFNCREATEINSTANCE)(IUnknown* pUnkOuter, REFIID riid, LPVOID* ppvObject);
70 HRESULT IDefClF_fnConstructor(LPFNCREATEINSTANCE lpfnCI, PLONG pcRefDll, const IID *riidInst, IClassFactory **theFactory);
71 
72 
73 /**************************************************************************
74  * Default ClassFactory Implementation
75  *
76  * SHCreateDefClassObject
77  *
78  * NOTES
79  *  Helper function for dlls without their own classfactory.
80  *  A generic classfactory is returned.
81  *  When the CreateInstance of the cf is called the callback is executed.
82  */
83 
84 class IDefClFImpl :
85     public CComObjectRootEx<CComMultiThreadModelNoCS>,
86     public IClassFactory
87 {
88 private:
89     CLSID                    *rclsid;
90     LPFNCREATEINSTANCE        lpfnCI;
91     const IID                *riidInst;
92     LONG                    *pcRefDll;        /* pointer to refcounter in external dll (ugrrr...) */
93 public:
94     IDefClFImpl();
95     HRESULT Initialize(LPFNCREATEINSTANCE lpfnCI, PLONG pcRefDll, const IID *riidInstx);
96 
97     // IClassFactory
98     virtual HRESULT WINAPI CreateInstance(IUnknown * pUnkOuter, REFIID riid, LPVOID *ppvObject);
99     virtual HRESULT WINAPI LockServer(BOOL fLock);
100 
101 BEGIN_COM_MAP(IDefClFImpl)
102     COM_INTERFACE_ENTRY_IID(IID_IClassFactory, IClassFactory)
103 END_COM_MAP()
104 };
105 
106 IDefClFImpl::IDefClFImpl()
107 {
108     lpfnCI = NULL;
109     riidInst = NULL;
110     pcRefDll = NULL;
111     rclsid = NULL;
112 }
113 
114 HRESULT IDefClFImpl::Initialize(LPFNCREATEINSTANCE lpfnCIx, PLONG pcRefDllx, const IID *riidInstx)
115 {
116     lpfnCI = lpfnCIx;
117     riidInst = riidInstx;
118     pcRefDll = pcRefDllx;
119 
120     if (pcRefDll)
121         InterlockedIncrement(pcRefDll);
122 
123     TRACE("(%p)%s\n", this, shdebugstr_guid(riidInst));
124     return S_OK;
125 }
126 
127 /******************************************************************************
128  * IDefClF_fnCreateInstance
129  */
130 HRESULT WINAPI IDefClFImpl::CreateInstance(IUnknown * pUnkOuter, REFIID riid, LPVOID *ppvObject)
131 {
132     TRACE("%p->(%p,%s,%p)\n", this, pUnkOuter, shdebugstr_guid(&riid), ppvObject);
133 
134     *ppvObject = NULL;
135 
136     if (riidInst == NULL || IsEqualCLSID(riid, *riidInst) || IsEqualCLSID(riid, IID_IUnknown))
137     {
138         return lpfnCI(pUnkOuter, riid, ppvObject);
139     }
140 
141     ERR("unknown IID requested %s\n", shdebugstr_guid(&riid));
142     return E_NOINTERFACE;
143 }
144 
145 /******************************************************************************
146  * IDefClF_fnLockServer
147  */
148 HRESULT WINAPI IDefClFImpl::LockServer(BOOL fLock)
149 {
150     TRACE("%p->(0x%x), not implemented\n", this, fLock);
151     return E_NOTIMPL;
152 }
153 
154 /**************************************************************************
155  *  IDefClF_fnConstructor
156  */
157 
158 HRESULT IDefClF_fnConstructor(LPFNCREATEINSTANCE lpfnCI, PLONG pcRefDll, const IID *riidInst, IClassFactory **theFactory)
159 {
160     return ShellObjectCreatorInit<IDefClFImpl>(lpfnCI, pcRefDll, riidInst, IID_PPV_ARG(IClassFactory, theFactory));
161 }
162 
163 /******************************************************************************
164  * SHCreateDefClassObject            [SHELL32.70]
165  */
166 HRESULT WINAPI SHCreateDefClassObject(
167     REFIID    riid,
168     LPVOID*    ppv,
169     LPFNCREATEINSTANCE lpfnCI,    /* [in] create instance callback entry */
170     LPDWORD    pcRefDll,        /* [in/out] ref count of the dll */
171     REFIID    riidInst)        /* [in] optional interface to the instance */
172 {
173     IClassFactory                *pcf;
174     HRESULT                        hResult;
175 
176     TRACE("%s %p %p %p %s\n", shdebugstr_guid(&riid), ppv, lpfnCI, pcRefDll, shdebugstr_guid(&riidInst));
177 
178     if (!IsEqualCLSID(riid, IID_IClassFactory))
179         return E_NOINTERFACE;
180     hResult = IDefClF_fnConstructor(lpfnCI, (PLONG)pcRefDll, &riidInst, &pcf);
181     if (FAILED(hResult))
182         return hResult;
183     *ppv = pcf;
184     return S_OK;
185 }
186 
187 /**************************************************************************
188  *  CStartMenuDummy
189  */
190 class CStartMenuDummy :
191     public CComCoClass<CStartMenuDummy, &CLSID_StartMenu>,
192     public CComObjectRootEx<CComMultiThreadModelNoCS>
193 {
194 private:
195     CStartMenuDummy();
196     virtual ~CStartMenuDummy();
197 
198 public:
199     DECLARE_REGISTRY_RESOURCEID(IDR_STARTMENU)
200 
201     class _CreatorClass
202     {
203     public:
204         static STDMETHODIMP CreateInstance(void *pv, REFIID riid, LPVOID *ppv)
205         {
206             if (ppv == NULL)
207                 return E_POINTER;
208             *ppv = NULL;
209             if (pv != NULL)
210                 return CLASS_E_NOAGGREGATION;
211             return RSHELL_CStartMenu_CreateInstance(riid, ppv);
212         }
213     };
214 };
215 
216 /**************************************************************************
217  *  CShell32Module
218  */
219 class CShell32Module : public CComModule
220 {
221 public:
222     void Term()
223     {
224         CComCreatorCentralInstance< ATL::CComObject< CDrivesFolder > >::Term();
225         CComCreatorCentralInstance< ATL::CComObject< CDesktopFolder > >::Term();
226         CComModule::Term();
227     }
228 };
229 
230 
231 BEGIN_OBJECT_MAP(ObjectMap)
232     OBJECT_ENTRY(CLSID_ShellFSFolder, CFSFolder)
233     OBJECT_ENTRY(CLSID_MyComputer, CDrivesFolder)
234     OBJECT_ENTRY(CLSID_ShellDesktop, CDesktopFolder)
235     OBJECT_ENTRY(CLSID_ShellItem, CShellItem)
236     OBJECT_ENTRY(CLSID_ShellLink, CShellLink)
237     OBJECT_ENTRY(CLSID_Shell, CShellDispatch)
238     OBJECT_ENTRY(CLSID_DragDropHelper, CDropTargetHelper)
239     OBJECT_ENTRY(CLSID_ControlPanel, CControlPanelFolder)
240     OBJECT_ENTRY(CLSID_MyDocuments, CMyDocsFolder)
241     OBJECT_ENTRY(CLSID_NetworkPlaces, CNetFolder)
242     OBJECT_ENTRY(CLSID_FontsFolderShortcut, CFontsFolder)
243     OBJECT_ENTRY(CLSID_Printers, CPrinterFolder)
244     OBJECT_ENTRY(CLSID_AdminFolderShortcut, CAdminToolsFolder)
245     OBJECT_ENTRY(CLSID_ShellFldSetExt, CFolderOptions)
246     OBJECT_ENTRY(CLSID_RecycleBin, CRecycleBin)
247     OBJECT_ENTRY(CLSID_OpenWithMenu, COpenWithMenu)
248     OBJECT_ENTRY(CLSID_NewMenu, CNewMenu)
249     OBJECT_ENTRY(CLSID_StartMenu, CStartMenuDummy)
250     OBJECT_ENTRY(CLSID_MenuBandSite, CMenuSite)
251     OBJECT_ENTRY(CLSID_MenuBand, CMenuBand)
252     OBJECT_ENTRY(CLSID_MenuDeskBar, CMenuDeskBar)
253     OBJECT_ENTRY(CLSID_MergedFolder, CMergedFolder)
254     OBJECT_ENTRY(CLSID_ExeDropHandler, CExeDropHandler)
255     OBJECT_ENTRY(CLSID_QueryAssociations, CQueryAssociations)
256     OBJECT_ENTRY(CLSID_UserNotification, CUserNotification)
257 END_OBJECT_MAP()
258 
259 CShell32Module  gModule;
260 
261 
262 /***********************************************************************
263  * DllGetVersion [SHELL32.@]
264  *
265  * Retrieves version information of the 'SHELL32.DLL'
266  *
267  * PARAMS
268  *     pdvi [O] pointer to version information structure.
269  *
270  * RETURNS
271  *     Success: S_OK
272  *     Failure: E_INVALIDARG
273  *
274  * NOTES
275  *     Returns version of a shell32.dll from IE4.01 SP1.
276  */
277 
278 STDAPI DllGetVersion(DLLVERSIONINFO *pdvi)
279 {
280     /* FIXME: shouldn't these values come from the version resource? */
281     if (pdvi->cbSize == sizeof(DLLVERSIONINFO) ||
282         pdvi->cbSize == sizeof(DLLVERSIONINFO2))
283     {
284         pdvi->dwMajorVersion = WINE_FILEVERSION_MAJOR;
285         pdvi->dwMinorVersion = WINE_FILEVERSION_MINOR;
286         pdvi->dwBuildNumber = WINE_FILEVERSION_BUILD;
287         pdvi->dwPlatformID = WINE_FILEVERSION_PLATFORMID;
288         if (pdvi->cbSize == sizeof(DLLVERSIONINFO2))
289         {
290             DLLVERSIONINFO2 *pdvi2 = (DLLVERSIONINFO2 *)pdvi;
291 
292             pdvi2->dwFlags = 0;
293             pdvi2->ullVersion = MAKEDLLVERULL(WINE_FILEVERSION_MAJOR,
294                                               WINE_FILEVERSION_MINOR,
295                                               WINE_FILEVERSION_BUILD,
296                                               WINE_FILEVERSION_PLATFORMID);
297         }
298         TRACE("%u.%u.%u.%u\n",
299               pdvi->dwMajorVersion, pdvi->dwMinorVersion,
300               pdvi->dwBuildNumber, pdvi->dwPlatformID);
301         return S_OK;
302     }
303     else
304     {
305         WARN("wrong DLLVERSIONINFO size from app\n");
306         return E_INVALIDARG;
307     }
308 }
309 
310 /*************************************************************************
311  * global variables of the shell32.dll
312  * all are once per process
313  *
314  */
315 HINSTANCE   shell32_hInstance;
316 
317 /*************************************************************************
318  * SHELL32 DllMain
319  *
320  * NOTES
321  *  calling oleinitialize here breaks sone apps.
322  */
323 STDAPI_(BOOL) DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID fImpLoad)
324 {
325     TRACE("%p 0x%x %p\n", hInstance, dwReason, fImpLoad);
326     if (dwReason == DLL_PROCESS_ATTACH)
327     {
328         shell32_hInstance = hInstance;
329         gModule.Init(ObjectMap, hInstance, &LIBID_Shell32);
330 
331         DisableThreadLibraryCalls (hInstance);
332 
333         /* get full path to this DLL for IExtractIconW_fnGetIconLocation() */
334         GetModuleFileNameW(hInstance, swShell32Name, MAX_PATH);
335         swShell32Name[MAX_PATH - 1] = '\0';
336 
337         /* Initialize comctl32 */
338         INITCOMMONCONTROLSEX InitCtrls;
339         InitCtrls.dwSize = sizeof(INITCOMMONCONTROLSEX);
340         InitCtrls.dwICC = ICC_WIN95_CLASSES | ICC_DATE_CLASSES | ICC_USEREX_CLASSES;
341         InitCommonControlsEx(&InitCtrls);
342 
343         /* Bad idea, initialization in DllMain! */
344         InitChangeNotifications();
345     }
346     else if (dwReason == DLL_PROCESS_DETACH)
347     {
348         shell32_hInstance = NULL;
349         SIC_Destroy();
350         FreeChangeNotifications();
351         gModule.Term();
352     }
353     return TRUE;
354 }
355 
356 /***********************************************************************
357  *              DllCanUnloadNow (SHELL32.@)
358  */
359 STDAPI DllCanUnloadNow()
360 {
361     return gModule.DllCanUnloadNow();
362 }
363 
364 /*************************************************************************
365  *              DllGetClassObject     [SHELL32.@]
366  *              SHDllGetClassObject   [SHELL32.128]
367  */
368 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
369 {
370     HRESULT                                hResult;
371 
372     TRACE("CLSID:%s,IID:%s\n", shdebugstr_guid(&rclsid), shdebugstr_guid(&riid));
373 
374     hResult = gModule.DllGetClassObject(rclsid, riid, ppv);
375     TRACE("-- pointer to class factory: %p\n", *ppv);
376     return hResult;
377 }
378 
379 /***********************************************************************
380  *              DllRegisterServer (SHELL32.@)
381  */
382 STDAPI DllRegisterServer()
383 {
384     HRESULT hr;
385 
386     hr = gModule.DllRegisterServer(TRUE);
387     if (FAILED(hr))
388         return hr;
389 
390     hr = gModule.UpdateRegistryFromResource(IDR_FOLDEROPTIONS, TRUE, NULL);
391     if (FAILED(hr))
392         return hr;
393 
394     hr = SHELL_RegisterShellFolders();
395     if (FAILED(hr))
396         return hr;
397 
398     return S_OK;
399 }
400 
401 /***********************************************************************
402  *              DllUnregisterServer (SHELL32.@)
403  */
404 STDAPI DllUnregisterServer()
405 {
406     HRESULT hr;
407 
408     hr = gModule.DllUnregisterServer(TRUE);
409     if (FAILED(hr))
410         return hr;
411 
412     hr = gModule.UpdateRegistryFromResource(IDR_FOLDEROPTIONS, FALSE, NULL);
413     if (FAILED(hr))
414         return hr;
415 
416     return S_OK;
417 }
418 
419 /*************************************************************************
420  * DllInstall         [SHELL32.@]
421  *
422  * PARAMETERS
423  *
424  *    BOOL bInstall - TRUE for install, FALSE for uninstall
425  *    LPCWSTR pszCmdLine - command line (unused by shell32?)
426  */
427 
428 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
429 {
430     FIXME("%s %s: stub\n", bInstall ? "TRUE":"FALSE", debugstr_w(cmdline));
431     return S_OK;        /* indicate success */
432 }
433