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