[PATCH 4/6] OLE: Implement OleSavePictureFile.
Nathan Beckmann
nathan.beckmann at gmail.com
Sun Feb 24 09:57:17 CST 2008
Implemented OleSavePictureFile. Created helper functions as well as a
function hold common functionality between OleSavePictureFile and
IPersistStream::Save.
Added basic tests based on a sample image.
TODO: Implement serialize{JPG,PNG,GIF,etc} to allow for saving in more
formats than just BMP.
---
dlls/oleaut32/Makefile.in | 2 +-
dlls/oleaut32/oleaut32.spec | 2 +-
dlls/oleaut32/olepicture.c | 138 +++++++++++++++++++++++++++++++++++--
dlls/oleaut32/tests/olepicture.c | 52 ++++++++++++++
4 files changed, 184 insertions(+), 10 deletions(-)
diff --git a/dlls/oleaut32/Makefile.in b/dlls/oleaut32/Makefile.in
index 18390a6..54107e7 100644
--- a/dlls/oleaut32/Makefile.in
+++ b/dlls/oleaut32/Makefile.in
@@ -5,7 +5,7 @@ SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = oleaut32.dll
IMPORTLIB = liboleaut32.$(IMPLIBEXT)
-IMPORTS = ole32 rpcrt4 user32 gdi32 advapi32 kernel32 ntdll
+IMPORTS = shlwapi ole32 rpcrt4 user32 gdi32 advapi32 kernel32 ntdll
DELAYIMPORTS = comctl32 urlmon
EXTRALIBS = -luuid
diff --git a/dlls/oleaut32/oleaut32.spec b/dlls/oleaut32/oleaut32.spec
index 7b764ef..a60926c 100644
--- a/dlls/oleaut32/oleaut32.spec
+++ b/dlls/oleaut32/oleaut32.spec
@@ -391,7 +391,7 @@
420 stdcall OleCreateFontIndirect(ptr ptr ptr)
421 stdcall OleTranslateColor(long long long)
422 stub OleLoadPictureFile
-423 stub OleSavePictureFile
+423 stdcall OleSavePictureFile(ptr wstr)
424 stdcall OleLoadPicturePath(wstr ptr long long ptr ptr)
425 stdcall VarUI4FromI8(double ptr)
426 stdcall VarUI4FromUI8(double ptr)
diff --git a/dlls/oleaut32/olepicture.c b/dlls/oleaut32/olepicture.c
index 42385a2..bf9213b 100644
--- a/dlls/oleaut32/olepicture.c
+++ b/dlls/oleaut32/olepicture.c
@@ -57,6 +57,8 @@
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
+#include "winreg.h"
+#include "shlwapi.h"
#include "ole2.h"
#include "olectl.h"
#include "oleauto.h"
@@ -2150,8 +2152,69 @@ static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
return iSuccess;
}
-static HRESULT WINAPI OLEPictureImpl_Save(
- IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
+/***********************************************************************
+ * picture_format_from_filename -
+ * Detect which picture format to use based on a file's extension.
+ */
+
+#define BITMAP_FORMAT_BMP 0x4d42 /* "BM */
+#define BITMAP_FORMAT_JPEG 0xd8ff /* ?? */
+#define BITMAP_FORMAT_GIF 0x4947 /* ?? */
+#define BITMAP_FORMAT_PNG 0x5089 /* ?? */
+
+static unsigned int picture_format_from_filename(WCHAR* filename)
+{
+ WCHAR* end_of_filename;
+ WCHAR* extension;
+ unsigned int fmt;
+
+ static const WCHAR bmp_ext[] = { 'b','m','p','\0' };
+ static const WCHAR jpg_ext[] = { 'j','p','g','\0' };
+ static const WCHAR jpeg_ext[] = { 'j','p','e','g','\0' };
+ static const WCHAR gif_ext[] = { 'g','i','f','\0' };
+ static const WCHAR png_ext[] = { 'p','n','g','\0' };
+
+ end_of_filename = filename;
+ while (*end_of_filename != '\0') {
+ ++end_of_filename;
+ }
+
+ extension = end_of_filename;
+ while (extension > filename && *extension != ((WCHAR)'.')) {
+ --extension;
+ }
+
+ if (extension <= filename)
+ return 0;
+
+ ++extension;
+
+ fmt = 0;
+
+ if (CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, extension, -1, bmp_ext, -1) == CSTR_EQUAL)
+ fmt = BITMAP_FORMAT_BMP;
+ else if (CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, extension, -1, jpeg_ext, -1) == CSTR_EQUAL ||
+ CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, extension, -1, jpg_ext, -1) == CSTR_EQUAL)
+ fmt = BITMAP_FORMAT_JPEG;
+ else if (CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, extension, -1, gif_ext, -1) == CSTR_EQUAL)
+ fmt = BITMAP_FORMAT_GIF;
+ else if (CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, extension, -1, png_ext, -1) == CSTR_EQUAL)
+ fmt = BITMAP_FORMAT_PNG;
+
+ return fmt;
+}
+
+/***********************************************************************
+ * save_picture_to_stream -
+ * This function combines OLEPictureImpl_Save, which implements
+ * IPersistStream::Save, with the functionality needed for
+ * OleSavePictureFile.
+ */
+
+static HRESULT save_picture_to_stream(IPersistStream *iface,
+ IStream *pStm,
+ BOOL fClearDirty,
+ unsigned int dest_format)
{
HRESULT hResult = E_NOTIMPL;
void * pIconData;
@@ -2159,6 +2222,7 @@ static HRESULT WINAPI OLEPictureImpl_Save(
ULONG dummy;
int iSerializeResult = 0;
OLEPictureImpl *This = impl_from_IPersistStream(iface);
+ unsigned int format;
TRACE("%p %p %d\n", This, pStm, fClearDirty);
@@ -2186,18 +2250,29 @@ static HRESULT WINAPI OLEPictureImpl_Save(
hResult = S_OK;
break;
case PICTYPE_BITMAP:
- if (This->bIsDirty) {
- switch (This->keepOrigFormat ? This->loadtime_format : 0x4d42) {
- case 0x4d42:
+ if (This->bIsDirty
+ ||
+ (dest_format && (dest_format != This->loadtime_format))
+ ) {
+
+ if (dest_format)
+ format = dest_format;
+ else if (This->keepOrigFormat)
+ format = This->loadtime_format;
+ else
+ format = BITMAP_FORMAT_BMP;
+
+ switch (format) {
+ case BITMAP_FORMAT_BMP:
iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
break;
- case 0xd8ff:
+ case BITMAP_FORMAT_JPEG:
FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
break;
- case 0x4947:
+ case BITMAP_FORMAT_GIF:
FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
break;
- case 0x5089:
+ case BITMAP_FORMAT_PNG:
FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
break;
default:
@@ -2231,6 +2306,12 @@ static HRESULT WINAPI OLEPictureImpl_Save(
return hResult;
}
+static HRESULT WINAPI OLEPictureImpl_Save(
+ IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
+{
+ return save_picture_to_stream(iface, pStm, fClearDirty, 0);
+}
+
static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
IPersistStream* iface,ULARGE_INTEGER*pcbSize)
{
@@ -2590,6 +2671,47 @@ HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
return hr;
}
+/***********************************************************************
+ * OleSavePictureFile (OLEAUT32.418)
+ */
+
+HRESULT WINAPI OleSavePictureFile( LPDISPATCH lpdispPicture, BSTR bstrFileName )
+{
+ LPPERSISTSTREAM ps;
+ LPSTREAM stream;
+ unsigned int dest_format;
+ HRESULT hr;
+
+ if (lpdispPicture == NULL || bstrFileName == NULL)
+ return CTL_E_INVALIDPROPERTYVALUE;
+
+ dest_format = picture_format_from_filename(bstrFileName);
+ if (!dest_format)
+ return CTL_E_INVALIDPROPERTYVALUE; /* FIXME: Is this a generic invalid parameter error code? */
+
+ hr = SHCreateStreamOnFileW(bstrFileName, STGM_SHARE_DENY_WRITE | STGM_WRITE | STGM_CREATE, &stream);
+ if (FAILED(hr)) {
+ return CTL_E_FILENOTFOUND;
+ }
+
+ hr = IDispatch_QueryInterface(lpdispPicture, &IID_IPersistStream, (LPVOID*)&ps);
+ if (FAILED(hr)) {
+ FIXME("Could not get IPersistStream iface from IPictureDisp?\n");
+ IStream_Release(stream);
+ return hr; /* FIXME: what is the right error code? */
+ }
+
+ hr = save_picture_to_stream(ps, stream, FALSE, dest_format);
+
+ if (FAILED(hr)) {
+ FIXME("If save_picture_to_stream fails, we still create an empty file. Is this correct behavior?\n");
+ }
+
+ IPersistStream_Release(ps);
+ IStream_Release(stream);
+ return hr;
+}
+
/***********************************************************************
* OleLoadPicture (OLEAUT32.418)
diff --git a/dlls/oleaut32/tests/olepicture.c b/dlls/oleaut32/tests/olepicture.c
index 22e2321..cd7c2b0 100644
--- a/dlls/oleaut32/tests/olepicture.c
+++ b/dlls/oleaut32/tests/olepicture.c
@@ -489,6 +489,7 @@ static void test_save_picture()
LPSTREAM in_stream;
LPSTREAM out_stream;
IPicture *pic;
+ IDispatch *dispatch;
IPersistStream *persist_stream;
ULONG dummy;
int i;
@@ -497,10 +498,13 @@ static void test_save_picture()
static const char oleloadpicture_file[] = { 't','e','s','t','.','b','m','p','\0' };
static const char ipersiststream_save_file[] = { 't','e','s','t','_','i','p','e','r','s','i','s','t','s','t','r','e','a','m','.','b','m','p','\0' };
+ static const WCHAR olesavepicturefile_file[] = { 't','e','s','t','_','o','l','e','s','a','v','e','p','i','c','t','u','r','e','f','i','l','e','.','b','m','p','\0' };
+ static const WCHAR olesavepicturefile_jpg_file[] = { 't','e','s','t','_','o','l','e','s','a','v','e','p','i','c','t','u','r','e','f','i','l','e','.','j','p','g','\0' };
in_stream = NULL;
out_stream = NULL;
pic = NULL;
+ dispatch = NULL;
persist_stream = NULL;
/* Create file */
@@ -534,6 +538,22 @@ static void test_save_picture()
IStream_Release(out_stream);
IPersistStream_Release(persist_stream);
+ /* OleSavePictureFile */
+ ret = IPicture_QueryInterface(pic, &IID_IDispatch, (LPVOID*) &dispatch);
+ ok(ret == S_OK, "Couldn't query IDispatch from pic.\n");
+
+ ret = OleSavePictureFile(dispatch, (BSTR)olesavepicturefile_file);
+ ok(ret == S_OK, "Failed OleSavePictureFile [bmp]\n");
+ ret = OleSavePictureFile(NULL, (BSTR)olesavepicturefile_file);
+ ok(ret != S_OK, "OleSavePictureFile succeeded with NULL pointer\n");
+ ret = OleSavePictureFile(dispatch, NULL);
+ ok(ret != S_OK, "OleSavePictureFile succeeded with NULL pointer\n");
+ todo_wine {
+ ret = OleSavePictureFile(dispatch, (BSTR)olesavepicturefile_jpg_file);
+ ok(ret == S_OK, "Failed OleSavePictureFile [jpeg]\n");
+ }
+
+ IDispatch_Release(dispatch);
IPicture_Release(pic);
/* Test output */
@@ -551,6 +571,38 @@ static void test_save_picture()
IStream_Release(in_stream);
}
+
+ ret = SHCreateStreamOnFileW(olesavepicturefile_file, STGM_SHARE_DENY_WRITE | STGM_READ | STGM_FAILIFTHERE, &in_stream);
+ ok(ret == S_OK, "Failed to read OleSavePictureFile [bmp] test image.\n");
+ if (SUCCEEDED(ret)) {
+ IStream_Read(in_stream, output_file, sizeof(output_file), &dummy);
+ ok(dummy == sizeof(bmpimage), "Output from OleSavePictureFile [bmp] is different size than test image.\n");
+ image_differ = FALSE;
+ for (i = 0; i < sizeof(bmpimage); i++) {
+ if (output_file[i] != bmpimage[i])
+ image_differ = TRUE;
+ }
+ ok(!image_differ, "Output from OleSavePictureFile [bmp] differs from test image.\n");
+
+ IStream_Release(in_stream);
+ }
+
+ ret = SHCreateStreamOnFileW(olesavepicturefile_jpg_file, STGM_SHARE_DENY_WRITE | STGM_READ | STGM_FAILIFTHERE, &in_stream);
+ ok(ret == S_OK, "Failed to read OleSavePictureFile [jpg] test image.\n");
+ if (SUCCEEDED(ret)) {
+ IStream_Read(in_stream, output_file, sizeof(output_file), &dummy);
+ ok(dummy != sizeof(bmpimage), "Output from OleSavePictureFile [jpg] is same size as test image.\n");
+ if (dummy == sizeof(bmpimage)) {
+ image_differ = FALSE;
+ for (i = 0; i < sizeof(bmpimage); i++) {
+ if (output_file[i] != bmpimage[i])
+ image_differ = TRUE;
+ }
+ ok(image_differ, "Output from OleSavePictureFile [jpg] is same as test image.\n");
+ }
+
+ IStream_Release(in_stream);
+ }
}
START_TEST(olepicture)
--
1.5.4.2
More information about the wine-patches
mailing list