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_ShellItem, CShellItem)
279 OBJECT_ENTRY(CLSID_ShellLink, CShellLink)
280 OBJECT_ENTRY(CLSID_Shell, CShellDispatch)
281 OBJECT_ENTRY(CLSID_DragDropHelper, CDropTargetHelper)
282 OBJECT_ENTRY(CLSID_ControlPanel, CControlPanelFolder)
283 OBJECT_ENTRY(CLSID_OpenControlPanel, COpenControlPanel)
284 OBJECT_ENTRY(CLSID_MyDocuments, CMyDocsFolder)
285 OBJECT_ENTRY(CLSID_NetworkPlaces, CNetFolder)
286 OBJECT_ENTRY(CLSID_FontsFolderShortcut, CFontsFolder)
287 OBJECT_ENTRY(CLSID_Printers, CPrinterFolder)
288 OBJECT_ENTRY(CLSID_AdminFolderShortcut, CAdminToolsFolder)
289 OBJECT_ENTRY(CLSID_ShellFldSetExt, CFolderOptions)
290 OBJECT_ENTRY(CLSID_RecycleBin, CRecycleBin)
291 OBJECT_ENTRY(CLSID_OpenWithMenu, COpenWithMenu)
292 OBJECT_ENTRY(CLSID_NewMenu, CNewMenu)
293 OBJECT_ENTRY(CLSID_SendToMenu, CSendToMenu)
294 OBJECT_ENTRY(CLSID_CopyAsPathMenu, CCopyAsPathMenu)
295 OBJECT_ENTRY(CLSID_CopyToMenu, CCopyToMenu)
296 OBJECT_ENTRY(CLSID_MoveToMenu, CMoveToMenu)
297 OBJECT_ENTRY(CLSID_StartMenu, CStartMenuDummy)
298 OBJECT_ENTRY(CLSID_MenuBandSite, CMenuSite)
299 OBJECT_ENTRY(CLSID_MenuBand, CMenuBand)
300 OBJECT_ENTRY(CLSID_MenuDeskBar, CMenuDeskBar)
301 OBJECT_ENTRY(CLSID_MergedFolder, CMergedFolder)
302 OBJECT_ENTRY(CLSID_ExeDropHandler, CExeDropHandler)
303 OBJECT_ENTRY(CLSID_QueryAssociations, CQueryAssociations)
304 OBJECT_ENTRY(CLSID_UserNotification, CUserNotification)
305 END_OBJECT_MAP()
306
307 CShell32Module gModule;
308
309
310 /***********************************************************************
311 * DllGetVersion [SHELL32.@]
312 *
313 * Retrieves version information of the 'SHELL32.DLL'
314 *
315 * PARAMS
316 * pdvi [O] pointer to version information structure.
317 *
318 * RETURNS
319 * Success: S_OK
320 * Failure: E_INVALIDARG
321 *
322 * NOTES
323 * Returns version of a shell32.dll from IE4.01 SP1.
324 */
325
DllGetVersion(DLLVERSIONINFO * pdvi)326 STDAPI DllGetVersion(DLLVERSIONINFO *pdvi)
327 {
328 /* FIXME: shouldn't these values come from the version resource? */
329 if (pdvi->cbSize == sizeof(DLLVERSIONINFO) ||
330 pdvi->cbSize == sizeof(DLLVERSIONINFO2))
331 {
332 pdvi->dwMajorVersion = WINE_FILEVERSION_MAJOR;
333 pdvi->dwMinorVersion = WINE_FILEVERSION_MINOR;
334 pdvi->dwBuildNumber = WINE_FILEVERSION_BUILD;
335 pdvi->dwPlatformID = WINE_FILEVERSION_PLATFORMID;
336 if (pdvi->cbSize == sizeof(DLLVERSIONINFO2))
337 {
338 DLLVERSIONINFO2 *pdvi2 = (DLLVERSIONINFO2 *)pdvi;
339
340 pdvi2->dwFlags = 0;
341 pdvi2->ullVersion = MAKEDLLVERULL(WINE_FILEVERSION_MAJOR,
342 WINE_FILEVERSION_MINOR,
343 WINE_FILEVERSION_BUILD,
344 WINE_FILEVERSION_PLATFORMID);
345 }
346 TRACE("%u.%u.%u.%u\n",
347 pdvi->dwMajorVersion, pdvi->dwMinorVersion,
348 pdvi->dwBuildNumber, pdvi->dwPlatformID);
349 return S_OK;
350 }
351 else
352 {
353 WARN("wrong DLLVERSIONINFO size from app\n");
354 return E_INVALIDARG;
355 }
356 }
357
358 /*************************************************************************
359 * global variables of the shell32.dll
360 * all are once per process
361 *
362 */
363 HINSTANCE shell32_hInstance;
364
365 /*************************************************************************
366 * SHELL32 DllMain
367 *
368 * NOTES
369 * calling oleinitialize here breaks sone apps.
370 */
DllMain(HINSTANCE hInstance,DWORD dwReason,LPVOID fImpLoad)371 STDAPI_(BOOL) DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID fImpLoad)
372 {
373 TRACE("%p 0x%x %p\n", hInstance, dwReason, fImpLoad);
374 if (dwReason == DLL_PROCESS_ATTACH)
375 {
376 shell32_hInstance = hInstance;
377 gModule.Init(ObjectMap, hInstance, &LIBID_Shell32);
378
379 DisableThreadLibraryCalls (hInstance);
380
381 /* get full path to this DLL for IExtractIconW_fnGetIconLocation() */
382 GetModuleFileNameW(hInstance, swShell32Name, MAX_PATH);
383 swShell32Name[MAX_PATH - 1] = '\0';
384
385 /* Initialize comctl32 */
386 INITCOMMONCONTROLSEX InitCtrls;
387 InitCtrls.dwSize = sizeof(INITCOMMONCONTROLSEX);
388 InitCtrls.dwICC = ICC_WIN95_CLASSES | ICC_DATE_CLASSES | ICC_USEREX_CLASSES;
389 InitCommonControlsEx(&InitCtrls);
390
391 /* Bad idea, initialization in DllMain! */
392 InitChangeNotifications();
393 }
394 else if (dwReason == DLL_PROCESS_DETACH)
395 {
396 shell32_hInstance = NULL;
397 SIC_Destroy();
398 FreeChangeNotifications();
399 gModule.Term();
400 }
401 return TRUE;
402 }
403
404 /***********************************************************************
405 * DllCanUnloadNow (SHELL32.@)
406 */
DllCanUnloadNow()407 STDAPI DllCanUnloadNow()
408 {
409 return gModule.DllCanUnloadNow();
410 }
411
412 /*************************************************************************
413 * DllGetClassObject [SHELL32.@]
414 * SHDllGetClassObject [SHELL32.128]
415 */
DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID * ppv)416 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
417 {
418 HRESULT hResult;
419
420 TRACE("CLSID:%s,IID:%s\n", shdebugstr_guid(&rclsid), shdebugstr_guid(&riid));
421
422 hResult = gModule.DllGetClassObject(rclsid, riid, ppv);
423 TRACE("-- pointer to class factory: %p\n", *ppv);
424 return hResult;
425 }
426
427 /***********************************************************************
428 * DllRegisterServer (SHELL32.@)
429 */
DllRegisterServer()430 STDAPI DllRegisterServer()
431 {
432 HRESULT hr;
433
434 hr = gModule.DllRegisterServer(TRUE);
435 if (FAILED(hr))
436 return hr;
437
438 hr = gModule.UpdateRegistryFromResource(IDR_FOLDEROPTIONS, TRUE, NULL);
439 if (FAILED(hr))
440 return hr;
441
442 hr = SHELL_RegisterShellFolders();
443 if (FAILED(hr))
444 return hr;
445
446 return S_OK;
447 }
448
449 /***********************************************************************
450 * DllUnregisterServer (SHELL32.@)
451 */
DllUnregisterServer()452 STDAPI DllUnregisterServer()
453 {
454 HRESULT hr;
455
456 hr = gModule.DllUnregisterServer(TRUE);
457 if (FAILED(hr))
458 return hr;
459
460 hr = gModule.UpdateRegistryFromResource(IDR_FOLDEROPTIONS, FALSE, NULL);
461 if (FAILED(hr))
462 return hr;
463
464 return S_OK;
465 }
466
467 /*************************************************************************
468 * DllInstall [SHELL32.@]
469 *
470 * PARAMETERS
471 *
472 * BOOL bInstall - TRUE for install, FALSE for uninstall
473 * LPCWSTR pszCmdLine - command line (unused by shell32?)
474 */
475
DllInstall(BOOL bInstall,LPCWSTR cmdline)476 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
477 {
478 FIXME("%s %s: stub\n", bInstall ? "TRUE":"FALSE", debugstr_w(cmdline));
479 return S_OK; /* indicate success */
480 }
481