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