Fixed cut&paste error.
[wine] / dlls / shlwapi / assoc.c
1 /*
2  * IQueryAssociations object and helper functions
3  *
4  * Copyright 2002 Jon Griffiths
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include <stdarg.h>
21
22 #include "windef.h"
23 #include "winbase.h"
24 #include "winnls.h"
25 #include "winreg.h"
26 #include "objbase.h"
27 #include "shlguid.h"
28 #include "shlwapi.h"
29 #include "wine/debug.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(shell);
32
33 /**************************************************************************
34  *  IQueryAssociations {SHLWAPI}
35  *
36  * DESCRIPTION
37  *  This object provides a layer of abstraction over the system registry in
38  *  order to simplify the process of parsing associations between files.
39  *  Associations in this context means the registry entries that link (for
40  *  example) the extension of a file with its description, list of
41  *  applications to open the file with, and actions that can be performed on it
42  *  (the shell displays such information in the context menu of explorer
43  *  when you right-click on a file).
44  *
45  * HELPERS
46  * You can use this object tranparently by calling the helper functions
47  * AssocQueryKeyA(), AssocQueryStringA() and AssocQueryStringByKeyA(). These
48  * create an IQueryAssociations object, perform the requested actions
49  * and then dispose of the object. Alternatively, you can create an instance
50  * of the object using AssocCreate() and call the following methods on it:
51  *
52  * METHODS
53  */
54
55 /* Default IQueryAssociations::Init() flags */
56 #define SHLWAPI_DEF_ASSOCF (ASSOCF_INIT_BYEXENAME|ASSOCF_INIT_DEFAULTTOSTAR| \
57                             ASSOCF_INIT_DEFAULTTOFOLDER)
58
59 typedef struct
60 {
61   ICOM_VFIELD(IQueryAssociations);
62   LONG ref;
63   HKEY hkeySource;
64   HKEY hkeyProgID;
65 } IQueryAssociationsImpl;
66
67 static struct ICOM_VTABLE(IQueryAssociations) IQueryAssociations_vtbl;
68
69 /**************************************************************************
70  *  IQueryAssociations_Constructor [internal]
71  *
72  * Construct a new IQueryAssociations object.
73  */
74 static IQueryAssociations* IQueryAssociations_Constructor(void)
75 {
76   IQueryAssociationsImpl* iface;
77
78   iface =(IQueryAssociationsImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IQueryAssociationsImpl));
79   iface->lpVtbl = &IQueryAssociations_vtbl;
80   iface->ref = 1;
81   iface->hkeySource = NULL;
82   iface->hkeyProgID = NULL;
83
84   TRACE("Returning IQueryAssociations* %p\n", iface);
85   return (IQueryAssociations*)iface;
86 }
87
88 /*************************************************************************
89  * SHLWAPI_ParamAToW
90  *
91  * Internal helper function: Convert ASCII parameter to Unicode.
92  */
93 static BOOL SHLWAPI_ParamAToW(LPCSTR lpszParam, LPWSTR lpszBuff, DWORD dwLen,
94                               LPWSTR* lpszOut)
95 {
96   if (lpszParam)
97   {
98     DWORD dwStrLen = lstrlenA(lpszParam);
99
100     if (dwStrLen < dwLen)
101     {
102       *lpszOut = lpszBuff; /* Use Buffer, it is big enough */
103     }
104     else
105     {
106       /* Create a new buffer big enough for the string */
107       *lpszOut = (LPWSTR)HeapAlloc(GetProcessHeap(), 0,
108                                    (dwStrLen + 1) * sizeof(WCHAR));
109       if (!*lpszOut)
110         return FALSE;
111     }
112     MultiByteToWideChar(0, 0, lpszParam, -1, *lpszOut, -1);
113   }
114   else
115     *lpszOut = NULL;
116   return TRUE;
117 }
118
119 /*************************************************************************
120  * AssocCreate  [SHLWAPI.@]
121  *
122  * Create a new IQueryAssociations object.
123  *
124  * PARAMS
125  *  clsid       [I] CLSID of object
126  *  refiid      [I] REFIID of interface
127  *  lpInterface [O] Destination for the created IQueryAssociations object
128  *
129  * RETURNS
130  *  Success: S_OK. lpInterface contains the new object.
131  *  Failure: An HRESULT error code indicating the error.
132  *
133  * NOTES
134  *  refiid must be equal to IID_IQueryAssociations, or this function will fail.
135  */
136 HRESULT WINAPI AssocCreate(CLSID clsid, REFIID refiid, void **lpInterface)
137 {
138   HRESULT hRet;
139   IQueryAssociations* lpAssoc;
140
141   TRACE("(%s,%s,%p)\n", debugstr_guid(&clsid), debugstr_guid(refiid),
142         lpInterface);
143
144   if (!lpInterface)
145     return E_INVALIDARG;
146
147   *(DWORD*)lpInterface = 0;
148
149   if (!IsEqualGUID(&clsid, &IID_IQueryAssociations))
150     return E_NOTIMPL;
151
152   lpAssoc = IQueryAssociations_Constructor();
153
154   if (!lpAssoc)
155     return E_OUTOFMEMORY;
156
157   hRet = IQueryAssociations_QueryInterface(lpAssoc, refiid, lpInterface);
158   IQueryAssociations_Release(lpAssoc);
159   return hRet;
160 }
161
162 /*************************************************************************
163  * AssocQueryKeyW  [SHLWAPI.@]
164  *
165  * See AssocQueryKeyA.
166  */
167 HRESULT WINAPI AssocQueryKeyW(ASSOCF cfFlags, ASSOCKEY assockey, LPCWSTR pszAssoc,
168                               LPCWSTR pszExtra, HKEY *phkeyOut)
169 {
170   HRESULT hRet;
171   IQueryAssociations* lpAssoc;
172
173   TRACE("(0x%8lx,0x%8x,%s,%s,%p)\n", cfFlags, assockey, debugstr_w(pszAssoc),
174         debugstr_w(pszExtra), phkeyOut);
175
176   lpAssoc = IQueryAssociations_Constructor();
177
178   if (!lpAssoc)
179     return E_OUTOFMEMORY;
180
181   cfFlags &= SHLWAPI_DEF_ASSOCF;
182   hRet = IQueryAssociations_Init(lpAssoc, cfFlags, pszAssoc, NULL, NULL);
183
184   if (SUCCEEDED(hRet))
185     hRet = IQueryAssociations_GetKey(lpAssoc, cfFlags, assockey, pszExtra, phkeyOut);
186
187   IQueryAssociations_Release(lpAssoc);
188   return hRet;
189 }
190
191 /*************************************************************************
192  * AssocQueryKeyA  [SHLWAPI.@]
193  *
194  * Get a file association key from the registry.
195  *
196  * PARAMS
197  *  cfFlags  [I] ASSOCF_ flags from "shlwapi.h"
198  *  assockey [I] Type of key to get
199  *  pszAssoc [I] Key name to search below
200  *  pszExtra [I] Extra information about the key location
201  *  phkeyOut [O] Destination for the association key
202  *
203  * RETURNS
204  *  Success: S_OK. phkeyOut contains the key.
205  *  Failure: An HRESULT error code indicating the error.
206  */
207 HRESULT WINAPI AssocQueryKeyA(ASSOCF cfFlags, ASSOCKEY assockey, LPCSTR pszAssoc,
208                               LPCSTR pszExtra, HKEY *phkeyOut)
209 {
210   WCHAR szAssocW[MAX_PATH], *lpszAssocW = NULL;
211   WCHAR szExtraW[MAX_PATH], *lpszExtraW = NULL;
212   HRESULT hRet = E_OUTOFMEMORY;
213
214   TRACE("(0x%8lx,0x%8x,%s,%s,%p)\n", cfFlags, assockey, debugstr_a(pszAssoc),
215         debugstr_a(pszExtra), phkeyOut);
216
217   if (SHLWAPI_ParamAToW(pszAssoc, szAssocW, MAX_PATH, &lpszAssocW) &&
218       SHLWAPI_ParamAToW(pszExtra, szExtraW, MAX_PATH, &lpszExtraW))
219   {
220     hRet = AssocQueryKeyW(cfFlags, assockey, lpszAssocW, lpszExtraW, phkeyOut);
221   }
222
223   if (lpszAssocW && lpszAssocW != szAssocW)
224     HeapFree(GetProcessHeap(), 0, lpszAssocW);
225
226   if (lpszExtraW && lpszExtraW != szExtraW)
227     HeapFree(GetProcessHeap(), 0, lpszExtraW);
228
229   return hRet;
230 }
231
232 /*************************************************************************
233  * AssocQueryStringW  [SHLWAPI.@]
234  *
235  * See AssocQueryStringA.
236  */
237 HRESULT WINAPI AssocQueryStringW(ASSOCF cfFlags, ASSOCSTR str, LPCWSTR pszAssoc,
238                                  LPCWSTR pszExtra, LPWSTR pszOut, DWORD *pcchOut)
239 {
240   HRESULT hRet;
241   IQueryAssociations* lpAssoc;
242
243   TRACE("(0x%8lx,0x%8x,%s,%s,%p,%p)\n", cfFlags, str, debugstr_w(pszAssoc),
244         debugstr_w(pszExtra), pszOut, pcchOut);
245
246   if (!pcchOut)
247     return E_INVALIDARG;
248
249   lpAssoc = IQueryAssociations_Constructor();
250
251   if (!lpAssoc)
252     return E_OUTOFMEMORY;
253
254   hRet = IQueryAssociations_Init(lpAssoc, cfFlags & SHLWAPI_DEF_ASSOCF,
255                                  pszAssoc, NULL, NULL);
256
257   if (SUCCEEDED(hRet))
258     hRet = IQueryAssociations_GetString(lpAssoc, cfFlags, str, pszExtra,
259                                         pszOut, pcchOut);
260
261   IQueryAssociations_Release(lpAssoc);
262   return hRet;
263 }
264
265 /*************************************************************************
266  * AssocQueryStringA  [SHLWAPI.@]
267  *
268  * Get a file association string from the registry.
269  *
270  * PARAMS
271  *  cfFlags  [I] ASSOCF_ flags from "shlwapi.h"
272  *  str      [I] Type of string to get (ASSOCSTR enum from "shlwapi.h")
273  *  pszAssoc [I] Key name to search below
274  *  pszExtra [I] Extra information about the string location
275  *  pszOut   [O] Destination for the association string
276  *  pcchOut  [O] Length of pszOut
277  *
278  * RETURNS
279  *  Success: S_OK. pszOut contains the string, pcchOut contains its length.
280  *  Failure: An HRESULT error code indicating the error.
281  */
282 HRESULT WINAPI AssocQueryStringA(ASSOCF cfFlags, ASSOCSTR str, LPCSTR pszAssoc,
283                                  LPCSTR pszExtra, LPSTR pszOut, DWORD *pcchOut)
284 {
285   WCHAR szAssocW[MAX_PATH], *lpszAssocW = NULL;
286   WCHAR szExtraW[MAX_PATH], *lpszExtraW = NULL;
287   HRESULT hRet = E_OUTOFMEMORY;
288
289   TRACE("(0x%8lx,0x%8x,%s,%s,%p,%p)\n", cfFlags, str, debugstr_a(pszAssoc),
290         debugstr_a(pszExtra), pszOut, pcchOut);
291
292   if (!pcchOut)
293     hRet = E_INVALIDARG;
294   else if (SHLWAPI_ParamAToW(pszAssoc, szAssocW, MAX_PATH, &lpszAssocW) &&
295            SHLWAPI_ParamAToW(pszExtra, szExtraW, MAX_PATH, &lpszExtraW))
296   {
297     WCHAR szReturnW[MAX_PATH], *lpszReturnW = szReturnW;
298     DWORD dwLenOut = *pcchOut;
299
300     if (dwLenOut >= MAX_PATH)
301       lpszReturnW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0,
302                                       (dwLenOut + 1) * sizeof(WCHAR));
303
304     if (!lpszReturnW)
305       hRet = E_OUTOFMEMORY;
306     else
307     {
308       hRet = AssocQueryStringW(cfFlags, str, lpszAssocW, lpszExtraW,
309                                lpszReturnW, &dwLenOut);
310
311       if (SUCCEEDED(hRet))
312         WideCharToMultiByte(CP_ACP,0,szReturnW,-1,pszOut,dwLenOut,0,0);
313       *pcchOut = dwLenOut;
314
315       if (lpszReturnW && lpszReturnW != szReturnW)
316         HeapFree(GetProcessHeap(), 0, lpszReturnW);
317     }
318   }
319
320   if (lpszAssocW && lpszAssocW != szAssocW)
321     HeapFree(GetProcessHeap(), 0, lpszAssocW);
322   if (lpszExtraW && lpszExtraW != szExtraW)
323     HeapFree(GetProcessHeap(), 0, lpszExtraW);
324   return hRet;
325 }
326
327 /*************************************************************************
328  * AssocQueryStringByKeyW  [SHLWAPI.@]
329  *
330  * See AssocQueryStringByKeyA.
331  */
332 HRESULT WINAPI AssocQueryStringByKeyW(ASSOCF cfFlags, ASSOCSTR str, HKEY hkAssoc,
333                                       LPCWSTR pszExtra, LPWSTR pszOut,
334                                       DWORD *pcchOut)
335 {
336   HRESULT hRet;
337   IQueryAssociations* lpAssoc;
338
339   TRACE("(0x%8lx,0x%8x,%p,%s,%p,%p)\n", cfFlags, str, hkAssoc,
340         debugstr_w(pszExtra), pszOut, pcchOut);
341
342   lpAssoc = IQueryAssociations_Constructor();
343
344   if (!lpAssoc)
345     return E_OUTOFMEMORY;
346
347   cfFlags &= SHLWAPI_DEF_ASSOCF;
348   hRet = IQueryAssociations_Init(lpAssoc, cfFlags, 0, hkAssoc, NULL);
349
350   if (SUCCEEDED(hRet))
351     hRet = IQueryAssociations_GetString(lpAssoc, cfFlags, str, pszExtra,
352                                         pszOut, pcchOut);
353
354   IQueryAssociations_Release(lpAssoc);
355   return hRet;
356 }
357
358 /*************************************************************************
359  * AssocQueryStringByKeyA  [SHLWAPI.@]
360  *
361  * Get a file association string from the registry, given a starting key.
362  *
363  * PARAMS
364  *  cfFlags  [I] ASSOCF_ flags from "shlwapi.h"
365  *  str      [I] Type of string to get
366  *  hkAssoc  [I] Key to search below
367  *  pszExtra [I] Extra information about the string location
368  *  pszOut   [O] Destination for the association string
369  *  pcchOut  [O] Length of pszOut
370  *
371  * RETURNS
372  *  Success: S_OK. pszOut contains the string, pcchOut contains its length.
373  *  Failure: An HRESULT error code indicating the error.
374  */
375 HRESULT WINAPI AssocQueryStringByKeyA(ASSOCF cfFlags, ASSOCSTR str, HKEY hkAssoc,
376                                       LPCSTR pszExtra, LPSTR pszOut,
377                                       DWORD *pcchOut)
378 {
379   WCHAR szExtraW[MAX_PATH], *lpszExtraW;
380   WCHAR szReturnW[MAX_PATH], *lpszReturnW = szReturnW;
381   HRESULT hRet = E_OUTOFMEMORY;
382
383   TRACE("(0x%8lx,0x%8x,%p,%s,%p,%p)\n", cfFlags, str, hkAssoc,
384         debugstr_a(pszExtra), pszOut, pcchOut);
385
386   if (!pcchOut)
387     hRet = E_INVALIDARG;
388   else if (SHLWAPI_ParamAToW(pszExtra, szExtraW, MAX_PATH, &lpszExtraW))
389   {
390     DWORD dwLenOut = *pcchOut;
391     if (dwLenOut >= MAX_PATH)
392       lpszReturnW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0,
393                                       (dwLenOut + 1) * sizeof(WCHAR));
394
395     if (lpszReturnW)
396     {
397       hRet = AssocQueryStringByKeyW(cfFlags, str, hkAssoc, lpszExtraW,
398                                     lpszReturnW, &dwLenOut);
399
400       if (SUCCEEDED(hRet))
401         WideCharToMultiByte(CP_ACP,0,szReturnW,-1,pszOut,dwLenOut,0,0);
402       *pcchOut = dwLenOut;
403
404       if (lpszReturnW != szReturnW)
405         HeapFree(GetProcessHeap(), 0, lpszReturnW);
406     }
407   }
408
409   if (lpszExtraW && lpszExtraW != szExtraW)
410     HeapFree(GetProcessHeap(), 0, lpszExtraW);
411   return hRet;
412 }
413
414
415 /**************************************************************************
416  *  AssocIsDangerous  (SHLWAPI.@)
417  */
418 HRESULT WINAPI AssocIsDangerous( ASSOCSTR str )
419 {
420     FIXME("%08x\n", str);
421     return S_FALSE;
422 }
423
424 /**************************************************************************
425  *  IQueryAssociations_QueryInterface {SHLWAPI}
426  *
427  * See IUnknown_QueryInterface.
428  */
429 static HRESULT WINAPI IQueryAssociations_fnQueryInterface(
430   IQueryAssociations* iface,
431   REFIID riid,
432   LPVOID *ppvObj)
433 {
434   ICOM_THIS(IQueryAssociationsImpl, iface);
435
436   TRACE("(%p,%s,%p)\n",This, debugstr_guid(riid), ppvObj);
437
438   *ppvObj = NULL;
439
440   if (IsEqualIID(riid, &IID_IUnknown) ||
441       IsEqualIID(riid, &IID_IQueryAssociations))
442   {
443     *ppvObj = (IQueryAssociations*)This;
444
445     IQueryAssociations_AddRef((IQueryAssociations*)*ppvObj);
446     TRACE("Returning IQueryAssociations (%p)\n", *ppvObj);
447     return S_OK;
448   }
449   TRACE("Returning E_NOINTERFACE\n");
450   return E_NOINTERFACE;
451 }
452
453 /**************************************************************************
454  *  IQueryAssociations_AddRef {SHLWAPI}
455  *
456  * See IUnknown_AddRef.
457  */
458 static ULONG WINAPI IQueryAssociations_fnAddRef(IQueryAssociations *iface)
459 {
460   ICOM_THIS(IQueryAssociationsImpl,iface);
461
462   TRACE("(%p)->(ref before=%lu)\n",This, This->ref);
463
464   return InterlockedIncrement(&This->ref);
465 }
466
467 /**************************************************************************
468  *  IQueryAssociations_Release {SHLWAPI}
469  *
470  * See IUnknown_Release.
471  */
472 static ULONG WINAPI IQueryAssociations_fnRelease(IQueryAssociations *iface)
473 {
474   ICOM_THIS(IQueryAssociationsImpl,iface);
475   ULONG ulRet;
476
477   TRACE("(%p)->(ref before=%lu)\n",This, This->ref);
478
479   if (!(ulRet = InterlockedDecrement(&This->ref)))
480   {
481     TRACE("Destroying IQueryAssociations (%p)\n", This);
482     HeapFree(GetProcessHeap(), 0, This);
483   }
484   return ulRet;
485 }
486
487 /**************************************************************************
488  *  IQueryAssociations_Init {SHLWAPI}
489  *
490  * Initialise an IQueryAssociations object.
491  *
492  * PARAMS
493  *  iface      [I] IQueryAssociations interface to initialise
494  *  cfFlags    [I] ASSOCF_ flags from "shlwapi.h"
495  *  pszAssoc   [I] String for the root key name, or NULL if hkProgid is given
496  *  hkeyProgid [I] Handle for the root key, or NULL if pszAssoc is given
497  *  hWnd       [I] Reserved, must be NULL.
498  *
499  * RETURNS
500  *  Success: S_OK. iface is initialised with the parameters given.
501  *  Failure: An HRESULT error code indicating the error.
502  */
503 static HRESULT WINAPI IQueryAssociations_fnInit(
504   IQueryAssociations *iface,
505   ASSOCF cfFlags,
506   LPCWSTR pszAssoc,
507   HKEY hkeyProgid,
508   HWND hWnd)
509 {
510     static const WCHAR szProgID[] = {'P','r','o','g','I','D',0};
511     ICOM_THIS(IQueryAssociationsImpl,iface);
512     HRESULT hr;
513
514     TRACE("(%p)->(%ld,%s,%p,%p)\n", iface,
515                                     cfFlags,
516                                     debugstr_w(pszAssoc),
517                                     hkeyProgid,
518                                     hWnd);
519     if (hWnd != NULL)
520         FIXME("hwnd != NULL not supported\n");
521     if (cfFlags != 0)
522         FIXME("unsupported flags: %lx\n", cfFlags);
523     if (pszAssoc != NULL)
524     {
525         hr = RegOpenKeyExW(HKEY_CLASSES_ROOT,
526                            pszAssoc,
527                            0,
528                            KEY_READ,
529                            &This->hkeySource);
530         if (FAILED(hr))
531             return HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION);
532         /* if this is not a prog id */
533         if ((*pszAssoc == '.') || (*pszAssoc == '{'))
534         {
535             hr = RegOpenKeyExW(This->hkeySource,
536                                szProgID,
537                                0,
538                                KEY_READ,
539                                &This->hkeyProgID);
540             if (FAILED(hr))
541                 FIXME("Don't know what to return\n");
542         }
543         else
544             This->hkeyProgID = This->hkeySource;
545         return S_OK;
546     }
547     else if (hkeyProgid != NULL)
548     {
549         This->hkeyProgID = hkeyProgid;
550         return S_OK;
551     }
552     else
553         return E_FAIL;
554 }
555
556 /**************************************************************************
557  *  IQueryAssociations_GetString {SHLWAPI}
558  *
559  * Get a file association string from the registry.
560  *
561  * PARAMS
562  *  iface    [I]   IQueryAssociations interface to query
563  *  cfFlags  [I]   ASSOCF_ flags from "shlwapi.h"
564  *  str      [I]   Type of string to get (ASSOCSTR enum from "shlwapi.h")
565  *  pszExtra [I]   Extra information about the string location
566  *  pszOut   [O]   Destination for the association string
567  *  pcchOut  [I/O] Length of pszOut
568  *
569  * RETURNS
570  *  Success: S_OK. pszOut contains the string, pcchOut contains its length.
571  *  Failure: An HRESULT error code indicating the error.
572  */
573 static HRESULT WINAPI IQueryAssociations_fnGetString(
574   IQueryAssociations *iface,
575   ASSOCF cfFlags,
576   ASSOCSTR str,
577   LPCWSTR pszExtra,
578   LPWSTR pszOut,
579   DWORD *pcchOut)
580 {
581   ICOM_THIS(IQueryAssociationsImpl, iface);
582
583   FIXME("(%p,0x%8lx,0x%8x,%s,%p,%p)-stub!\n", This, cfFlags, str,
584         debugstr_w(pszExtra), pszOut, pcchOut);
585   return E_NOTIMPL;
586 }
587
588 /**************************************************************************
589  *  IQueryAssociations_GetKey {SHLWAPI}
590  *
591  * Get a file association key from the registry.
592  *
593  * PARAMS
594  *  iface    [I] IQueryAssociations interface to query
595  *  cfFlags  [I] ASSOCF_ flags from "shlwapi.h"
596  *  assockey [I] Type of key to get (ASSOCKEY enum from "shlwapi.h")
597  *  pszExtra [I] Extra information about the key location
598  *  phkeyOut [O] Destination for the association key
599  *
600  * RETURNS
601  *  Success: S_OK. phkeyOut contains a handle to the key.
602  *  Failure: An HRESULT error code indicating the error.
603  */
604 static HRESULT WINAPI IQueryAssociations_fnGetKey(
605   IQueryAssociations *iface,
606   ASSOCF cfFlags,
607   ASSOCKEY assockey,
608   LPCWSTR pszExtra,
609   HKEY *phkeyOut)
610 {
611   ICOM_THIS(IQueryAssociationsImpl, iface);
612
613   FIXME("(%p,0x%8lx,0x%8x,%s,%p)-stub!\n", This, cfFlags, assockey,
614         debugstr_w(pszExtra), phkeyOut);
615   return E_NOTIMPL;
616 }
617
618 /**************************************************************************
619  *  IQueryAssociations_GetData {SHLWAPI}
620  *
621  * Get the data for a file association key from the registry.
622  *
623  * PARAMS
624  *  iface     [I]   IQueryAssociations interface to query
625  *  cfFlags   [I]   ASSOCF_ flags from "shlwapi.h"
626  *  assocdata [I]   Type of data to get (ASSOCDATA enum from "shlwapi.h")
627  *  pszExtra  [I]   Extra information about the data location
628  *  pvOut     [O]   Destination for the association key
629  *  pcbOut    [I/O] Size of pvOut
630  *
631  * RETURNS
632  *  Success: S_OK. pszOut contains the data, pcbOut contains its length.
633  *  Failure: An HRESULT error code indicating the error.
634  */
635 static HRESULT WINAPI IQueryAssociations_fnGetData(
636   IQueryAssociations *iface,
637   ASSOCF cfFlags,
638   ASSOCDATA assocdata,
639   LPCWSTR pszExtra,
640   LPVOID pvOut,
641   DWORD *pcbOut)
642 {
643   ICOM_THIS(IQueryAssociationsImpl, iface);
644
645   FIXME("(%p,0x%8lx,0x%8x,%s,%p,%p)-stub!\n", This, cfFlags, assocdata,
646         debugstr_w(pszExtra), pvOut, pcbOut);
647   return E_NOTIMPL;
648 }
649
650 /**************************************************************************
651  *  IQueryAssociations_GetEnum {SHLWAPI}
652  *
653  * Not yet implemented in native Win32.
654  *
655  * PARAMS
656  *  iface     [I] IQueryAssociations interface to query
657  *  cfFlags   [I] ASSOCF_ flags from "shlwapi.h"
658  *  assocenum [I] Type of enum to get (ASSOCENUM enum from "shlwapi.h")
659  *  pszExtra  [I] Extra information about the enum location
660  *  riid      [I] REFIID to look for
661  *  ppvOut    [O] Destination for the interface.
662  *
663  * RETURNS
664  *  Success: S_OK.
665  *  Failure: An HRESULT error code indicating the error.
666  *
667  * NOTES
668  *  Presumably this function returns an enumerator object.
669  */
670 static HRESULT WINAPI IQueryAssociations_fnGetEnum(
671   IQueryAssociations *iface,
672   ASSOCF cfFlags,
673   ASSOCENUM assocenum,
674   LPCWSTR pszExtra,
675   REFIID riid,
676   LPVOID *ppvOut)
677 {
678   ICOM_THIS(IQueryAssociationsImpl, iface);
679
680   FIXME("(%p,0x%8lx,0x%8x,%s,%s,%p)-stub!\n", This, cfFlags, assocenum,
681         debugstr_w(pszExtra), debugstr_guid(riid), ppvOut);
682   return E_NOTIMPL;
683 }
684
685 static struct ICOM_VTABLE(IQueryAssociations) IQueryAssociations_vtbl =
686 {
687   ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
688   IQueryAssociations_fnQueryInterface,
689   IQueryAssociations_fnAddRef,
690   IQueryAssociations_fnRelease,
691   IQueryAssociations_fnInit,
692   IQueryAssociations_fnGetString,
693   IQueryAssociations_fnGetKey,
694   IQueryAssociations_fnGetData,
695   IQueryAssociations_fnGetEnum
696 };