[SHELL32] Fix COM registration of IShellFolder, IShellLinkA/W, IQueryContinue and...
[reactos.git] / 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 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 }