1 /* 2 * propsys main 3 * 4 * Copyright 1997, 2002 Alexandre Julliard 5 * Copyright 2008 James Hawkins 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 "propsys_private.h" 23 24 #include <rpcproxy.h> 25 26 static HINSTANCE propsys_hInstance; 27 28 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 29 { 30 TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved); 31 32 switch (fdwReason) 33 { 34 case DLL_WINE_PREATTACH: 35 return FALSE; /* prefer native version */ 36 case DLL_PROCESS_ATTACH: 37 propsys_hInstance = hinstDLL; 38 DisableThreadLibraryCalls(hinstDLL); 39 break; 40 } 41 42 return TRUE; 43 } 44 45 HRESULT WINAPI DllRegisterServer(void) 46 { 47 return __wine_register_resources( propsys_hInstance ); 48 } 49 50 HRESULT WINAPI DllUnregisterServer(void) 51 { 52 return __wine_unregister_resources( propsys_hInstance ); 53 } 54 55 static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv) 56 { 57 *ppv = NULL; 58 59 if(IsEqualGUID(&IID_IUnknown, riid)) { 60 TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv); 61 *ppv = iface; 62 }else if(IsEqualGUID(&IID_IClassFactory, riid)) { 63 TRACE("(%p)->(IID_IClassFactory %p)\n", iface, ppv); 64 *ppv = iface; 65 } 66 67 if(*ppv) { 68 IUnknown_AddRef((IUnknown*)*ppv); 69 return S_OK; 70 } 71 72 FIXME("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppv); 73 return E_NOINTERFACE; 74 } 75 76 static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface) 77 { 78 TRACE("(%p)\n", iface); 79 return 2; 80 } 81 82 static ULONG WINAPI ClassFactory_Release(IClassFactory *iface) 83 { 84 TRACE("(%p)\n", iface); 85 return 1; 86 } 87 88 static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL fLock) 89 { 90 TRACE("(%p)->(%x)\n", iface, fLock); 91 92 return S_OK; 93 } 94 95 static HRESULT WINAPI InMemoryPropertyStoreFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, 96 REFIID riid, void **ppv) 97 { 98 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv); 99 100 return PropertyStore_CreateInstance(outer, riid, ppv); 101 } 102 103 static const IClassFactoryVtbl InMemoryPropertyStoreFactoryVtbl = { 104 ClassFactory_QueryInterface, 105 ClassFactory_AddRef, 106 ClassFactory_Release, 107 InMemoryPropertyStoreFactory_CreateInstance, 108 ClassFactory_LockServer 109 }; 110 111 static IClassFactory InMemoryPropertyStoreFactory = { &InMemoryPropertyStoreFactoryVtbl }; 112 113 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) 114 { 115 if(IsEqualGUID(&CLSID_InMemoryPropertyStore, rclsid)) { 116 TRACE("(CLSID_InMemoryPropertyStore %s %p)\n", debugstr_guid(riid), ppv); 117 return IClassFactory_QueryInterface(&InMemoryPropertyStoreFactory, riid, ppv); 118 } 119 120 FIXME("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); 121 return CLASS_E_CLASSNOTAVAILABLE; 122 } 123 124 HRESULT WINAPI DllCanUnloadNow(void) 125 { 126 return S_FALSE; 127 } 128 129 static HRESULT WINAPI propsys_QueryInterface(IPropertySystem *iface, REFIID riid, void **obj) 130 { 131 *obj = NULL; 132 133 if (IsEqualIID(riid, &IID_IPropertySystem) || IsEqualIID(riid, &IID_IUnknown)) { 134 *obj = iface; 135 IPropertySystem_AddRef(iface); 136 return S_OK; 137 } 138 139 FIXME("%s\n", debugstr_guid(riid)); 140 return E_NOINTERFACE; 141 } 142 143 static ULONG WINAPI propsys_AddRef(IPropertySystem *iface) 144 { 145 return 2; 146 } 147 148 static ULONG WINAPI propsys_Release(IPropertySystem *iface) 149 { 150 return 1; 151 } 152 153 static HRESULT WINAPI propsys_GetPropertyDescription(IPropertySystem *iface, 154 REFPROPERTYKEY propkey, REFIID riid, void **ppv) 155 { 156 return PSGetPropertyDescription(propkey, riid, ppv); 157 } 158 159 static HRESULT WINAPI propsys_GetPropertyDescriptionByName(IPropertySystem *iface, 160 LPCWSTR canonical_name, REFIID riid, void **ppv) 161 { 162 FIXME("%s %s %p: stub\n", debugstr_w(canonical_name), debugstr_guid(riid), ppv); 163 return E_NOTIMPL; 164 } 165 166 static HRESULT WINAPI propsys_GetPropertyDescriptionListFromString(IPropertySystem *iface, 167 LPCWSTR proplist, REFIID riid, void **ppv) 168 { 169 return PSGetPropertyDescriptionListFromString(proplist, riid, ppv); 170 } 171 172 static HRESULT WINAPI propsys_EnumeratePropertyDescriptions(IPropertySystem *iface, 173 PROPDESC_ENUMFILTER filter, REFIID riid, void **ppv) 174 { 175 FIXME("%d %s %p: stub\n", filter, debugstr_guid(riid), ppv); 176 return E_NOTIMPL; 177 } 178 179 static HRESULT WINAPI propsys_FormatForDisplay(IPropertySystem *iface, 180 REFPROPERTYKEY key, REFPROPVARIANT propvar, PROPDESC_FORMAT_FLAGS flags, 181 LPWSTR dest, DWORD destlen) 182 { 183 FIXME("%p %p %x %p %d: stub\n", key, propvar, flags, dest, destlen); 184 return E_NOTIMPL; 185 } 186 187 static HRESULT WINAPI propsys_FormatForDisplayAlloc(IPropertySystem *iface, 188 REFPROPERTYKEY key, REFPROPVARIANT propvar, PROPDESC_FORMAT_FLAGS flags, 189 LPWSTR *text) 190 { 191 FIXME("%p %p %x %p: stub\n", key, propvar, flags, text); 192 return E_NOTIMPL; 193 } 194 195 static HRESULT WINAPI propsys_RegisterPropertySchema(IPropertySystem *iface, LPCWSTR path) 196 { 197 return PSRegisterPropertySchema(path); 198 } 199 200 static HRESULT WINAPI propsys_UnregisterPropertySchema(IPropertySystem *iface, LPCWSTR path) 201 { 202 return PSUnregisterPropertySchema(path); 203 } 204 205 static HRESULT WINAPI propsys_RefreshPropertySchema(IPropertySystem *iface) 206 { 207 return PSRefreshPropertySchema(); 208 } 209 210 static const IPropertySystemVtbl propsysvtbl = { 211 propsys_QueryInterface, 212 propsys_AddRef, 213 propsys_Release, 214 propsys_GetPropertyDescription, 215 propsys_GetPropertyDescriptionByName, 216 propsys_GetPropertyDescriptionListFromString, 217 propsys_EnumeratePropertyDescriptions, 218 propsys_FormatForDisplay, 219 propsys_FormatForDisplayAlloc, 220 propsys_RegisterPropertySchema, 221 propsys_UnregisterPropertySchema, 222 propsys_RefreshPropertySchema 223 }; 224 225 static IPropertySystem propsys = { &propsysvtbl }; 226 227 HRESULT WINAPI PSGetPropertySystem(REFIID riid, void **obj) 228 { 229 return IPropertySystem_QueryInterface(&propsys, riid, obj); 230 } 231 232 HRESULT WINAPI PSRegisterPropertySchema(PCWSTR path) 233 { 234 FIXME("%s stub\n", debugstr_w(path)); 235 236 return S_OK; 237 } 238 239 HRESULT WINAPI PSUnregisterPropertySchema(PCWSTR path) 240 { 241 FIXME("%s stub\n", debugstr_w(path)); 242 243 return E_NOTIMPL; 244 } 245 246 HRESULT WINAPI PSGetPropertyDescription(REFPROPERTYKEY propkey, REFIID riid, void **ppv) 247 { 248 FIXME("%p, %p, %p\n", propkey, riid, ppv); 249 return E_NOTIMPL; 250 } 251 252 HRESULT WINAPI PSGetPropertyDescriptionListFromString(LPCWSTR proplist, REFIID riid, void **ppv) 253 { 254 FIXME("%s, %p, %p\n", debugstr_w(proplist), riid, ppv); 255 return E_NOTIMPL; 256 } 257 258 HRESULT WINAPI PSRefreshPropertySchema(void) 259 { 260 FIXME("\n"); 261 return S_OK; 262 } 263 264 HRESULT WINAPI PSStringFromPropertyKey(REFPROPERTYKEY pkey, LPWSTR psz, UINT cch) 265 { 266 static const WCHAR guid_fmtW[] = {'{','%','0','8','X','-','%','0','4','X','-', 267 '%','0','4','X','-','%','0','2','X','%','0','2','X','-', 268 '%','0','2','X','%','0','2','X','%','0','2','X', 269 '%','0','2','X','%','0','2','X','%','0','2','X','}',0}; 270 static const WCHAR pid_fmtW[] = {'%','u',0}; 271 272 WCHAR pidW[PKEY_PIDSTR_MAX + 1]; 273 LPWSTR p = psz; 274 int len; 275 276 TRACE("(%p, %p, %u)\n", pkey, psz, cch); 277 278 if (!psz) 279 return E_POINTER; 280 281 /* GUIDSTRING_MAX accounts for null terminator, +1 for space character. */ 282 if (cch <= GUIDSTRING_MAX + 1) 283 return E_NOT_SUFFICIENT_BUFFER; 284 285 if (!pkey) 286 { 287 psz[0] = '\0'; 288 return E_NOT_SUFFICIENT_BUFFER; 289 } 290 291 sprintfW(psz, guid_fmtW, pkey->fmtid.Data1, pkey->fmtid.Data2, 292 pkey->fmtid.Data3, pkey->fmtid.Data4[0], pkey->fmtid.Data4[1], 293 pkey->fmtid.Data4[2], pkey->fmtid.Data4[3], pkey->fmtid.Data4[4], 294 pkey->fmtid.Data4[5], pkey->fmtid.Data4[6], pkey->fmtid.Data4[7]); 295 296 /* Overwrite the null terminator with the space character. */ 297 p += GUIDSTRING_MAX - 1; 298 *p++ = ' '; 299 cch -= GUIDSTRING_MAX - 1 + 1; 300 301 len = sprintfW(pidW, pid_fmtW, pkey->pid); 302 303 if (cch >= len + 1) 304 { 305 strcpyW(p, pidW); 306 return S_OK; 307 } 308 else 309 { 310 WCHAR *ptr = pidW + len - 1; 311 312 psz[0] = '\0'; 313 *p++ = '\0'; 314 cch--; 315 316 /* Replicate a quirk of the native implementation where the contents 317 * of the property ID string are written backwards to the output 318 * buffer, skipping the rightmost digit. */ 319 if (cch) 320 { 321 ptr--; 322 while (cch--) 323 *p++ = *ptr--; 324 } 325 326 return E_NOT_SUFFICIENT_BUFFER; 327 } 328 } 329 330 static const BYTE hex2bin[] = 331 { 332 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x00 */ 333 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x10 */ 334 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x20 */ 335 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, /* 0x30 */ 336 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, /* 0x40 */ 337 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x50 */ 338 0,10,11,12,13,14,15 /* 0x60 */ 339 }; 340 341 static BOOL validate_indices(LPCWSTR s, int min, int max) 342 { 343 int i; 344 345 for (i = min; i <= max; i++) 346 { 347 if (!s[i]) 348 return FALSE; 349 350 if (i == 0) 351 { 352 if (s[i] != '{') 353 return FALSE; 354 } 355 else if (i == 9 || i == 14 || i == 19 || i == 24) 356 { 357 if (s[i] != '-') 358 return FALSE; 359 } 360 else if (i == 37) 361 { 362 if (s[i] != '}') 363 return FALSE; 364 } 365 else 366 { 367 if (s[i] > 'f' || (!hex2bin[s[i]] && s[i] != '0')) 368 return FALSE; 369 } 370 } 371 372 return TRUE; 373 } 374 375 /* Adapted from CLSIDFromString helper in dlls/ole32/compobj.c and 376 * UuidFromString in dlls/rpcrt4/rpcrt4_main.c. */ 377 static BOOL string_to_guid(LPCWSTR s, LPGUID id) 378 { 379 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */ 380 381 if (!validate_indices(s, 0, 8)) return FALSE; 382 id->Data1 = (hex2bin[s[1]] << 28 | hex2bin[s[2]] << 24 | hex2bin[s[3]] << 20 | hex2bin[s[4]] << 16 | 383 hex2bin[s[5]] << 12 | hex2bin[s[6]] << 8 | hex2bin[s[7]] << 4 | hex2bin[s[8]]); 384 if (!validate_indices(s, 9, 14)) return FALSE; 385 id->Data2 = hex2bin[s[10]] << 12 | hex2bin[s[11]] << 8 | hex2bin[s[12]] << 4 | hex2bin[s[13]]; 386 if (!validate_indices(s, 15, 19)) return FALSE; 387 id->Data3 = hex2bin[s[15]] << 12 | hex2bin[s[16]] << 8 | hex2bin[s[17]] << 4 | hex2bin[s[18]]; 388 389 /* these are just sequential bytes */ 390 391 if (!validate_indices(s, 20, 21)) return FALSE; 392 id->Data4[0] = hex2bin[s[20]] << 4 | hex2bin[s[21]]; 393 if (!validate_indices(s, 22, 24)) return FALSE; 394 id->Data4[1] = hex2bin[s[22]] << 4 | hex2bin[s[23]]; 395 396 if (!validate_indices(s, 25, 26)) return FALSE; 397 id->Data4[2] = hex2bin[s[25]] << 4 | hex2bin[s[26]]; 398 if (!validate_indices(s, 27, 28)) return FALSE; 399 id->Data4[3] = hex2bin[s[27]] << 4 | hex2bin[s[28]]; 400 if (!validate_indices(s, 29, 30)) return FALSE; 401 id->Data4[4] = hex2bin[s[29]] << 4 | hex2bin[s[30]]; 402 if (!validate_indices(s, 31, 32)) return FALSE; 403 id->Data4[5] = hex2bin[s[31]] << 4 | hex2bin[s[32]]; 404 if (!validate_indices(s, 33, 34)) return FALSE; 405 id->Data4[6] = hex2bin[s[33]] << 4 | hex2bin[s[34]]; 406 if (!validate_indices(s, 35, 37)) return FALSE; 407 id->Data4[7] = hex2bin[s[35]] << 4 | hex2bin[s[36]]; 408 409 return TRUE; 410 } 411 412 HRESULT WINAPI PSPropertyKeyFromString(LPCWSTR pszString, PROPERTYKEY *pkey) 413 { 414 BOOL has_minus = FALSE, has_comma = FALSE; 415 416 TRACE("(%s, %p)\n", debugstr_w(pszString), pkey); 417 418 if (!pszString || !pkey) 419 return E_POINTER; 420 421 memset(pkey, 0, sizeof(PROPERTYKEY)); 422 423 if (!string_to_guid(pszString, &pkey->fmtid)) 424 return E_INVALIDARG; 425 426 pszString += GUIDSTRING_MAX - 1; 427 428 if (!*pszString) 429 return E_INVALIDARG; 430 431 /* Only the space seems to be recognized as whitespace. The comma is only 432 * recognized once and processing terminates if another comma is found. */ 433 while (*pszString == ' ' || *pszString == ',') 434 { 435 if (*pszString == ',') 436 { 437 if (has_comma) 438 return S_OK; 439 else 440 has_comma = TRUE; 441 } 442 pszString++; 443 } 444 445 if (!*pszString) 446 return E_INVALIDARG; 447 448 /* Only two minus signs are recognized if no comma is detected. The first 449 * sign is ignored, and the second is interpreted. If a comma is detected 450 * before the minus sign, then only one minus sign counts, and property ID 451 * interpretation begins with the next character. */ 452 if (has_comma) 453 { 454 if (*pszString == '-') 455 { 456 has_minus = TRUE; 457 pszString++; 458 } 459 } 460 else 461 { 462 if (*pszString == '-') 463 pszString++; 464 465 /* Skip any intermediate spaces after the first minus sign. */ 466 while (*pszString == ' ') 467 pszString++; 468 469 if (*pszString == '-') 470 { 471 has_minus = TRUE; 472 pszString++; 473 } 474 475 /* Skip any remaining spaces after minus sign. */ 476 while (*pszString == ' ') 477 pszString++; 478 } 479 480 /* Overflow is not checked. */ 481 while (isdigitW(*pszString)) 482 { 483 pkey->pid *= 10; 484 pkey->pid += (*pszString - '0'); 485 pszString++; 486 } 487 488 if (has_minus) 489 pkey->pid = ~pkey->pid + 1; 490 491 return S_OK; 492 } 493