1c2c66affSColin Finck /*
2c2c66affSColin Finck * IQueryAssociations object and helper functions
3c2c66affSColin Finck *
4c2c66affSColin Finck * Copyright 2002 Jon Griffiths
5c2c66affSColin Finck *
6c2c66affSColin Finck * This library is free software; you can redistribute it and/or
7c2c66affSColin Finck * modify it under the terms of the GNU Lesser General Public
8c2c66affSColin Finck * License as published by the Free Software Foundation; either
9c2c66affSColin Finck * version 2.1 of the License, or (at your option) any later version.
10c2c66affSColin Finck *
11c2c66affSColin Finck * This library is distributed in the hope that it will be useful,
12c2c66affSColin Finck * but WITHOUT ANY WARRANTY; without even the implied warranty of
13c2c66affSColin Finck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14c2c66affSColin Finck * Lesser General Public License for more details.
15c2c66affSColin Finck *
16c2c66affSColin Finck * You should have received a copy of the GNU Lesser General Public
17c2c66affSColin Finck * License along with this library; if not, write to the Free Software
18c2c66affSColin Finck * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19c2c66affSColin Finck */
20c2c66affSColin Finck
21c2c66affSColin Finck #include "precomp.h"
22c2c66affSColin Finck
23c2c66affSColin Finck WINE_DEFAULT_DEBUG_CHANNEL(shell);
24c2c66affSColin Finck
25c2c66affSColin Finck /**************************************************************************
26c2c66affSColin Finck * IQueryAssociations
27c2c66affSColin Finck *
28c2c66affSColin Finck * DESCRIPTION
29c2c66affSColin Finck * This object provides a layer of abstraction over the system registry in
30c2c66affSColin Finck * order to simplify the process of parsing associations between files.
31c2c66affSColin Finck * Associations in this context means the registry entries that link (for
32c2c66affSColin Finck * example) the extension of a file with its description, list of
33c2c66affSColin Finck * applications to open the file with, and actions that can be performed on it
34c2c66affSColin Finck * (the shell displays such information in the context menu of explorer
35c2c66affSColin Finck * when you right-click on a file).
36c2c66affSColin Finck *
37c2c66affSColin Finck * HELPERS
38c2c66affSColin Finck * You can use this object transparently by calling the helper functions
39c2c66affSColin Finck * AssocQueryKeyA(), AssocQueryStringA() and AssocQueryStringByKeyA(). These
40c2c66affSColin Finck * create an IQueryAssociations object, perform the requested actions
41c2c66affSColin Finck * and then dispose of the object. Alternatively, you can create an instance
42c2c66affSColin Finck * of the object using AssocCreate() and call the following methods on it:
43c2c66affSColin Finck *
44c2c66affSColin Finck * METHODS
45c2c66affSColin Finck */
46c2c66affSColin Finck
CQueryAssociations()47c2c66affSColin Finck CQueryAssociations::CQueryAssociations() : hkeySource(0), hkeyProgID(0)
48c2c66affSColin Finck {
49c2c66affSColin Finck }
50c2c66affSColin Finck
~CQueryAssociations()51c2c66affSColin Finck CQueryAssociations::~CQueryAssociations()
52c2c66affSColin Finck {
53c2c66affSColin Finck }
54c2c66affSColin Finck
55c2c66affSColin Finck /**************************************************************************
56c2c66affSColin Finck * IQueryAssociations_Init
57c2c66affSColin Finck *
58c2c66affSColin Finck * Initialise an IQueryAssociations object.
59c2c66affSColin Finck *
60c2c66affSColin Finck * PARAMS
61c2c66affSColin Finck * cfFlags [I] ASSOCF_ flags from "shlwapi.h"
62c2c66affSColin Finck * pszAssoc [I] String for the root key name, or NULL if hkeyProgid is given
63c2c66affSColin Finck * hkeyProgid [I] Handle for the root key, or NULL if pszAssoc is given
64c2c66affSColin Finck * hWnd [I] Reserved, must be NULL.
65c2c66affSColin Finck *
66c2c66affSColin Finck * RETURNS
67c2c66affSColin Finck * Success: S_OK. iface is initialised with the parameters given.
68c2c66affSColin Finck * Failure: An HRESULT error code indicating the error.
69c2c66affSColin Finck */
Init(ASSOCF cfFlags,LPCWSTR pszAssoc,HKEY hkeyProgid,HWND hWnd)70c2c66affSColin Finck HRESULT STDMETHODCALLTYPE CQueryAssociations::Init(
71c2c66affSColin Finck ASSOCF cfFlags,
72c2c66affSColin Finck LPCWSTR pszAssoc,
73c2c66affSColin Finck HKEY hkeyProgid,
74c2c66affSColin Finck HWND hWnd)
75c2c66affSColin Finck {
76c2c66affSColin Finck TRACE("(%p)->(%d,%s,%p,%p)\n", this,
77c2c66affSColin Finck cfFlags,
78c2c66affSColin Finck debugstr_w(pszAssoc),
79c2c66affSColin Finck hkeyProgid,
80c2c66affSColin Finck hWnd);
81c2c66affSColin Finck
82c2c66affSColin Finck if (hWnd != NULL)
83c2c66affSColin Finck {
84c2c66affSColin Finck FIXME("hwnd != NULL not supported\n");
85c2c66affSColin Finck }
86c2c66affSColin Finck
87c2c66affSColin Finck if (cfFlags != 0)
88c2c66affSColin Finck {
89c2c66affSColin Finck FIXME("unsupported flags: %x\n", cfFlags);
90c2c66affSColin Finck }
91c2c66affSColin Finck
92c2c66affSColin Finck RegCloseKey(this->hkeySource);
93c2c66affSColin Finck RegCloseKey(this->hkeyProgID);
94c2c66affSColin Finck this->hkeySource = this->hkeyProgID = NULL;
95c2c66affSColin Finck if (pszAssoc != NULL)
96c2c66affSColin Finck {
97c2c66affSColin Finck WCHAR *progId;
98c2c66affSColin Finck HRESULT hr;
996ac15363SKatayama Hirofumi MZ LPCWSTR pchDotExt;
1006ac15363SKatayama Hirofumi MZ
101*72a27e6dSKatayama Hirofumi MZ if (StrChrW(pszAssoc, L'\\'))
102*72a27e6dSKatayama Hirofumi MZ {
1036ac15363SKatayama Hirofumi MZ pchDotExt = PathFindExtensionW(pszAssoc);
1046ac15363SKatayama Hirofumi MZ if (pchDotExt && *pchDotExt)
1056ac15363SKatayama Hirofumi MZ pszAssoc = pchDotExt;
106*72a27e6dSKatayama Hirofumi MZ }
107c2c66affSColin Finck
108c2c66affSColin Finck LONG ret = RegOpenKeyExW(HKEY_CLASSES_ROOT,
109c2c66affSColin Finck pszAssoc,
110c2c66affSColin Finck 0,
111c2c66affSColin Finck KEY_READ,
112c2c66affSColin Finck &this->hkeySource);
113c2c66affSColin Finck if (ret)
114c2c66affSColin Finck {
115c2c66affSColin Finck return S_OK;
116c2c66affSColin Finck }
117c2c66affSColin Finck
118c2c66affSColin Finck /* if this is a progid */
119c2c66affSColin Finck if (*pszAssoc != '.' && *pszAssoc != '{')
120c2c66affSColin Finck {
121c2c66affSColin Finck this->hkeyProgID = this->hkeySource;
122c2c66affSColin Finck return S_OK;
123c2c66affSColin Finck }
124c2c66affSColin Finck
125c2c66affSColin Finck /* if it's not a progid, it's a file extension or clsid */
126c2c66affSColin Finck if (*pszAssoc == '.')
127c2c66affSColin Finck {
128c2c66affSColin Finck /* for a file extension, the progid is the default value */
129c2c66affSColin Finck hr = this->GetValue(this->hkeySource, NULL, (void**)&progId, NULL);
130c2c66affSColin Finck if (FAILED(hr))
131c2c66affSColin Finck return S_OK;
132c2c66affSColin Finck }
133c2c66affSColin Finck else /* if (*pszAssoc == '{') */
134c2c66affSColin Finck {
135c2c66affSColin Finck HKEY progIdKey;
136c2c66affSColin Finck /* for a clsid, the progid is the default value of the ProgID subkey */
13783be315aSHermès Bélusca-Maïto ret = RegOpenKeyExW(this->hkeySource, L"ProgID", 0, KEY_READ, &progIdKey);
138c2c66affSColin Finck if (ret != ERROR_SUCCESS)
139c2c66affSColin Finck return S_OK;
140c2c66affSColin Finck hr = this->GetValue(progIdKey, NULL, (void**)&progId, NULL);
141c2c66affSColin Finck if (FAILED(hr))
142c2c66affSColin Finck return S_OK;
143c2c66affSColin Finck RegCloseKey(progIdKey);
144c2c66affSColin Finck }
145c2c66affSColin Finck
146c2c66affSColin Finck /* open the actual progid key, the one with the shell subkey */
147c2c66affSColin Finck ret = RegOpenKeyExW(HKEY_CLASSES_ROOT,
148c2c66affSColin Finck progId,
149c2c66affSColin Finck 0,
150c2c66affSColin Finck KEY_READ,
151c2c66affSColin Finck &this->hkeyProgID);
152c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, progId);
153c2c66affSColin Finck
154c2c66affSColin Finck return S_OK;
155c2c66affSColin Finck }
156c2c66affSColin Finck else if (hkeyProgid != NULL)
157c2c66affSColin Finck {
158c2c66affSColin Finck /* reopen the key so we don't end up closing a key owned by the caller */
159c2c66affSColin Finck RegOpenKeyExW(hkeyProgid, NULL, 0, KEY_READ, &this->hkeyProgID);
160c2c66affSColin Finck this->hkeySource = this->hkeyProgID;
161c2c66affSColin Finck return S_OK;
162c2c66affSColin Finck }
163c2c66affSColin Finck else
164c2c66affSColin Finck return E_INVALIDARG;
165c2c66affSColin Finck }
166c2c66affSColin Finck
167c2c66affSColin Finck /**************************************************************************
168c2c66affSColin Finck * IQueryAssociations_GetString
169c2c66affSColin Finck *
170c2c66affSColin Finck * Get a file association string from the registry.
171c2c66affSColin Finck *
172c2c66affSColin Finck * PARAMS
173c2c66affSColin Finck * cfFlags [I] ASSOCF_ flags from "shlwapi.h"
174c2c66affSColin Finck * str [I] Type of string to get (ASSOCSTR enum from "shlwapi.h")
175c2c66affSColin Finck * pszExtra [I] Extra information about the string location
176c2c66affSColin Finck * pszOut [O] Destination for the association string
177c2c66affSColin Finck * pcchOut [I/O] Length of pszOut
178c2c66affSColin Finck *
179c2c66affSColin Finck * RETURNS
180c2c66affSColin Finck * Success: S_OK. pszOut contains the string, pcchOut contains its length.
181c2c66affSColin Finck * Failure: An HRESULT error code indicating the error.
182c2c66affSColin Finck */
GetString(ASSOCF flags,ASSOCSTR str,LPCWSTR pszExtra,LPWSTR pszOut,DWORD * pcchOut)183c2c66affSColin Finck HRESULT STDMETHODCALLTYPE CQueryAssociations::GetString(
184c2c66affSColin Finck ASSOCF flags,
185c2c66affSColin Finck ASSOCSTR str,
186c2c66affSColin Finck LPCWSTR pszExtra,
187c2c66affSColin Finck LPWSTR pszOut,
188c2c66affSColin Finck DWORD *pcchOut)
189c2c66affSColin Finck {
190c2c66affSColin Finck const ASSOCF unimplemented_flags = ~ASSOCF_NOTRUNCATE;
191c2c66affSColin Finck DWORD len = 0;
192c2c66affSColin Finck HRESULT hr;
193c2c66affSColin Finck WCHAR path[MAX_PATH];
194c2c66affSColin Finck
195c2c66affSColin Finck TRACE("(%p)->(0x%08x, %u, %s, %p, %p)\n", this, flags, str, debugstr_w(pszExtra), pszOut, pcchOut);
196c2c66affSColin Finck if (flags & unimplemented_flags)
197c2c66affSColin Finck {
198c2c66affSColin Finck FIXME("%08x: unimplemented flags\n", flags & unimplemented_flags);
199c2c66affSColin Finck }
200c2c66affSColin Finck
201c2c66affSColin Finck if (!pcchOut)
202c2c66affSColin Finck {
203c2c66affSColin Finck return E_UNEXPECTED;
204c2c66affSColin Finck }
205c2c66affSColin Finck
206c2c66affSColin Finck if (!this->hkeySource && !this->hkeyProgID)
207c2c66affSColin Finck {
208c2c66affSColin Finck return HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION);
209c2c66affSColin Finck }
210c2c66affSColin Finck
211c2c66affSColin Finck switch (str)
212c2c66affSColin Finck {
213c2c66affSColin Finck case ASSOCSTR_COMMAND:
214c2c66affSColin Finck {
215c2c66affSColin Finck WCHAR *command;
216c2c66affSColin Finck hr = this->GetCommand(pszExtra, &command);
217c2c66affSColin Finck if (SUCCEEDED(hr))
218c2c66affSColin Finck {
219c2c66affSColin Finck hr = this->ReturnString(flags, pszOut, pcchOut, command, strlenW(command) + 1);
220c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, command);
221c2c66affSColin Finck }
222c2c66affSColin Finck return hr;
223c2c66affSColin Finck }
224c2c66affSColin Finck case ASSOCSTR_EXECUTABLE:
225c2c66affSColin Finck {
226c2c66affSColin Finck hr = this->GetExecutable(pszExtra, path, MAX_PATH, &len);
2276ac15363SKatayama Hirofumi MZ if (FAILED_UNEXPECTEDLY(hr))
228c2c66affSColin Finck {
229c2c66affSColin Finck return hr;
230c2c66affSColin Finck }
231c2c66affSColin Finck len++;
232c2c66affSColin Finck return this->ReturnString(flags, pszOut, pcchOut, path, len);
233c2c66affSColin Finck }
234c2c66affSColin Finck case ASSOCSTR_FRIENDLYDOCNAME:
235c2c66affSColin Finck {
236c2c66affSColin Finck WCHAR *pszFileType;
237c2c66affSColin Finck
238c2c66affSColin Finck hr = this->GetValue(this->hkeySource, NULL, (void**)&pszFileType, NULL);
239c2c66affSColin Finck if (FAILED(hr))
240c2c66affSColin Finck {
241c2c66affSColin Finck return hr;
242c2c66affSColin Finck }
243c2c66affSColin Finck DWORD size = 0;
244c2c66affSColin Finck DWORD ret = RegGetValueW(HKEY_CLASSES_ROOT, pszFileType, NULL, RRF_RT_REG_SZ, NULL, NULL, &size);
245c2c66affSColin Finck if (ret == ERROR_SUCCESS)
246c2c66affSColin Finck {
247c2c66affSColin Finck WCHAR *docName = static_cast<WCHAR *>(HeapAlloc(GetProcessHeap(), 0, size));
248c2c66affSColin Finck if (docName)
249c2c66affSColin Finck {
250c2c66affSColin Finck ret = RegGetValueW(HKEY_CLASSES_ROOT, pszFileType, NULL, RRF_RT_REG_SZ, NULL, docName, &size);
251c2c66affSColin Finck if (ret == ERROR_SUCCESS)
252c2c66affSColin Finck {
253c2c66affSColin Finck hr = this->ReturnString(flags, pszOut, pcchOut, docName, strlenW(docName) + 1);
254c2c66affSColin Finck }
255c2c66affSColin Finck else
256c2c66affSColin Finck {
257c2c66affSColin Finck hr = HRESULT_FROM_WIN32(ret);
258c2c66affSColin Finck }
259c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, docName);
260c2c66affSColin Finck }
261c2c66affSColin Finck else
262c2c66affSColin Finck {
263c2c66affSColin Finck hr = E_OUTOFMEMORY;
264c2c66affSColin Finck }
265c2c66affSColin Finck }
266c2c66affSColin Finck else
267c2c66affSColin Finck {
268c2c66affSColin Finck hr = HRESULT_FROM_WIN32(ret);
269c2c66affSColin Finck }
270c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, pszFileType);
271c2c66affSColin Finck return hr;
272c2c66affSColin Finck }
273c2c66affSColin Finck case ASSOCSTR_FRIENDLYAPPNAME:
274c2c66affSColin Finck {
275c2c66affSColin Finck PVOID verinfoW = NULL;
276c2c66affSColin Finck DWORD size, retval = 0;
277c2c66affSColin Finck UINT flen;
278c2c66affSColin Finck WCHAR *bufW;
279c2c66affSColin Finck WCHAR fileDescW[41];
280c2c66affSColin Finck
281c2c66affSColin Finck hr = this->GetExecutable(pszExtra, path, MAX_PATH, &len);
282c2c66affSColin Finck if (FAILED(hr))
283c2c66affSColin Finck {
284c2c66affSColin Finck return hr;
285c2c66affSColin Finck }
286c2c66affSColin Finck retval = GetFileVersionInfoSizeW(path, &size);
287c2c66affSColin Finck if (!retval)
288c2c66affSColin Finck {
289c2c66affSColin Finck goto get_friendly_name_fail;
290c2c66affSColin Finck }
291c2c66affSColin Finck verinfoW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, retval);
292c2c66affSColin Finck if (!verinfoW)
293c2c66affSColin Finck {
294c2c66affSColin Finck return E_OUTOFMEMORY;
295c2c66affSColin Finck }
296c2c66affSColin Finck if (!GetFileVersionInfoW(path, 0, retval, verinfoW))
297c2c66affSColin Finck {
298c2c66affSColin Finck goto get_friendly_name_fail;
299c2c66affSColin Finck }
30083be315aSHermès Bélusca-Maïto if (VerQueryValueW(verinfoW, L"\\VarFileInfo\\Translation", (LPVOID *)&bufW, &flen))
301c2c66affSColin Finck {
302c2c66affSColin Finck UINT i;
303c2c66affSColin Finck DWORD *langCodeDesc = (DWORD *)bufW;
304c2c66affSColin Finck for (i = 0; i < flen / sizeof(DWORD); i++)
305c2c66affSColin Finck {
30683be315aSHermès Bélusca-Maïto sprintfW(fileDescW, L"\\StringFileInfo\\%04x%04x\\FileDescription",
30783be315aSHermès Bélusca-Maïto LOWORD(langCodeDesc[i]), HIWORD(langCodeDesc[i]));
308c2c66affSColin Finck if (VerQueryValueW(verinfoW, fileDescW, (LPVOID *)&bufW, &flen))
309c2c66affSColin Finck {
310c2c66affSColin Finck /* Does strlenW(bufW) == 0 mean we use the filename? */
311c2c66affSColin Finck len = strlenW(bufW) + 1;
312c2c66affSColin Finck TRACE("found FileDescription: %s\n", debugstr_w(bufW));
313c2c66affSColin Finck hr = this->ReturnString(flags, pszOut, pcchOut, bufW, len);
314c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, verinfoW);
315c2c66affSColin Finck return hr;
316c2c66affSColin Finck }
317c2c66affSColin Finck }
318c2c66affSColin Finck }
319c2c66affSColin Finck get_friendly_name_fail:
320c2c66affSColin Finck PathRemoveExtensionW(path);
321c2c66affSColin Finck PathStripPathW(path);
322c2c66affSColin Finck TRACE("using filename: %s\n", debugstr_w(path));
323c2c66affSColin Finck hr = this->ReturnString(flags, pszOut, pcchOut, path, strlenW(path) + 1);
324c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, verinfoW);
325c2c66affSColin Finck return hr;
326c2c66affSColin Finck }
327c2c66affSColin Finck case ASSOCSTR_CONTENTTYPE:
328c2c66affSColin Finck {
329c2c66affSColin Finck DWORD size = 0;
33083be315aSHermès Bélusca-Maïto DWORD ret = RegGetValueW(this->hkeySource, NULL, L"Content Type", RRF_RT_REG_SZ, NULL, NULL, &size);
331c2c66affSColin Finck if (ret != ERROR_SUCCESS)
332c2c66affSColin Finck {
333c2c66affSColin Finck return HRESULT_FROM_WIN32(ret);
334c2c66affSColin Finck }
335c2c66affSColin Finck WCHAR *contentType = static_cast<WCHAR *>(HeapAlloc(GetProcessHeap(), 0, size));
336c2c66affSColin Finck if (contentType != NULL)
337c2c66affSColin Finck {
33883be315aSHermès Bélusca-Maïto ret = RegGetValueW(this->hkeySource, NULL, L"Content Type", RRF_RT_REG_SZ, NULL, contentType, &size);
339c2c66affSColin Finck if (ret == ERROR_SUCCESS)
340c2c66affSColin Finck {
341c2c66affSColin Finck hr = this->ReturnString(flags, pszOut, pcchOut, contentType, strlenW(contentType) + 1);
342c2c66affSColin Finck }
343c2c66affSColin Finck else
344c2c66affSColin Finck {
345c2c66affSColin Finck hr = HRESULT_FROM_WIN32(ret);
346c2c66affSColin Finck }
347c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, contentType);
348c2c66affSColin Finck }
349c2c66affSColin Finck else
350c2c66affSColin Finck {
351c2c66affSColin Finck hr = E_OUTOFMEMORY;
352c2c66affSColin Finck }
353c2c66affSColin Finck return hr;
354c2c66affSColin Finck }
355c2c66affSColin Finck case ASSOCSTR_DEFAULTICON:
356c2c66affSColin Finck {
357c2c66affSColin Finck DWORD ret;
358c2c66affSColin Finck DWORD size = 0;
35983be315aSHermès Bélusca-Maïto ret = RegGetValueW(this->hkeyProgID, L"DefaultIcon", NULL, RRF_RT_REG_SZ, NULL, NULL, &size);
360c2c66affSColin Finck if (ret == ERROR_SUCCESS)
361c2c66affSColin Finck {
362c2c66affSColin Finck WCHAR *icon = static_cast<WCHAR *>(HeapAlloc(GetProcessHeap(), 0, size));
363c2c66affSColin Finck if (icon)
364c2c66affSColin Finck {
36583be315aSHermès Bélusca-Maïto ret = RegGetValueW(this->hkeyProgID, L"DefaultIcon", NULL, RRF_RT_REG_SZ, NULL, icon, &size);
366c2c66affSColin Finck if (ret == ERROR_SUCCESS)
367c2c66affSColin Finck {
368c2c66affSColin Finck hr = this->ReturnString(flags, pszOut, pcchOut, icon, strlenW(icon) + 1);
369c2c66affSColin Finck }
370c2c66affSColin Finck else
371c2c66affSColin Finck {
372c2c66affSColin Finck hr = HRESULT_FROM_WIN32(ret);
373c2c66affSColin Finck }
374c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, icon);
375c2c66affSColin Finck }
376c2c66affSColin Finck else
377c2c66affSColin Finck {
378c2c66affSColin Finck hr = HRESULT_FROM_WIN32(ret);
379c2c66affSColin Finck }
380c2c66affSColin Finck }
381c2c66affSColin Finck else
382c2c66affSColin Finck {
383c2c66affSColin Finck hr = HRESULT_FROM_WIN32(ret);
384c2c66affSColin Finck }
385c2c66affSColin Finck return hr;
386c2c66affSColin Finck }
387c2c66affSColin Finck case ASSOCSTR_SHELLEXTENSION:
388c2c66affSColin Finck {
38983be315aSHermès Bélusca-Maïto WCHAR keypath[ARRAY_SIZE(L"ShellEx\\") + 39], guid[39];
390c2c66affSColin Finck CLSID clsid;
391c2c66affSColin Finck HKEY hkey;
392c2c66affSColin Finck
393c2c66affSColin Finck hr = CLSIDFromString(pszExtra, &clsid);
394c2c66affSColin Finck if (FAILED(hr))
395c2c66affSColin Finck {
396c2c66affSColin Finck return hr;
397c2c66affSColin Finck }
39883be315aSHermès Bélusca-Maïto strcpyW(keypath, L"ShellEx\\");
399c2c66affSColin Finck strcatW(keypath, pszExtra);
400c2c66affSColin Finck LONG ret = RegOpenKeyExW(this->hkeySource, keypath, 0, KEY_READ, &hkey);
401c2c66affSColin Finck if (ret)
402c2c66affSColin Finck {
403c2c66affSColin Finck return HRESULT_FROM_WIN32(ret);
404c2c66affSColin Finck }
405c2c66affSColin Finck DWORD size = sizeof(guid);
406c2c66affSColin Finck ret = RegGetValueW(hkey, NULL, NULL, RRF_RT_REG_SZ, NULL, guid, &size);
407c2c66affSColin Finck RegCloseKey(hkey);
408c2c66affSColin Finck if (ret)
409c2c66affSColin Finck {
410c2c66affSColin Finck return HRESULT_FROM_WIN32(ret);
411c2c66affSColin Finck }
412c2c66affSColin Finck return this->ReturnString(flags, pszOut, pcchOut, guid, size / sizeof(WCHAR));
413c2c66affSColin Finck }
414c2c66affSColin Finck
415c2c66affSColin Finck default:
416c2c66affSColin Finck {
417c2c66affSColin Finck FIXME("assocstr %d unimplemented!\n", str);
418c2c66affSColin Finck return E_NOTIMPL;
419c2c66affSColin Finck }
420c2c66affSColin Finck }
421c2c66affSColin Finck }
422c2c66affSColin Finck
423c2c66affSColin Finck /**************************************************************************
424c2c66affSColin Finck * IQueryAssociations_GetKey
425c2c66affSColin Finck *
426c2c66affSColin Finck * Get a file association key from the registry.
427c2c66affSColin Finck *
428c2c66affSColin Finck * PARAMS
429c2c66affSColin Finck * cfFlags [I] ASSOCF_ flags from "shlwapi.h"
430c2c66affSColin Finck * assockey [I] Type of key to get (ASSOCKEY enum from "shlwapi.h")
431c2c66affSColin Finck * pszExtra [I] Extra information about the key location
432c2c66affSColin Finck * phkeyOut [O] Destination for the association key
433c2c66affSColin Finck *
434c2c66affSColin Finck * RETURNS
435c2c66affSColin Finck * Success: S_OK. phkeyOut contains a handle to the key.
436c2c66affSColin Finck * Failure: An HRESULT error code indicating the error.
437c2c66affSColin Finck */
GetKey(ASSOCF cfFlags,ASSOCKEY assockey,LPCWSTR pszExtra,HKEY * phkeyOut)438c2c66affSColin Finck HRESULT STDMETHODCALLTYPE CQueryAssociations::GetKey(
439c2c66affSColin Finck ASSOCF cfFlags,
440c2c66affSColin Finck ASSOCKEY assockey,
441c2c66affSColin Finck LPCWSTR pszExtra,
442c2c66affSColin Finck HKEY *phkeyOut)
443c2c66affSColin Finck {
444c2c66affSColin Finck FIXME("(%p,0x%8x,0x%8x,%s,%p)-stub!\n", this, cfFlags, assockey,
445c2c66affSColin Finck debugstr_w(pszExtra), phkeyOut);
446c2c66affSColin Finck return E_NOTIMPL;
447c2c66affSColin Finck }
448c2c66affSColin Finck
449c2c66affSColin Finck /**************************************************************************
450c2c66affSColin Finck * IQueryAssociations_GetData
451c2c66affSColin Finck *
452c2c66affSColin Finck * Get the data for a file association key from the registry.
453c2c66affSColin Finck *
454c2c66affSColin Finck * PARAMS
455c2c66affSColin Finck * cfFlags [I] ASSOCF_ flags from "shlwapi.h"
456c2c66affSColin Finck * assocdata [I] Type of data to get (ASSOCDATA enum from "shlwapi.h")
457c2c66affSColin Finck * pszExtra [I] Extra information about the data location
458c2c66affSColin Finck * pvOut [O] Destination for the association key
459c2c66affSColin Finck * pcbOut [I/O] Size of pvOut
460c2c66affSColin Finck *
461c2c66affSColin Finck * RETURNS
462c2c66affSColin Finck * Success: S_OK. pszOut contains the data, pcbOut contains its length.
463c2c66affSColin Finck * Failure: An HRESULT error code indicating the error.
464c2c66affSColin Finck */
GetData(ASSOCF cfFlags,ASSOCDATA assocdata,LPCWSTR pszExtra,LPVOID pvOut,DWORD * pcbOut)465c2c66affSColin Finck HRESULT STDMETHODCALLTYPE CQueryAssociations::GetData(ASSOCF cfFlags, ASSOCDATA assocdata, LPCWSTR pszExtra, LPVOID pvOut, DWORD *pcbOut)
466c2c66affSColin Finck {
467c2c66affSColin Finck TRACE("(%p,0x%8x,0x%8x,%s,%p,%p)\n", this, cfFlags, assocdata,
468c2c66affSColin Finck debugstr_w(pszExtra), pvOut, pcbOut);
469c2c66affSColin Finck
470c2c66affSColin Finck if(cfFlags)
471c2c66affSColin Finck {
472c2c66affSColin Finck FIXME("Unsupported flags: %x\n", cfFlags);
473c2c66affSColin Finck }
474c2c66affSColin Finck
475c2c66affSColin Finck switch(assocdata)
476c2c66affSColin Finck {
477c2c66affSColin Finck case ASSOCDATA_EDITFLAGS:
478c2c66affSColin Finck {
479c2c66affSColin Finck if(!this->hkeyProgID)
480c2c66affSColin Finck {
481c2c66affSColin Finck return HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION);
482c2c66affSColin Finck }
483c2c66affSColin Finck
484c2c66affSColin Finck void *data;
485c2c66affSColin Finck DWORD size;
48683be315aSHermès Bélusca-Maïto HRESULT hres = this->GetValue(this->hkeyProgID, L"EditFlags", &data, &size);
487c2c66affSColin Finck if(FAILED(hres))
488c2c66affSColin Finck {
489c2c66affSColin Finck return hres;
490c2c66affSColin Finck }
491c2c66affSColin Finck
492c2c66affSColin Finck if (!pcbOut)
493c2c66affSColin Finck {
494c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, data);
495c2c66affSColin Finck return hres;
496c2c66affSColin Finck }
497c2c66affSColin Finck
498c2c66affSColin Finck hres = this->ReturnData(pvOut, pcbOut, data, size);
499c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, data);
500c2c66affSColin Finck return hres;
501c2c66affSColin Finck }
502c2c66affSColin Finck default:
503c2c66affSColin Finck {
504c2c66affSColin Finck FIXME("Unsupported ASSOCDATA value: %d\n", assocdata);
505c2c66affSColin Finck return E_NOTIMPL;
506c2c66affSColin Finck }
507c2c66affSColin Finck }
508c2c66affSColin Finck }
509c2c66affSColin Finck
510c2c66affSColin Finck /**************************************************************************
511c2c66affSColin Finck * IQueryAssociations_GetEnum
512c2c66affSColin Finck *
513c2c66affSColin Finck * Not yet implemented in native Win32.
514c2c66affSColin Finck *
515c2c66affSColin Finck * PARAMS
516c2c66affSColin Finck * cfFlags [I] ASSOCF_ flags from "shlwapi.h"
517c2c66affSColin Finck * assocenum [I] Type of enum to get (ASSOCENUM enum from "shlwapi.h")
518c2c66affSColin Finck * pszExtra [I] Extra information about the enum location
519c2c66affSColin Finck * riid [I] REFIID to look for
520c2c66affSColin Finck * ppvOut [O] Destination for the interface.
521c2c66affSColin Finck *
522c2c66affSColin Finck * RETURNS
523c2c66affSColin Finck * Success: S_OK.
524c2c66affSColin Finck * Failure: An HRESULT error code indicating the error.
525c2c66affSColin Finck *
526c2c66affSColin Finck * NOTES
527c2c66affSColin Finck * Presumably this function returns an enumerator object.
528c2c66affSColin Finck */
GetEnum(ASSOCF cfFlags,ASSOCENUM assocenum,LPCWSTR pszExtra,REFIID riid,LPVOID * ppvOut)529c2c66affSColin Finck HRESULT STDMETHODCALLTYPE CQueryAssociations::GetEnum(
530c2c66affSColin Finck ASSOCF cfFlags,
531c2c66affSColin Finck ASSOCENUM assocenum,
532c2c66affSColin Finck LPCWSTR pszExtra,
533c2c66affSColin Finck REFIID riid,
534c2c66affSColin Finck LPVOID *ppvOut)
535c2c66affSColin Finck {
536c2c66affSColin Finck return E_NOTIMPL;
537c2c66affSColin Finck }
538c2c66affSColin Finck
GetValue(HKEY hkey,const WCHAR * name,void ** data,DWORD * data_size)539c2c66affSColin Finck HRESULT CQueryAssociations::GetValue(HKEY hkey, const WCHAR *name, void **data, DWORD *data_size)
540c2c66affSColin Finck {
541c2c66affSColin Finck DWORD size;
542c2c66affSColin Finck LONG ret;
543c2c66affSColin Finck
544c2c66affSColin Finck ret = RegQueryValueExW(hkey, name, 0, NULL, NULL, &size);
545c2c66affSColin Finck if (ret != ERROR_SUCCESS)
546c2c66affSColin Finck return HRESULT_FROM_WIN32(ret);
5476ac15363SKatayama Hirofumi MZ
548c2c66affSColin Finck if (!size)
549c2c66affSColin Finck return E_FAIL;
5506ac15363SKatayama Hirofumi MZ
551c2c66affSColin Finck *data = HeapAlloc(GetProcessHeap(), 0, size);
552c2c66affSColin Finck if (!*data)
553c2c66affSColin Finck return E_OUTOFMEMORY;
5546ac15363SKatayama Hirofumi MZ
555c2c66affSColin Finck ret = RegQueryValueExW(hkey, name, 0, NULL, (LPBYTE)*data, &size);
556c2c66affSColin Finck if (ret != ERROR_SUCCESS)
557c2c66affSColin Finck {
558c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, *data);
559c2c66affSColin Finck return HRESULT_FROM_WIN32(ret);
560c2c66affSColin Finck }
5616ac15363SKatayama Hirofumi MZ
562c2c66affSColin Finck if (data_size)
563c2c66affSColin Finck *data_size = size;
5646ac15363SKatayama Hirofumi MZ
565c2c66affSColin Finck return S_OK;
566c2c66affSColin Finck }
567c2c66affSColin Finck
GetCommand(const WCHAR * extra,WCHAR ** command)568c2c66affSColin Finck HRESULT CQueryAssociations::GetCommand(const WCHAR *extra, WCHAR **command)
569c2c66affSColin Finck {
570c2c66affSColin Finck HKEY hkeyCommand;
571c2c66affSColin Finck HKEY hkeyShell;
572c2c66affSColin Finck HKEY hkeyVerb;
573c2c66affSColin Finck HRESULT hr;
574c2c66affSColin Finck LONG ret;
575c2c66affSColin Finck WCHAR *extra_from_reg = NULL;
576c2c66affSColin Finck WCHAR *filetype;
577c2c66affSColin Finck
578c2c66affSColin Finck /* When looking for file extension it's possible to have a default value
579c2c66affSColin Finck that points to another key that contains 'shell/<verb>/command' subtree. */
580c2c66affSColin Finck hr = this->GetValue(this->hkeySource, NULL, (void**)&filetype, NULL);
581c2c66affSColin Finck if (hr == S_OK)
582c2c66affSColin Finck {
583c2c66affSColin Finck HKEY hkeyFile;
584c2c66affSColin Finck
585c2c66affSColin Finck ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, filetype, 0, KEY_READ, &hkeyFile);
586c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, filetype);
587c2c66affSColin Finck
588c2c66affSColin Finck if (ret == ERROR_SUCCESS)
589c2c66affSColin Finck {
59083be315aSHermès Bélusca-Maïto ret = RegOpenKeyExW(hkeyFile, L"shell", 0, KEY_READ, &hkeyShell);
591c2c66affSColin Finck RegCloseKey(hkeyFile);
592c2c66affSColin Finck }
593c2c66affSColin Finck else
594c2c66affSColin Finck {
59583be315aSHermès Bélusca-Maïto ret = RegOpenKeyExW(this->hkeySource, L"shell", 0, KEY_READ, &hkeyShell);
596c2c66affSColin Finck }
597c2c66affSColin Finck }
598c2c66affSColin Finck else
599c2c66affSColin Finck {
60083be315aSHermès Bélusca-Maïto ret = RegOpenKeyExW(this->hkeySource, L"shell", 0, KEY_READ, &hkeyShell);
601c2c66affSColin Finck }
602c2c66affSColin Finck
603c2c66affSColin Finck if (ret)
604c2c66affSColin Finck {
605c2c66affSColin Finck return HRESULT_FROM_WIN32(ret);
606c2c66affSColin Finck }
607c2c66affSColin Finck
608c2c66affSColin Finck if (!extra)
609c2c66affSColin Finck {
610c2c66affSColin Finck /* check for default verb */
611c2c66affSColin Finck hr = this->GetValue(hkeyShell, NULL, (void**)&extra_from_reg, NULL);
612c2c66affSColin Finck if (FAILED(hr))
6136ac15363SKatayama Hirofumi MZ hr = this->GetValue(hkeyShell, L"open", (void**)&extra_from_reg, NULL);
6146ac15363SKatayama Hirofumi MZ if (FAILED(hr))
615c2c66affSColin Finck {
616c2c66affSColin Finck /* no default verb, try first subkey */
617c2c66affSColin Finck DWORD max_subkey_len;
618c2c66affSColin Finck
619c2c66affSColin Finck ret = RegQueryInfoKeyW(hkeyShell, NULL, NULL, NULL, NULL, &max_subkey_len, NULL, NULL, NULL, NULL, NULL, NULL);
620c2c66affSColin Finck if (ret)
621c2c66affSColin Finck {
622c2c66affSColin Finck RegCloseKey(hkeyShell);
623c2c66affSColin Finck return HRESULT_FROM_WIN32(ret);
624c2c66affSColin Finck }
625c2c66affSColin Finck
626c2c66affSColin Finck max_subkey_len++;
627c2c66affSColin Finck extra_from_reg = static_cast<WCHAR*>(HeapAlloc(GetProcessHeap(), 0, max_subkey_len * sizeof(WCHAR)));
628c2c66affSColin Finck if (!extra_from_reg)
629c2c66affSColin Finck {
630c2c66affSColin Finck RegCloseKey(hkeyShell);
631c2c66affSColin Finck return E_OUTOFMEMORY;
632c2c66affSColin Finck }
633c2c66affSColin Finck
634c2c66affSColin Finck ret = RegEnumKeyExW(hkeyShell, 0, extra_from_reg, &max_subkey_len, NULL, NULL, NULL, NULL);
635c2c66affSColin Finck if (ret)
636c2c66affSColin Finck {
637c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, extra_from_reg);
638c2c66affSColin Finck RegCloseKey(hkeyShell);
639c2c66affSColin Finck return HRESULT_FROM_WIN32(ret);
640c2c66affSColin Finck }
641c2c66affSColin Finck }
642c2c66affSColin Finck extra = extra_from_reg;
643c2c66affSColin Finck }
644c2c66affSColin Finck
645c2c66affSColin Finck /* open verb subkey */
646c2c66affSColin Finck ret = RegOpenKeyExW(hkeyShell, extra, 0, KEY_READ, &hkeyVerb);
647c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, extra_from_reg);
648c2c66affSColin Finck RegCloseKey(hkeyShell);
649c2c66affSColin Finck if (ret)
650c2c66affSColin Finck {
651c2c66affSColin Finck return HRESULT_FROM_WIN32(ret);
652c2c66affSColin Finck }
653c2c66affSColin Finck /* open command subkey */
65483be315aSHermès Bélusca-Maïto ret = RegOpenKeyExW(hkeyVerb, L"command", 0, KEY_READ, &hkeyCommand);
655c2c66affSColin Finck RegCloseKey(hkeyVerb);
656c2c66affSColin Finck if (ret)
657c2c66affSColin Finck {
658c2c66affSColin Finck return HRESULT_FROM_WIN32(ret);
659c2c66affSColin Finck }
660c2c66affSColin Finck hr = this->GetValue(hkeyCommand, NULL, (void**)command, NULL);
661c2c66affSColin Finck RegCloseKey(hkeyCommand);
662c2c66affSColin Finck return hr;
663c2c66affSColin Finck }
664c2c66affSColin Finck
GetExecutable(LPCWSTR pszExtra,LPWSTR path,DWORD pathlen,DWORD * len)665c2c66affSColin Finck HRESULT CQueryAssociations::GetExecutable(LPCWSTR pszExtra, LPWSTR path, DWORD pathlen, DWORD *len)
666c2c66affSColin Finck {
667c2c66affSColin Finck WCHAR *pszCommand;
668c2c66affSColin Finck WCHAR *pszStart;
669c2c66affSColin Finck WCHAR *pszEnd;
670c2c66affSColin Finck
671c2c66affSColin Finck HRESULT hr = this->GetCommand(pszExtra, &pszCommand);
6726ac15363SKatayama Hirofumi MZ if (FAILED_UNEXPECTEDLY(hr))
673c2c66affSColin Finck {
674c2c66affSColin Finck return hr;
675c2c66affSColin Finck }
676c2c66affSColin Finck
677c2c66affSColin Finck DWORD expLen = ExpandEnvironmentStringsW(pszCommand, NULL, 0);
678c2c66affSColin Finck if (expLen > 0)
679c2c66affSColin Finck {
680c2c66affSColin Finck expLen++;
681c2c66affSColin Finck WCHAR *buf = static_cast<WCHAR *>(HeapAlloc(GetProcessHeap(), 0, expLen * sizeof(WCHAR)));
682c2c66affSColin Finck ExpandEnvironmentStringsW(pszCommand, buf, expLen);
683c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, pszCommand);
684c2c66affSColin Finck pszCommand = buf;
685c2c66affSColin Finck }
686c2c66affSColin Finck
687c2c66affSColin Finck /* cleanup pszCommand */
688c2c66affSColin Finck if (pszCommand[0] == '"')
689c2c66affSColin Finck {
690c2c66affSColin Finck pszStart = pszCommand + 1;
691c2c66affSColin Finck pszEnd = strchrW(pszStart, '"');
692c2c66affSColin Finck if (pszEnd)
693c2c66affSColin Finck {
694c2c66affSColin Finck *pszEnd = 0;
695c2c66affSColin Finck }
696c2c66affSColin Finck *len = SearchPathW(NULL, pszStart, NULL, pathlen, path, NULL);
697c2c66affSColin Finck }
698c2c66affSColin Finck else
699c2c66affSColin Finck {
700c2c66affSColin Finck pszStart = pszCommand;
701c2c66affSColin Finck for (pszEnd = pszStart; (pszEnd = strchrW(pszEnd, ' ')); pszEnd++)
702c2c66affSColin Finck {
703c2c66affSColin Finck WCHAR c = *pszEnd;
704c2c66affSColin Finck *pszEnd = 0;
705c2c66affSColin Finck if ((*len = SearchPathW(NULL, pszStart, NULL, pathlen, path, NULL)))
706c2c66affSColin Finck {
707c2c66affSColin Finck break;
708c2c66affSColin Finck }
709c2c66affSColin Finck *pszEnd = c;
710c2c66affSColin Finck }
711c2c66affSColin Finck if (!pszEnd)
712c2c66affSColin Finck {
713c2c66affSColin Finck *len = SearchPathW(NULL, pszStart, NULL, pathlen, path, NULL);
714c2c66affSColin Finck }
715c2c66affSColin Finck }
716c2c66affSColin Finck
717c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, pszCommand);
718c2c66affSColin Finck if (!*len)
719c2c66affSColin Finck {
720c2c66affSColin Finck return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
721c2c66affSColin Finck }
722c2c66affSColin Finck return S_OK;
723c2c66affSColin Finck }
724c2c66affSColin Finck
ReturnData(void * out,DWORD * outlen,const void * data,DWORD datalen)725c2c66affSColin Finck HRESULT CQueryAssociations::ReturnData(void *out, DWORD *outlen, const void *data, DWORD datalen)
726c2c66affSColin Finck {
727c2c66affSColin Finck if (out)
728c2c66affSColin Finck {
729c2c66affSColin Finck if (*outlen < datalen)
730c2c66affSColin Finck {
731c2c66affSColin Finck *outlen = datalen;
732c2c66affSColin Finck return E_POINTER;
733c2c66affSColin Finck }
734c2c66affSColin Finck *outlen = datalen;
735c2c66affSColin Finck memcpy(out, data, datalen);
736c2c66affSColin Finck return S_OK;
737c2c66affSColin Finck }
738c2c66affSColin Finck else
739c2c66affSColin Finck {
740c2c66affSColin Finck *outlen = datalen;
741c2c66affSColin Finck return S_FALSE;
742c2c66affSColin Finck }
743c2c66affSColin Finck }
744c2c66affSColin Finck
ReturnString(ASSOCF flags,LPWSTR out,DWORD * outlen,LPCWSTR data,DWORD datalen)745c2c66affSColin Finck HRESULT CQueryAssociations::ReturnString(ASSOCF flags, LPWSTR out, DWORD *outlen, LPCWSTR data, DWORD datalen)
746c2c66affSColin Finck {
747c2c66affSColin Finck HRESULT hr = S_OK;
748c2c66affSColin Finck DWORD len;
749c2c66affSColin Finck
750c2c66affSColin Finck TRACE("flags=0x%08x, data=%s\n", flags, debugstr_w(data));
751c2c66affSColin Finck
752c2c66affSColin Finck if (!out)
753c2c66affSColin Finck {
754c2c66affSColin Finck *outlen = datalen;
755c2c66affSColin Finck return S_FALSE;
756c2c66affSColin Finck }
757c2c66affSColin Finck
758c2c66affSColin Finck if (*outlen < datalen)
759c2c66affSColin Finck {
760c2c66affSColin Finck if (flags & ASSOCF_NOTRUNCATE)
761c2c66affSColin Finck {
762c2c66affSColin Finck len = 0;
763c2c66affSColin Finck if (*outlen > 0) out[0] = 0;
764c2c66affSColin Finck hr = E_POINTER;
765c2c66affSColin Finck }
766c2c66affSColin Finck else
767c2c66affSColin Finck {
768c2c66affSColin Finck len = min(*outlen, datalen);
769c2c66affSColin Finck hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
770c2c66affSColin Finck }
771c2c66affSColin Finck *outlen = datalen;
772c2c66affSColin Finck }
773c2c66affSColin Finck else
774c2c66affSColin Finck {
7756ac15363SKatayama Hirofumi MZ *outlen = len = datalen;
776c2c66affSColin Finck }
777c2c66affSColin Finck
778c2c66affSColin Finck if (len)
779c2c66affSColin Finck {
780c2c66affSColin Finck memcpy(out, data, len*sizeof(WCHAR));
781c2c66affSColin Finck }
782c2c66affSColin Finck
783c2c66affSColin Finck return hr;
784c2c66affSColin Finck }
785