gdi32: Improve EMF DC cleanup when CloseEnhMetafile is not called.
[wine.git] / dlls / packager / packager_main.c
blobc08bc30da6e84fc5c449d788429267cf95af4fa8
1 /*
2 * Copyright 2014 Andrew Eikum for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdarg.h>
21 #define COBJMACROS
22 #include "initguid.h"
23 #include "windef.h"
24 #include "winbase.h"
25 #include "ole2.h"
26 #include "rpcproxy.h"
27 #include "shellapi.h"
28 #include "shlwapi.h"
30 #include "wine/debug.h"
32 #include "packager_classes.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(packager);
36 struct Package {
37 IOleObject IOleObject_iface;
38 IPersistStorage IPersistStorage_iface;
40 LONG ref;
42 WCHAR filename[MAX_PATH];
44 IOleClientSite *clientsite;
47 static inline struct Package *impl_from_IOleObject(IOleObject *iface)
49 return CONTAINING_RECORD(iface, struct Package, IOleObject_iface);
52 static inline struct Package *impl_from_IPersistStorage(IPersistStorage *iface)
54 return CONTAINING_RECORD(iface, struct Package, IPersistStorage_iface);
57 static HRESULT WINAPI OleObject_QueryInterface(IOleObject *iface, REFIID riid, void **obj)
59 struct Package *This = impl_from_IOleObject(iface);
61 if(IsEqualGUID(riid, &IID_IUnknown) ||
62 IsEqualGUID(riid, &IID_IOleObject)) {
63 TRACE("(%p)->(IID_IOleObject, %p)\n", This, obj);
64 *obj = &This->IOleObject_iface;
65 }else if(IsEqualGUID(riid, &IID_IPersistStorage)){
66 TRACE("(%p)->(IID_IPersistStorage, %p)\n", This, obj);
67 *obj = &This->IPersistStorage_iface;
68 }else {
69 FIXME("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj);
70 *obj = NULL;
71 return E_NOINTERFACE;
74 IUnknown_AddRef((IUnknown*)*obj);
75 return S_OK;
78 static ULONG WINAPI OleObject_AddRef(IOleObject *iface)
80 struct Package *This = impl_from_IOleObject(iface);
81 LONG ref = InterlockedIncrement(&This->ref);
83 TRACE("(%p) ref=%ld\n", This, ref);
85 return ref;
88 static ULONG WINAPI OleObject_Release(IOleObject *iface)
90 struct Package *This = impl_from_IOleObject(iface);
91 LONG ref = InterlockedDecrement(&This->ref);
93 TRACE("(%p) ref=%ld\n", This, ref);
95 if(!ref){
96 if(This->clientsite)
97 IOleClientSite_Release(This->clientsite);
99 if(*This->filename)
100 DeleteFileW(This->filename);
102 HeapFree(GetProcessHeap(), 0, This);
105 return ref;
108 static HRESULT WINAPI OleObject_SetClientSite(IOleObject *iface, IOleClientSite *pClientSite)
110 struct Package *This = impl_from_IOleObject(iface);
112 TRACE("(%p)->(%p)\n", This, pClientSite);
114 if(This->clientsite)
115 IOleClientSite_Release(This->clientsite);
117 This->clientsite = pClientSite;
118 if(pClientSite)
119 IOleClientSite_AddRef(pClientSite);
121 return S_OK;
124 static HRESULT WINAPI OleObject_GetClientSite(IOleObject *iface, IOleClientSite **ppClientSite)
126 struct Package *This = impl_from_IOleObject(iface);
127 FIXME("(%p)->(%p)\n", This, ppClientSite);
128 return E_NOTIMPL;
131 static HRESULT WINAPI OleObject_SetHostNames(IOleObject *iface, LPCOLESTR szContainerApp, LPCOLESTR szContainerObj)
133 struct Package *This = impl_from_IOleObject(iface);
134 FIXME("(%p)->(%s, %s)\n", This, debugstr_w(szContainerApp), debugstr_w(szContainerObj));
135 return E_NOTIMPL;
138 static HRESULT WINAPI OleObject_Close(IOleObject *iface, DWORD dwSaveOption)
140 struct Package *This = impl_from_IOleObject(iface);
142 TRACE("(%p)->(0x%lx)\n", This, dwSaveOption);
144 if(dwSaveOption == OLECLOSE_SAVEIFDIRTY ||
145 dwSaveOption == OLECLOSE_PROMPTSAVE)
146 WARN("Saving unsupported\n");
148 return S_OK;
151 static HRESULT WINAPI OleObject_SetMoniker(IOleObject *iface, DWORD dwWhichMoniker, IMoniker *pmk)
153 struct Package *This = impl_from_IOleObject(iface);
154 FIXME("(%p)->(%ld, %p)\n", This, dwWhichMoniker, pmk);
155 return E_NOTIMPL;
158 static HRESULT WINAPI OleObject_GetMoniker(IOleObject *iface, DWORD dwAssign, DWORD dwWhichMoniker, IMoniker **ppmk)
160 struct Package *This = impl_from_IOleObject(iface);
161 FIXME("(%p)->(%ld, %ld, %p)\n", This, dwAssign, dwWhichMoniker, ppmk);
162 return E_NOTIMPL;
165 static HRESULT WINAPI OleObject_InitFromData(IOleObject *iface, IDataObject *pDataObject, BOOL fCreation,
166 DWORD dwReserved)
168 struct Package *This = impl_from_IOleObject(iface);
169 FIXME("(%p)->(%p, 0x%x, %ld)\n", This, pDataObject, fCreation, dwReserved);
170 return E_NOTIMPL;
173 static HRESULT WINAPI OleObject_GetClipboardData(IOleObject *iface, DWORD dwReserved, IDataObject **ppDataObject)
175 struct Package *This = impl_from_IOleObject(iface);
176 FIXME("(%p)->(%ld, %p)\n", This, dwReserved, ppDataObject);
177 return E_NOTIMPL;
180 static HRESULT do_activate_object(struct Package *This, HWND parent)
182 ShellExecuteW(parent, L"open", This->filename, NULL, NULL, SW_SHOW);
183 return S_OK;
186 static HRESULT WINAPI OleObject_DoVerb(IOleObject *iface, LONG iVerb, LPMSG lpmsg, IOleClientSite *pActiveSite,
187 LONG lindex, HWND hwndParent, LPCRECT lprcPosRect)
189 struct Package *This = impl_from_IOleObject(iface);
191 TRACE("(%p)->(%ld)\n", This, iVerb);
193 switch(iVerb){
194 case 0:
195 return do_activate_object(This, hwndParent);
198 return E_INVALIDARG;
201 static HRESULT WINAPI OleObject_EnumVerbs(IOleObject *iface, IEnumOLEVERB **ppEnumOleVerb)
203 struct Package *This = impl_from_IOleObject(iface);
204 FIXME("(%p)->(%p)\n", This, ppEnumOleVerb);
205 return E_NOTIMPL;
208 static HRESULT WINAPI OleObject_Update(IOleObject *iface)
210 struct Package *This = impl_from_IOleObject(iface);
211 FIXME("(%p)\n", This);
212 return E_NOTIMPL;
215 static HRESULT WINAPI OleObject_IsUpToDate(IOleObject *iface)
217 struct Package *This = impl_from_IOleObject(iface);
218 FIXME("(%p)\n", This);
219 return E_NOTIMPL;
222 static HRESULT WINAPI OleObject_GetUserClassID(IOleObject *iface, CLSID *pClsid)
224 struct Package *This = impl_from_IOleObject(iface);
225 FIXME("(%p)->(%p)\n", This, pClsid);
226 return E_NOTIMPL;
229 static HRESULT WINAPI OleObject_GetUserType(IOleObject *iface, DWORD dwFormOfType, LPOLESTR *pszUserType)
231 struct Package *This = impl_from_IOleObject(iface);
232 FIXME("(%p)->(%ld, %p)\n", This, dwFormOfType, pszUserType);
233 return E_NOTIMPL;
236 static HRESULT WINAPI OleObject_SetExtent(IOleObject *iface, DWORD dwDrawAspect, SIZEL *psizel)
238 struct Package *This = impl_from_IOleObject(iface);
239 FIXME("(%p)->(%ld, %p)\n", This, dwDrawAspect, psizel);
240 return E_NOTIMPL;
243 static HRESULT WINAPI OleObject_GetExtent(IOleObject *iface, DWORD dwDrawAspect, SIZEL *psizel)
245 struct Package *This = impl_from_IOleObject(iface);
246 FIXME("(%p)->(%ld, %p)\n", This, dwDrawAspect, psizel);
247 return E_NOTIMPL;
250 static HRESULT WINAPI OleObject_Advise(IOleObject *iface, IAdviseSink *pAdvSink, DWORD *pdwConnection)
252 struct Package *This = impl_from_IOleObject(iface);
253 FIXME("(%p)->(%p, %p)\n", This, pAdvSink, pdwConnection);
254 return E_NOTIMPL;
257 static HRESULT WINAPI OleObject_Unadvise(IOleObject *iface, DWORD dwConnection)
259 struct Package *This = impl_from_IOleObject(iface);
260 FIXME("(%p)->(%ld)\n", This, dwConnection);
261 return E_NOTIMPL;
264 static HRESULT WINAPI OleObject_EnumAdvise(IOleObject *iface, IEnumSTATDATA **ppenumAdvise)
266 struct Package *This = impl_from_IOleObject(iface);
267 FIXME("(%p)->(%p)\n", This, ppenumAdvise);
268 return E_NOTIMPL;
271 static HRESULT WINAPI OleObject_GetMiscStatus(IOleObject *iface, DWORD dwAspect, DWORD *pdwStatus)
273 struct Package *This = impl_from_IOleObject(iface);
275 TRACE("(%p)->(%ld, %p)\n", This, dwAspect, pdwStatus);
277 if(!pdwStatus)
278 return E_INVALIDARG;
280 *pdwStatus = OLEMISC_ONLYICONIC;
282 return S_OK;
285 static HRESULT WINAPI OleObject_SetColorScheme(IOleObject *iface, LOGPALETTE *pLogpal)
287 struct Package *This = impl_from_IOleObject(iface);
288 FIXME("(%p)->(%p)\n", This, pLogpal);
289 return E_NOTIMPL;
292 static const IOleObjectVtbl OleObject_Vtbl = {
293 OleObject_QueryInterface,
294 OleObject_AddRef,
295 OleObject_Release,
296 OleObject_SetClientSite,
297 OleObject_GetClientSite,
298 OleObject_SetHostNames,
299 OleObject_Close,
300 OleObject_SetMoniker,
301 OleObject_GetMoniker,
302 OleObject_InitFromData,
303 OleObject_GetClipboardData,
304 OleObject_DoVerb,
305 OleObject_EnumVerbs,
306 OleObject_Update,
307 OleObject_IsUpToDate,
308 OleObject_GetUserClassID,
309 OleObject_GetUserType,
310 OleObject_SetExtent,
311 OleObject_GetExtent,
312 OleObject_Advise,
313 OleObject_Unadvise,
314 OleObject_EnumAdvise,
315 OleObject_GetMiscStatus,
316 OleObject_SetColorScheme
319 static HRESULT WINAPI PersistStorage_QueryInterface(IPersistStorage* iface,
320 REFIID riid, void **ppvObject)
322 struct Package *This = impl_from_IPersistStorage(iface);
324 return OleObject_QueryInterface(&This->IOleObject_iface, riid, ppvObject);
327 static ULONG WINAPI PersistStorage_AddRef(IPersistStorage* iface)
329 struct Package *This = impl_from_IPersistStorage(iface);
331 return OleObject_AddRef(&This->IOleObject_iface);
334 static ULONG WINAPI PersistStorage_Release(IPersistStorage* iface)
336 struct Package *This = impl_from_IPersistStorage(iface);
338 return OleObject_Release(&This->IOleObject_iface);
341 static HRESULT WINAPI PersistStorage_GetClassID(IPersistStorage* iface,
342 CLSID *pClassID)
344 struct Package *This = impl_from_IPersistStorage(iface);
345 FIXME("(%p)->(%p)\n", This, pClassID);
346 return E_NOTIMPL;
349 static HRESULT WINAPI PersistStorage_IsDirty(IPersistStorage* iface)
351 struct Package *This = impl_from_IPersistStorage(iface);
352 FIXME("(%p)\n", This);
353 return E_NOTIMPL;
356 static HRESULT WINAPI PersistStorage_InitNew(IPersistStorage* iface,
357 IStorage *pStg)
359 struct Package *This = impl_from_IPersistStorage(iface);
360 FIXME("(%p)->(%p)\n", This, pStg);
361 return E_NOTIMPL;
364 static HRESULT discard_string(struct Package *This, IStream *stream)
366 ULONG nbytes;
367 HRESULT hr;
368 char chr = 0;
371 hr = IStream_Read(stream, &chr, 1, &nbytes);
372 if(FAILED(hr) || !nbytes){
373 TRACE("Unexpected end of stream or Read failed with %08lx\n", hr);
374 return (hr == S_OK || hr == S_FALSE) ? E_FAIL : hr;
376 }while(chr);
378 return S_OK;
381 static HRESULT WINAPI PersistStorage_Load(IPersistStorage* iface,
382 IStorage *pStg)
384 struct Package *This = impl_from_IPersistStorage(iface);
385 IStream *stream;
386 DWORD payload_size, len, stream_filename_len, filenameA_len, i, bytes_read;
387 ULARGE_INTEGER payload_pos;
388 LARGE_INTEGER seek;
389 HRESULT hr;
390 HANDLE file = INVALID_HANDLE_VALUE;
391 WCHAR filenameW[MAX_PATH];
392 char filenameA[MAX_PATH];
393 WCHAR *stream_filename;
394 WCHAR *base_end, extension[MAX_PATH];
396 TRACE("(%p)->(%p)\n", This, pStg);
398 hr = IStorage_OpenStream(pStg, L"\1Ole10Native", NULL,
399 STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stream);
400 if(FAILED(hr)){
401 TRACE("OpenStream gave: %08lx\n", hr);
402 return hr;
405 /* skip stream size & two unknown bytes */
406 seek.QuadPart = 6;
407 hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
408 if(FAILED(hr))
409 goto exit;
411 /* read and discard label */
412 hr = discard_string(This, stream);
413 if(FAILED(hr))
414 goto exit;
416 /* read and discard filename */
417 hr = discard_string(This, stream);
418 if(FAILED(hr))
419 goto exit;
421 /* skip more unknown data */
422 seek.QuadPart = 4;
423 hr = IStream_Seek(stream, seek, STREAM_SEEK_CUR, NULL);
424 if(FAILED(hr))
425 goto exit;
427 /* ASCIIZ filename */
428 hr = IStream_Read(stream, &filenameA_len, 4, NULL);
429 if(FAILED(hr))
430 goto exit;
432 hr = IStream_Read(stream, filenameA, filenameA_len, NULL);
433 if(FAILED(hr))
434 goto exit;
436 /* skip payload for now */
437 hr = IStream_Read(stream, &payload_size, 4, NULL);
438 if(FAILED(hr))
439 goto exit;
441 seek.QuadPart = 0;
442 hr = IStream_Seek(stream, seek, STREAM_SEEK_CUR, &payload_pos);
443 if(FAILED(hr))
444 goto exit;
446 seek.QuadPart = payload_size;
447 hr = IStream_Seek(stream, seek, STREAM_SEEK_CUR, NULL);
448 if(FAILED(hr))
449 goto exit;
451 /* read WCHAR filename, if present */
452 hr = IStream_Read(stream, &len, 4, &bytes_read);
453 if(SUCCEEDED(hr) && bytes_read == 4 && len > 0){
454 hr = IStream_Read(stream, filenameW, len * sizeof(WCHAR), NULL);
455 if(FAILED(hr))
456 goto exit;
457 }else{
458 len = MultiByteToWideChar(CP_ACP, 0, filenameA, filenameA_len,
459 filenameW, ARRAY_SIZE(filenameW));
462 stream_filename = filenameW + len - 1;
463 while(stream_filename != filenameW &&
464 *stream_filename != '\\')
465 --stream_filename;
466 if(*stream_filename == '\\')
467 ++stream_filename;
468 stream_filename_len = len - (stream_filename - filenameW);
470 len = GetTempPathW(ARRAY_SIZE(This->filename), This->filename);
471 memcpy(This->filename + len, stream_filename, stream_filename_len * sizeof(WCHAR));
472 This->filename[len + stream_filename_len] = 0;
474 /* read & write payload */
475 memcpy(&seek, &payload_pos, sizeof(seek)); /* STREAM_SEEK_SET treats as ULARGE_INTEGER */
476 hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
477 if(FAILED(hr))
478 goto exit;
480 base_end = PathFindExtensionW(This->filename);
481 lstrcpyW(extension, base_end);
482 i = 1;
484 file = CreateFileW(This->filename, GENERIC_WRITE, FILE_SHARE_READ, NULL,
485 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
486 while(file == INVALID_HANDLE_VALUE){
487 if(GetLastError() != ERROR_FILE_EXISTS){
488 WARN("CreateFile failed: %lu\n", GetLastError());
489 hr = E_FAIL;
490 goto exit;
493 /* file exists, so increment file name and try again */
494 ++i;
495 wsprintfW(base_end, L" (%u)", i);
496 lstrcatW(base_end, extension);
498 file = CreateFileW(This->filename, GENERIC_WRITE, FILE_SHARE_READ, NULL,
499 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
501 TRACE("Final filename: %s\n", wine_dbgstr_w(This->filename));
503 while(payload_size){
504 ULONG nbytes;
505 BYTE data[4096];
506 DWORD written;
508 hr = IStream_Read(stream, data, min(sizeof(data), payload_size), &nbytes);
509 if(FAILED(hr) || nbytes == 0){
510 TRACE("Unexpected end of file, or Read failed with %08lx\n", hr);
511 if(hr == S_OK || hr == S_FALSE)
512 hr = E_FAIL;
513 goto exit;
516 payload_size -= nbytes;
518 WriteFile(file, data, nbytes, &written, NULL);
521 hr = S_OK;
523 exit:
524 if(file != INVALID_HANDLE_VALUE){
525 CloseHandle(file);
526 if(FAILED(hr))
527 DeleteFileW(This->filename);
529 IStream_Release(stream);
531 TRACE("Returning: %08lx\n", hr);
532 return hr;
535 static HRESULT WINAPI PersistStorage_Save(IPersistStorage* iface,
536 IStorage *pStgSave, BOOL fSameAsLoad)
538 struct Package *This = impl_from_IPersistStorage(iface);
539 FIXME("(%p)->(%p, %u)\n", This, pStgSave, fSameAsLoad);
540 return E_NOTIMPL;
543 static HRESULT WINAPI PersistStorage_SaveCompleted(IPersistStorage* iface,
544 IStorage *pStgNew)
546 struct Package *This = impl_from_IPersistStorage(iface);
547 FIXME("(%p)->(%p)\n", This, pStgNew);
548 return E_NOTIMPL;
551 static HRESULT WINAPI PersistStorage_HandsOffStorage(IPersistStorage* iface)
553 struct Package *This = impl_from_IPersistStorage(iface);
554 FIXME("(%p)\n", This);
555 return E_NOTIMPL;
558 static IPersistStorageVtbl PersistStorage_Vtbl = {
559 PersistStorage_QueryInterface,
560 PersistStorage_AddRef,
561 PersistStorage_Release,
562 PersistStorage_GetClassID,
563 PersistStorage_IsDirty,
564 PersistStorage_InitNew,
565 PersistStorage_Load,
566 PersistStorage_Save,
567 PersistStorage_SaveCompleted,
568 PersistStorage_HandsOffStorage
571 static HRESULT WINAPI PackageCF_QueryInterface(IClassFactory *iface, REFIID riid, void **obj)
573 TRACE("(static)->(%s, %p)\n", debugstr_guid(riid), obj);
575 if(IsEqualGUID(&IID_IUnknown, riid) ||
576 IsEqualGUID(&IID_IClassFactory, riid))
577 *obj = iface;
578 else
579 *obj = NULL;
581 if(*obj){
582 IUnknown_AddRef((IUnknown*)*obj);
583 return S_OK;
586 FIXME("Unknown interface: %s\n", debugstr_guid(riid));
587 return E_NOINTERFACE;
590 static ULONG WINAPI PackageCF_AddRef(IClassFactory *iface)
592 TRACE("(static)\n");
593 return 2;
596 static ULONG WINAPI PackageCF_Release(IClassFactory *iface)
598 TRACE("(static)\n");
599 return 1;
602 static HRESULT WINAPI PackageCF_CreateInstance(IClassFactory *iface, IUnknown *outer,
603 REFIID iid, void **obj)
605 struct Package *package;
607 TRACE("(static)->(%p, %s, %p)\n", outer, wine_dbgstr_guid(iid), obj);
609 package = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*package));
610 if(!package)
611 return E_OUTOFMEMORY;
613 package->IOleObject_iface.lpVtbl = &OleObject_Vtbl;
614 package->IPersistStorage_iface.lpVtbl = &PersistStorage_Vtbl;
616 return IOleObject_QueryInterface(&package->IOleObject_iface, iid, obj);
619 static HRESULT WINAPI PackageCF_LockServer(IClassFactory *iface, BOOL fLock)
621 TRACE("(%p)->(%x)\n", iface, fLock);
622 return S_OK;
625 static const IClassFactoryVtbl PackageCF_Vtbl = {
626 PackageCF_QueryInterface,
627 PackageCF_AddRef,
628 PackageCF_Release,
629 PackageCF_CreateInstance,
630 PackageCF_LockServer
633 static IClassFactory PackageCF = {
634 &PackageCF_Vtbl
637 HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **obj)
639 TRACE("(%s, %s, %p)\n", wine_dbgstr_guid(clsid), wine_dbgstr_guid(iid), obj);
641 if(IsEqualGUID(clsid, &CLSID_Package))
642 return IClassFactory_QueryInterface(&PackageCF, iid, obj);
644 FIXME("Unknown CLSID: %s\n", wine_dbgstr_guid(clsid));
646 return CLASS_E_CLASSNOTAVAILABLE;