a4a363e8f72e7f257da415ecb30be778dca79fdc
[reactos.git] / reactos / dll / win32 / shell32 / shell32.cpp
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 CStartMenu_Constructor(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 END_OBJECT_MAP()
257
258 CShell32Module gModule;
259
260
261 /***********************************************************************
262 * DllGetVersion [SHELL32.@]
263 *
264 * Retrieves version information of the 'SHELL32.DLL'
265 *
266 * PARAMS
267 * pdvi [O] pointer to version information structure.
268 *
269 * RETURNS
270 * Success: S_OK
271 * Failure: E_INVALIDARG
272 *
273 * NOTES
274 * Returns version of a shell32.dll from IE4.01 SP1.
275 */
276
277 STDAPI DllGetVersion(DLLVERSIONINFO *pdvi)
278 {
279 /* FIXME: shouldn't these values come from the version resource? */
280 if (pdvi->cbSize == sizeof(DLLVERSIONINFO) ||
281 pdvi->cbSize == sizeof(DLLVERSIONINFO2))
282 {
283 pdvi->dwMajorVersion = WINE_FILEVERSION_MAJOR;
284 pdvi->dwMinorVersion = WINE_FILEVERSION_MINOR;
285 pdvi->dwBuildNumber = WINE_FILEVERSION_BUILD;
286 pdvi->dwPlatformID = WINE_FILEVERSION_PLATFORMID;
287 if (pdvi->cbSize == sizeof(DLLVERSIONINFO2))
288 {
289 DLLVERSIONINFO2 *pdvi2 = (DLLVERSIONINFO2 *)pdvi;
290
291 pdvi2->dwFlags = 0;
292 pdvi2->ullVersion = MAKEDLLVERULL(WINE_FILEVERSION_MAJOR,
293 WINE_FILEVERSION_MINOR,
294 WINE_FILEVERSION_BUILD,
295 WINE_FILEVERSION_PLATFORMID);
296 }
297 TRACE("%u.%u.%u.%u\n",
298 pdvi->dwMajorVersion, pdvi->dwMinorVersion,
299 pdvi->dwBuildNumber, pdvi->dwPlatformID);
300 return S_OK;
301 }
302 else
303 {
304 WARN("wrong DLLVERSIONINFO size from app\n");
305 return E_INVALIDARG;
306 }
307 }
308
309 /*************************************************************************
310 * global variables of the shell32.dll
311 * all are once per process
312 *
313 */
314 HINSTANCE shell32_hInstance;
315
316 void *operator new (size_t, void *buf)
317 {
318 return buf;
319 }
320
321 /*************************************************************************
322 * SHELL32 DllMain
323 *
324 * NOTES
325 * calling oleinitialize here breaks sone apps.
326 */
327 STDAPI_(BOOL) DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID fImpLoad)
328 {
329 TRACE("%p 0x%x %p\n", hInstance, dwReason, fImpLoad);
330 if (dwReason == DLL_PROCESS_ATTACH)
331 {
332 shell32_hInstance = hInstance;
333 gModule.Init(ObjectMap, hInstance, &LIBID_Shell32);
334
335 DisableThreadLibraryCalls (hInstance);
336
337 /* get full path to this DLL for IExtractIconW_fnGetIconLocation() */
338 GetModuleFileNameW(hInstance, swShell32Name, MAX_PATH);
339 swShell32Name[MAX_PATH - 1] = '\0';
340
341 /* Initialize comctl32 */
342 INITCOMMONCONTROLSEX InitCtrls;
343 InitCtrls.dwSize = sizeof(INITCOMMONCONTROLSEX);
344 InitCtrls.dwICC = ICC_WIN95_CLASSES | ICC_DATE_CLASSES | ICC_USEREX_CLASSES;
345 InitCommonControlsEx(&InitCtrls);
346
347 /* Bad idea, initialization in DllMain! */
348 InitChangeNotifications();
349 }
350 else if (dwReason == DLL_PROCESS_DETACH)
351 {
352 shell32_hInstance = NULL;
353 SIC_Destroy();
354 FreeChangeNotifications();
355 gModule.Term();
356 }
357 return TRUE;
358 }
359
360 /***********************************************************************
361 * DllCanUnloadNow (SHELL32.@)
362 */
363 STDAPI DllCanUnloadNow()
364 {
365 return gModule.DllCanUnloadNow();
366 }
367
368 /*************************************************************************
369 * DllGetClassObject [SHELL32.@]
370 * SHDllGetClassObject [SHELL32.128]
371 */
372 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
373 {
374 HRESULT hResult;
375
376 TRACE("CLSID:%s,IID:%s\n", shdebugstr_guid(&rclsid), shdebugstr_guid(&riid));
377
378 hResult = gModule.DllGetClassObject(rclsid, riid, ppv);
379 TRACE("-- pointer to class factory: %p\n", *ppv);
380 return hResult;
381 }
382
383 /***********************************************************************
384 * DllRegisterServer (SHELL32.@)
385 */
386 STDAPI DllRegisterServer()
387 {
388 HRESULT hr;
389
390 hr = gModule.DllRegisterServer(TRUE);
391 if (FAILED(hr))
392 return hr;
393
394 hr = gModule.UpdateRegistryFromResource(IDR_FOLDEROPTIONS, TRUE, NULL);
395 if (FAILED(hr))
396 return hr;
397
398 hr = SHELL_RegisterShellFolders();
399 if (FAILED(hr))
400 return hr;
401
402 return S_OK;
403 }
404
405 /***********************************************************************
406 * DllUnregisterServer (SHELL32.@)
407 */
408 STDAPI DllUnregisterServer()
409 {
410 HRESULT hr;
411
412 hr = gModule.DllUnregisterServer(TRUE);
413 if (FAILED(hr))
414 return hr;
415
416 hr = gModule.UpdateRegistryFromResource(IDR_FOLDEROPTIONS, FALSE, NULL);
417 if (FAILED(hr))
418 return hr;
419
420 return S_OK;
421 }
422
423 /*************************************************************************
424 * DllInstall [SHELL32.@]
425 *
426 * PARAMETERS
427 *
428 * BOOL bInstall - TRUE for install, FALSE for uninstall
429 * LPCWSTR pszCmdLine - command line (unused by shell32?)
430 */
431
432 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
433 {
434 FIXME("%s %s: stub\n", bInstall ? "TRUE":"FALSE", debugstr_w(cmdline));
435 return S_OK; /* indicate success */
436 }