- Implement ProtocolResetComplete
[reactos.git] / dll / win32 / shell32 / extracticon.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Registry namespace extension
4 * FILE: dll/win32/shell32/extracticon.c
5 * PURPOSE: Icon extraction
6 *
7 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
8 */
9
10 #define COBJMACROS
11 #define CONST_VTABLE
12 #include <shlobj.h>
13 #include <debug.h>
14
15 WINE_DEFAULT_DEBUG_CHANNEL(shell);
16
17 struct IconLocation
18 {
19 LPWSTR file;
20 UINT index;
21 };
22
23 struct IconExtraction
24 {
25 LONG ref;
26 IDefaultExtractIconInit defaultExtractIconInitImpl;
27 IExtractIconW extractIconWImpl;
28 IExtractIconA extractIconAImpl;
29 IPersistFile persistFileImpl;
30
31 UINT flags;
32 struct IconLocation defaultIcon;
33 struct IconLocation normalIcon;
34 struct IconLocation openIcon;
35 struct IconLocation shortcutIcon;
36 };
37
38 static VOID
39 DuplicateString(
40 LPCWSTR Source,
41 LPWSTR *Destination)
42 {
43 SIZE_T cb;
44
45 if (*Destination)
46 CoTaskMemFree(*Destination);
47
48 cb = (wcslen(Source) + 1) * sizeof(WCHAR);
49 *Destination = CoTaskMemAlloc(cb);
50 if (!*Destination)
51 return;
52 CopyMemory(*Destination, Source, cb);
53 }
54
55 static HRESULT STDMETHODCALLTYPE
56 IconExtraction_DefaultExtractIconInit_QueryInterface(
57 IDefaultExtractIconInit *This,
58 REFIID riid,
59 void **ppvObject)
60 {
61 struct IconExtraction *s = CONTAINING_RECORD(This, struct IconExtraction, defaultExtractIconInitImpl);
62
63 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
64
65 if (!ppvObject)
66 return E_POINTER;
67
68 if (IsEqualIID(riid, &IID_IUnknown))
69 *ppvObject = &s->defaultExtractIconInitImpl;
70 else if (IsEqualIID(riid, &IID_IDefaultExtractIconInit))
71 *ppvObject = &s->defaultExtractIconInitImpl;
72 else if (IsEqualIID(riid, &IID_IExtractIconW))
73 *ppvObject = &s->extractIconWImpl;
74 else if (IsEqualIID(riid, &IID_IExtractIconA))
75 *ppvObject = &s->extractIconAImpl;
76 else if (IsEqualIID(riid, &IID_IPersist))
77 *ppvObject = &s->persistFileImpl;
78 else if (IsEqualIID(riid, &IID_IPersistFile))
79 *ppvObject = &s->persistFileImpl;
80 else
81 {
82 *ppvObject = NULL;
83 return E_NOINTERFACE;
84 }
85
86 IUnknown_AddRef(This);
87 return S_OK;
88 }
89
90 static ULONG STDMETHODCALLTYPE
91 IconExtraction_DefaultExtractIconInit_AddRef(
92 IDefaultExtractIconInit *This)
93 {
94 struct IconExtraction *s = CONTAINING_RECORD(This, struct IconExtraction, defaultExtractIconInitImpl);
95 ULONG refCount = InterlockedIncrement(&s->ref);
96 TRACE("(%p)\n", This);
97 return refCount;
98 }
99
100 static ULONG STDMETHODCALLTYPE
101 IconExtraction_DefaultExtractIconInit_Release(
102 IDefaultExtractIconInit *This)
103 {
104 struct IconExtraction *s = CONTAINING_RECORD(This, struct IconExtraction, defaultExtractIconInitImpl);
105 ULONG refCount;
106
107 TRACE("(%p)\n", This);
108
109 refCount = InterlockedDecrement(&s->ref);
110 if (refCount == 0)
111 {
112 if (s->defaultIcon.file) CoTaskMemFree(s->defaultIcon.file);
113 if (s->normalIcon.file) CoTaskMemFree(s->normalIcon.file);
114 if (s->openIcon.file) CoTaskMemFree(s->openIcon.file);
115 if (s->shortcutIcon.file) CoTaskMemFree(s->shortcutIcon.file);
116 CoTaskMemFree(s);
117 }
118
119 return refCount;
120 }
121
122 static HRESULT STDMETHODCALLTYPE
123 IconExtraction_DefaultExtractIconInit_SetDefaultIcon(
124 IDefaultExtractIconInit *This,
125 LPCWSTR pszFile,
126 int iIcon)
127 {
128 struct IconExtraction *s = CONTAINING_RECORD(This, struct IconExtraction, defaultExtractIconInitImpl);
129
130 TRACE("(%p, %s, %d)\n", This, debugstr_w(pszFile), iIcon);
131
132 DuplicateString(pszFile, &s->defaultIcon.file);
133 if (!s->defaultIcon.file)
134 return E_OUTOFMEMORY;
135 s->defaultIcon.index = iIcon;
136 return S_OK;
137 }
138
139 static HRESULT STDMETHODCALLTYPE
140 IconExtraction_DefaultExtractIconInit_SetFlags(
141 IDefaultExtractIconInit *This,
142 UINT uFlags)
143 {
144 struct IconExtraction *s = CONTAINING_RECORD(This, struct IconExtraction, defaultExtractIconInitImpl);
145
146 TRACE("(%p, 0x%x)\n", This, uFlags);
147
148 s->flags = uFlags;
149 return S_OK;
150 }
151
152 static HRESULT STDMETHODCALLTYPE
153 IconExtraction_DefaultExtractIconInit_SetKey(
154 IDefaultExtractIconInit *This,
155 HKEY hkey)
156 {
157 FIXME("(%p, %p)\n", This, hkey);
158 UNIMPLEMENTED;
159 return E_NOTIMPL;
160 }
161
162 static HRESULT STDMETHODCALLTYPE
163 IconExtraction_DefaultExtractIconInit_SetNormalIcon(
164 IDefaultExtractIconInit *This,
165 LPCWSTR pszFile,
166 int iIcon)
167 {
168 struct IconExtraction *s = CONTAINING_RECORD(This, struct IconExtraction, defaultExtractIconInitImpl);
169
170 TRACE("(%p, %s, %d)\n", This, debugstr_w(pszFile), iIcon);
171
172 DuplicateString(pszFile, &s->normalIcon.file);
173 if (!s->normalIcon.file)
174 return E_OUTOFMEMORY;
175 s->normalIcon.index = iIcon;
176 return S_OK;
177 }
178
179 static HRESULT STDMETHODCALLTYPE
180 IconExtraction_DefaultExtractIconInit_SetOpenIcon(
181 IDefaultExtractIconInit *This,
182 LPCWSTR pszFile,
183 int iIcon)
184 {
185 struct IconExtraction *s = CONTAINING_RECORD(This, struct IconExtraction, defaultExtractIconInitImpl);
186
187 TRACE("(%p, %s, %d)\n", This, debugstr_w(pszFile), iIcon);
188
189 DuplicateString(pszFile, &s->openIcon.file);
190 if (!s->openIcon.file)
191 return E_OUTOFMEMORY;
192 s->openIcon.index = iIcon;
193 return S_OK;
194 }
195
196 static HRESULT STDMETHODCALLTYPE
197 IconExtraction_DefaultExtractIconInit_SetShortcutIcon(
198 IDefaultExtractIconInit *This,
199 LPCWSTR pszFile,
200 int iIcon)
201 {
202 struct IconExtraction *s = CONTAINING_RECORD(This, struct IconExtraction, defaultExtractIconInitImpl);
203
204 TRACE("(%p, %s, %d)\n", This, debugstr_w(pszFile), iIcon);
205
206 DuplicateString(pszFile, &s->shortcutIcon.file);
207 if (!s->shortcutIcon.file)
208 return E_OUTOFMEMORY;
209 s->shortcutIcon.index = iIcon;
210 return S_OK;
211 }
212
213 static HRESULT STDMETHODCALLTYPE
214 IconExtraction_ExtractIconW_QueryInterface(
215 IExtractIconW *This,
216 REFIID riid,
217 void **ppvObject)
218 {
219 struct IconExtraction *s = CONTAINING_RECORD(This, struct IconExtraction, extractIconWImpl);
220 return IconExtraction_DefaultExtractIconInit_QueryInterface(&s->defaultExtractIconInitImpl, riid, ppvObject);
221 }
222
223 static ULONG STDMETHODCALLTYPE
224 IconExtraction_ExtractIconW_AddRef(
225 IExtractIconW *This)
226 {
227 struct IconExtraction *s = CONTAINING_RECORD(This, struct IconExtraction, extractIconWImpl);
228 return IconExtraction_DefaultExtractIconInit_AddRef(&s->defaultExtractIconInitImpl);
229 }
230
231 static ULONG STDMETHODCALLTYPE
232 IconExtraction_ExtractIconW_Release(
233 IExtractIconW *This)
234 {
235 struct IconExtraction *s = CONTAINING_RECORD(This, struct IconExtraction, extractIconWImpl);
236 return IconExtraction_DefaultExtractIconInit_Release(&s->defaultExtractIconInitImpl);
237 }
238
239 static HRESULT STDMETHODCALLTYPE
240 IconExtraction_ExtractIconW_GetIconLocation(
241 IExtractIconW *This,
242 UINT uFlags,
243 LPWSTR szIconFile,
244 UINT cchMax,
245 int *piIndex,
246 UINT *pwFlags)
247 {
248 struct IconExtraction *s = CONTAINING_RECORD(This, struct IconExtraction, extractIconWImpl);
249 const struct IconLocation *icon = NULL;
250 SIZE_T cb;
251
252 TRACE("(%p, 0x%x, %s, 0x%x, %p, %p)\n", This, uFlags, debugstr_w(szIconFile), cchMax, piIndex, pwFlags);
253
254 if (!piIndex || !pwFlags)
255 return E_POINTER;
256
257 if (uFlags & GIL_DEFAULTICON)
258 icon = s->defaultIcon.file ? &s->defaultIcon : &s->normalIcon;
259 else if (uFlags & GIL_FORSHORTCUT)
260 icon = s->shortcutIcon.file ? &s->shortcutIcon : &s->normalIcon;
261 else if (uFlags & GIL_OPENICON)
262 icon = s->openIcon.file ? &s->openIcon : &s->normalIcon;
263 else
264 icon = &s->normalIcon;
265
266 if (!icon->file)
267 return E_FAIL;
268
269 cb = wcslen(icon->file) + 1;
270 if (cchMax < (UINT)cb)
271 return E_FAIL;
272 CopyMemory(szIconFile, icon->file, cb * sizeof(WCHAR));
273 *piIndex = icon->index;
274 *pwFlags = s->flags;
275 return S_OK;
276 }
277
278 static HRESULT STDMETHODCALLTYPE
279 IconExtraction_ExtractIconW_Extract(
280 IExtractIconW *This,
281 LPCWSTR pszFile,
282 UINT nIconIndex,
283 HICON *phiconLarge,
284 HICON *phiconSmall,
285 UINT nIconSize)
286 {
287 TRACE("(%p, %s, %u, %p, %p, %u)\n", This, debugstr_w(pszFile),
288 nIconIndex, phiconLarge, phiconSmall, nIconSize);
289
290 /* Nothing to do, ExtractIconW::GetIconLocation should be enough */
291 return S_FALSE;
292 }
293
294 static HRESULT STDMETHODCALLTYPE
295 IconExtraction_ExtractIconA_QueryInterface(
296 IExtractIconA *This,
297 REFIID riid,
298 void **ppvObject)
299 {
300 struct IconExtraction *s = CONTAINING_RECORD(This, struct IconExtraction, extractIconAImpl);
301 return IconExtraction_DefaultExtractIconInit_QueryInterface(&s->defaultExtractIconInitImpl, riid, ppvObject);
302 }
303
304 static ULONG STDMETHODCALLTYPE
305 IconExtraction_ExtractIconA_AddRef(
306 IExtractIconA *This)
307 {
308 struct IconExtraction *s = CONTAINING_RECORD(This, struct IconExtraction, extractIconAImpl);
309 return IconExtraction_DefaultExtractIconInit_AddRef(&s->defaultExtractIconInitImpl);
310 }
311
312 static ULONG STDMETHODCALLTYPE
313 IconExtraction_ExtractIconA_Release(
314 IExtractIconA *This)
315 {
316 struct IconExtraction *s = CONTAINING_RECORD(This, struct IconExtraction, extractIconAImpl);
317 return IconExtraction_DefaultExtractIconInit_Release(&s->defaultExtractIconInitImpl);
318 }
319
320 static HRESULT STDMETHODCALLTYPE
321 IconExtraction_ExtractIconA_GetIconLocation(
322 IExtractIconA *This,
323 UINT uFlags,
324 LPSTR szIconFile,
325 UINT cchMax,
326 int *piIndex,
327 UINT *pwFlags)
328 {
329 struct IconExtraction *s = CONTAINING_RECORD(This, struct IconExtraction, extractIconAImpl);
330 LPWSTR szIconFileW = NULL;
331 HRESULT hr;
332
333 if (cchMax > 0)
334 {
335 szIconFileW = CoTaskMemAlloc(cchMax * sizeof(WCHAR));
336 if (!szIconFileW)
337 return E_OUTOFMEMORY;
338 }
339
340 hr = IconExtraction_ExtractIconW_GetIconLocation(
341 &s->extractIconWImpl, uFlags, szIconFileW, cchMax, piIndex, pwFlags);
342 if (SUCCEEDED(hr) && cchMax > 0)
343 if (0 == WideCharToMultiByte(CP_ACP, 0, szIconFileW, cchMax, szIconFile, cchMax, NULL, NULL))
344 hr = E_FAIL;
345
346 if (szIconFileW)
347 CoTaskMemFree(szIconFileW);
348 return hr;
349 }
350
351 static HRESULT STDMETHODCALLTYPE
352 IconExtraction_ExtractIconA_Extract(
353 IExtractIconA *This,
354 LPCSTR pszFile,
355 UINT nIconIndex,
356 HICON *phiconLarge,
357 HICON *phiconSmall,
358 UINT nIconSize)
359 {
360 struct IconExtraction *s = CONTAINING_RECORD(This, struct IconExtraction, extractIconAImpl);
361 LPWSTR pszFileW = NULL;
362 int nLength;
363 HRESULT hr;
364
365 if (pszFile)
366 {
367 nLength = MultiByteToWideChar(CP_ACP, 0, pszFile, -1, NULL, 0);
368 if (nLength == 0)
369 return E_FAIL;
370 pszFileW = CoTaskMemAlloc(nLength * sizeof(WCHAR));
371 if (!pszFileW)
372 return E_OUTOFMEMORY;
373 if (!MultiByteToWideChar(CP_ACP, 0, pszFile, nLength, pszFileW, nLength))
374 {
375 CoTaskMemFree(pszFileW);
376 return E_FAIL;
377 }
378 }
379
380 hr = IconExtraction_ExtractIconW_Extract(
381 &s->extractIconWImpl, pszFileW, nIconIndex, phiconLarge, phiconSmall, nIconSize);
382
383 if (pszFileW)
384 CoTaskMemFree(pszFileW);
385 return hr;
386 }
387
388 static HRESULT STDMETHODCALLTYPE
389 IconExtraction_PersistFile_QueryInterface(
390 IPersistFile *This,
391 REFIID riid,
392 void **ppvObject)
393 {
394 struct IconExtraction *s = CONTAINING_RECORD(This, struct IconExtraction, persistFileImpl);
395 return IconExtraction_DefaultExtractIconInit_QueryInterface(&s->defaultExtractIconInitImpl, riid, ppvObject);
396 }
397
398 static ULONG STDMETHODCALLTYPE
399 IconExtraction_PersistFile_AddRef(
400 IPersistFile *This)
401 {
402 struct IconExtraction *s = CONTAINING_RECORD(This, struct IconExtraction, persistFileImpl);
403 return IconExtraction_DefaultExtractIconInit_AddRef(&s->defaultExtractIconInitImpl);
404 }
405
406 static ULONG STDMETHODCALLTYPE
407 IconExtraction_PersistFile_Release(
408 IPersistFile *This)
409 {
410 struct IconExtraction *s = CONTAINING_RECORD(This, struct IconExtraction, persistFileImpl);
411 return IconExtraction_DefaultExtractIconInit_Release(&s->defaultExtractIconInitImpl);
412 }
413
414 static HRESULT STDMETHODCALLTYPE
415 IconExtraction_PersistFile_GetClassID(
416 IPersistFile *This,
417 CLSID *pClassID)
418 {
419 TRACE("(%p, %p)\n", This, pClassID);
420
421 if (!pClassID)
422 return E_POINTER;
423
424 *pClassID = GUID_NULL;
425 return S_OK;
426 }
427
428 static HRESULT STDMETHODCALLTYPE
429 IconExtraction_PersistFile_IsDirty(
430 IPersistFile *This)
431 {
432 FIXME("(%p)\n", This);
433 UNIMPLEMENTED;
434 return E_NOTIMPL;
435 }
436
437 static HRESULT STDMETHODCALLTYPE
438 IconExtraction_PersistFile_Load(
439 IPersistFile *This,
440 LPCOLESTR pszFileName,
441 DWORD dwMode)
442 {
443 FIXME("(%p, %s, %u)\n", This, debugstr_w(pszFileName), dwMode);
444 UNIMPLEMENTED;
445 return E_NOTIMPL;
446 }
447
448 static HRESULT STDMETHODCALLTYPE
449 IconExtraction_PersistFile_Save(
450 IPersistFile *This,
451 LPCOLESTR pszFileName,
452 BOOL fRemember)
453 {
454 FIXME("(%p, %s, %d)\n", This, debugstr_w(pszFileName), fRemember);
455 UNIMPLEMENTED;
456 return E_NOTIMPL;
457 }
458
459 static HRESULT STDMETHODCALLTYPE
460 IconExtraction_PersistFile_SaveCompleted(
461 IPersistFile *This,
462 LPCOLESTR pszFileName)
463 {
464 FIXME("(%p, %s)\n", This, debugstr_w(pszFileName));
465 UNIMPLEMENTED;
466 return E_NOTIMPL;
467 }
468
469 static HRESULT STDMETHODCALLTYPE
470 IconExtraction_PersistFile_GetCurFile(
471 IPersistFile *This,
472 LPOLESTR *ppszFileName)
473 {
474 FIXME("(%p, %p)\n", This, ppszFileName);
475 UNIMPLEMENTED;
476 return E_NOTIMPL;
477 }
478
479 static const IDefaultExtractIconInitVtbl IconExtractionDefaultExtractIconInitVtbl =
480 {
481 IconExtraction_DefaultExtractIconInit_QueryInterface,
482 IconExtraction_DefaultExtractIconInit_AddRef,
483 IconExtraction_DefaultExtractIconInit_Release,
484 IconExtraction_DefaultExtractIconInit_SetDefaultIcon,
485 IconExtraction_DefaultExtractIconInit_SetFlags,
486 IconExtraction_DefaultExtractIconInit_SetKey,
487 IconExtraction_DefaultExtractIconInit_SetNormalIcon,
488 IconExtraction_DefaultExtractIconInit_SetOpenIcon,
489 IconExtraction_DefaultExtractIconInit_SetShortcutIcon,
490 };
491
492 static const IExtractIconWVtbl IconExtractionExtractIconWVtbl =
493 {
494 IconExtraction_ExtractIconW_QueryInterface,
495 IconExtraction_ExtractIconW_AddRef,
496 IconExtraction_ExtractIconW_Release,
497 IconExtraction_ExtractIconW_GetIconLocation,
498 IconExtraction_ExtractIconW_Extract,
499 };
500
501 static const IExtractIconAVtbl IconExtractionExtractIconAVtbl =
502 {
503 IconExtraction_ExtractIconA_QueryInterface,
504 IconExtraction_ExtractIconA_AddRef,
505 IconExtraction_ExtractIconA_Release,
506 IconExtraction_ExtractIconA_GetIconLocation,
507 IconExtraction_ExtractIconA_Extract,
508 };
509
510 static const IPersistFileVtbl IconExtractionPersistFileVtbl =
511 {
512 IconExtraction_PersistFile_QueryInterface,
513 IconExtraction_PersistFile_AddRef,
514 IconExtraction_PersistFile_Release,
515 IconExtraction_PersistFile_GetClassID,
516 IconExtraction_PersistFile_IsDirty,
517 IconExtraction_PersistFile_Load,
518 IconExtraction_PersistFile_Save,
519 IconExtraction_PersistFile_SaveCompleted,
520 IconExtraction_PersistFile_GetCurFile,
521 };
522
523 HRESULT WINAPI
524 SHCreateDefaultExtractIcon(
525 REFIID riid,
526 void **ppv)
527 {
528 struct IconExtraction *s;
529
530 if (!ppv)
531 return E_POINTER;
532
533 *ppv = NULL;
534
535 s = CoTaskMemAlloc(sizeof(struct IconExtraction));
536 if (!s)
537 return E_OUTOFMEMORY;
538 memset(s, 0, sizeof(struct IconExtraction));
539 s->defaultExtractIconInitImpl.lpVtbl = &IconExtractionDefaultExtractIconInitVtbl;
540 s->extractIconAImpl.lpVtbl = &IconExtractionExtractIconAVtbl;
541 s->extractIconWImpl.lpVtbl = &IconExtractionExtractIconWVtbl;
542 s->persistFileImpl.lpVtbl = &IconExtractionPersistFileVtbl;
543 s->ref = 1;
544 *ppv = &s->defaultExtractIconInitImpl;
545
546 return S_OK;
547 }