ole32: Add OleDoAutoConvert implementation.

This commit is contained in:
Piotr Caban 2014-04-07 18:55:59 +02:00 committed by Alexandre Julliard
parent 2db5418e02
commit 0d4c693a7b
2 changed files with 419 additions and 2 deletions

View file

@ -2718,8 +2718,59 @@ done:
*/
HRESULT WINAPI OleDoAutoConvert(LPSTORAGE pStg, LPCLSID pClsidNew)
{
FIXME("(%p,%p) : stub\n",pStg,pClsidNew);
return E_NOTIMPL;
WCHAR *user_type_old, *user_type_new;
CLIPFORMAT cf;
STATSTG stat;
CLSID clsid;
HRESULT hr;
TRACE("(%p, %p)\n", pStg, pClsidNew);
*pClsidNew = CLSID_NULL;
if(!pStg)
return E_INVALIDARG;
hr = IStorage_Stat(pStg, &stat, STATFLAG_NONAME);
if(FAILED(hr))
return hr;
*pClsidNew = stat.clsid;
hr = OleGetAutoConvert(&stat.clsid, &clsid);
if(FAILED(hr))
return hr;
hr = IStorage_SetClass(pStg, &clsid);
if(FAILED(hr))
return hr;
hr = ReadFmtUserTypeStg(pStg, &cf, &user_type_old);
if(FAILED(hr)) {
cf = 0;
user_type_new = NULL;
}
hr = OleRegGetUserType(&clsid, USERCLASSTYPE_FULL, &user_type_new);
if(FAILED(hr))
user_type_new = NULL;
hr = WriteFmtUserTypeStg(pStg, cf, user_type_new);
CoTaskMemFree(user_type_new);
if(FAILED(hr))
{
CoTaskMemFree(user_type_old);
IStorage_SetClass(pStg, &stat.clsid);
return hr;
}
hr = SetConvertStg(pStg, TRUE);
if(FAILED(hr))
{
WriteFmtUserTypeStg(pStg, cf, user_type_old);
IStorage_SetClass(pStg, &stat.clsid);
}
else
*pClsidNew = clsid;
CoTaskMemFree(user_type_old);
return hr;
}
/******************************************************************************

View file

@ -33,10 +33,48 @@
#define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr)
#define DEFINE_EXPECT(func) \
static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
#define SET_EXPECT(func) \
expect_ ## func = TRUE
#define CHECK_EXPECT2(func) \
do { \
ok(expect_ ##func, "unexpected call " #func "\n"); \
called_ ## func = TRUE; \
}while(0)
#define CHECK_EXPECT(func) \
do { \
CHECK_EXPECT2(func); \
expect_ ## func = FALSE; \
}while(0)
#define CHECK_CALLED(func) \
do { \
ok(called_ ## func, "expected " #func "\n"); \
expect_ ## func = called_ ## func = FALSE; \
}while(0)
DEFINE_EXPECT(Storage_Stat);
DEFINE_EXPECT(Storage_OpenStream_CompObj);
DEFINE_EXPECT(Storage_SetClass);
DEFINE_EXPECT(Storage_CreateStream_CompObj);
DEFINE_EXPECT(Storage_OpenStream_Ole);
static IPersistStorage OleObjectPersistStg;
static IOleCache *cache;
static IRunnableObject *runnable;
static const CLSID CLSID_WineTestOld =
{ /* 9474ba1a-258b-490b-bc13-516e9239acd0 */
0x9474ba1a,
0x258b,
0x490b,
{0xbc, 0x13, 0x51, 0x6e, 0x92, 0x39, 0xac, 0xd0}
};
static const CLSID CLSID_WineTest =
{ /* 9474ba1a-258b-490b-bc13-516e9239ace0 */
0x9474ba1a,
@ -1957,6 +1995,333 @@ static void test_OleDraw(void)
ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
}
static const WCHAR comp_objW[] = {1,'C','o','m','p','O','b','j',0};
static IStream *comp_obj_stream;
static IStream *ole_stream;
static HRESULT WINAPI Storage_QueryInterface(IStorage *iface, REFIID riid, void **ppvObject)
{
ok(0, "unexpected call to QueryInterface\n");
return E_NOTIMPL;
}
static ULONG WINAPI Storage_AddRef(IStorage *iface)
{
ok(0, "unexpected call to AddRef\n");
return 2;
}
static ULONG WINAPI Storage_Release(IStorage *iface)
{
ok(0, "unexpected call to Release\n");
return 1;
}
static HRESULT WINAPI Storage_CreateStream(IStorage *iface, LPCOLESTR pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream **ppstm)
{
ULARGE_INTEGER size = {{0}};
LARGE_INTEGER pos = {{0}};
HRESULT hr;
CHECK_EXPECT(Storage_CreateStream_CompObj);
ok(!lstrcmpW(pwcsName, comp_objW), "pwcsName = %s\n", wine_dbgstr_w(pwcsName));
todo_wine ok(grfMode == (STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE), "grfMode = %x\n", grfMode);
ok(!reserved1, "reserved1 = %x\n", reserved1);
ok(!reserved2, "reserved2 = %x\n", reserved2);
ok(!!ppstm, "ppstm = NULL\n");
*ppstm = comp_obj_stream;
IStream_AddRef(comp_obj_stream);
hr = IStream_Seek(comp_obj_stream, pos, STREAM_SEEK_SET, NULL);
ok(hr == S_OK, "IStream_Seek returned %x\n", hr);
hr = IStream_SetSize(comp_obj_stream, size);
ok(hr == S_OK, "IStream_SetSize returned %x\n", hr);
return S_OK;
}
static HRESULT WINAPI Storage_OpenStream(IStorage *iface, LPCOLESTR pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm)
{
static const WCHAR ole1W[] = {1,'O','l','e',0};
LARGE_INTEGER pos = {{0}};
HRESULT hr;
ok(!reserved1, "reserved1 = %p\n", reserved1);
ok(!reserved2, "reserved2 = %x\n", reserved2);
ok(!!ppstm, "ppstm = NULL\n");
if(!lstrcmpW(pwcsName, comp_objW)) {
CHECK_EXPECT2(Storage_OpenStream_CompObj);
ok(grfMode == STGM_SHARE_EXCLUSIVE, "grfMode = %x\n", grfMode);
*ppstm = comp_obj_stream;
IStream_AddRef(comp_obj_stream);
hr = IStream_Seek(comp_obj_stream, pos, STREAM_SEEK_SET, NULL);
ok(hr == S_OK, "IStream_Seek returned %x\n", hr);
return S_OK;
}else if(!lstrcmpW(pwcsName, ole1W)) {
CHECK_EXPECT(Storage_OpenStream_Ole);
ok(grfMode == (STGM_SHARE_EXCLUSIVE|STGM_READWRITE), "grfMode = %x\n", grfMode);
*ppstm = ole_stream;
IStream_AddRef(ole_stream);
hr = IStream_Seek(ole_stream, pos, STREAM_SEEK_SET, NULL);
ok(hr == S_OK, "IStream_Seek returned %x\n", hr);
return S_OK;
}
ok(0, "unexpected call to OpenStream: %s\n", wine_dbgstr_w(pwcsName));
return E_NOTIMPL;
}
static HRESULT WINAPI Storage_CreateStorage(IStorage *iface, LPCOLESTR pwcsName, DWORD grfMode, DWORD dwStgFmt, DWORD reserved2, IStorage **ppstg)
{
ok(0, "unexpected call to CreateStorage\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Storage_OpenStorage(IStorage *iface, LPCOLESTR pwcsName, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstg)
{
ok(0, "unexpected call to OpenStorage\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Storage_CopyTo(IStorage *iface, DWORD ciidExclude, const IID *rgiidExclude, SNB snbExclude, IStorage *pstgDest)
{
ok(0, "unexpected call to CopyTo\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Storage_MoveElementTo(IStorage *iface, LPCOLESTR pwcsName, IStorage *pstgDest, LPCOLESTR pwcsNewName, DWORD grfFlags)
{
ok(0, "unexpected call to MoveElementTo\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Storage_Commit(IStorage *iface, DWORD grfCommitFlags)
{
ok(0, "unexpected call to Commit\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Storage_Revert(IStorage *iface)
{
ok(0, "unexpected call to Revert\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Storage_EnumElements(IStorage *iface, DWORD reserved1, void *reserved2, DWORD reserved3, IEnumSTATSTG **ppenum)
{
ok(0, "unexpected call to EnumElements\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Storage_DestroyElement(IStorage *iface, LPCOLESTR pwcsName)
{
ok(0, "unexpected call to DestroyElement\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Storage_RenameElement(IStorage *iface, LPCOLESTR pwcsOldName, LPCOLESTR pwcsNewName)
{
ok(0, "unexpected call to RenameElement\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Storage_SetElementTimes(IStorage *iface, LPCOLESTR pwcsName, const FILETIME *pctime, const FILETIME *patime, const FILETIME *pmtime)
{
ok(0, "unexpected call to SetElementTimes\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Storage_SetClass(IStorage *iface, REFCLSID clsid)
{
CHECK_EXPECT(Storage_SetClass);
ok(IsEqualIID(clsid, &CLSID_WineTest), "clsid = %s\n", wine_dbgstr_guid(clsid));
return S_OK;
}
static HRESULT WINAPI Storage_SetStateBits(IStorage *iface, DWORD grfStateBits, DWORD grfMask)
{
ok(0, "unexpected call to SetStateBits\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Storage_Stat(IStorage *iface, STATSTG *pstatstg, DWORD grfStatFlag)
{
CHECK_EXPECT2(Storage_Stat);
ok(pstatstg != NULL, "pstatstg = NULL\n");
ok(grfStatFlag == STATFLAG_NONAME, "grfStatFlag = %x\n", grfStatFlag);
memset(pstatstg, 0, sizeof(STATSTG));
pstatstg->type = STGTY_STORAGE;
pstatstg->clsid = CLSID_WineTestOld;
return S_OK;
}
static IStorageVtbl StorageVtbl =
{
Storage_QueryInterface,
Storage_AddRef,
Storage_Release,
Storage_CreateStream,
Storage_OpenStream,
Storage_CreateStorage,
Storage_OpenStorage,
Storage_CopyTo,
Storage_MoveElementTo,
Storage_Commit,
Storage_Revert,
Storage_EnumElements,
Storage_DestroyElement,
Storage_RenameElement,
Storage_SetElementTimes,
Storage_SetClass,
Storage_SetStateBits,
Storage_Stat
};
static IStorage Storage = { &StorageVtbl };
static void test_OleDoAutoConvert(void)
{
static const WCHAR clsidW[] = {'C','L','S','I','D','\\',0};
static struct {
DWORD reserved1;
DWORD version;
DWORD reserved2[5];
DWORD ansi_user_type_len;
DWORD ansi_clipboard_format_len;
DWORD reserved3;
DWORD unicode_marker;
DWORD unicode_user_type_len;
DWORD unicode_clipboard_format_len;
DWORD reserved4;
} comp_obj_data;
static struct {
DWORD version;
DWORD flags;
DWORD link_update_option;
DWORD reserved1;
DWORD reserved_moniker_stream_size;
DWORD relative_source_moniker_stream_size;
DWORD absolute_source_moniker_stream_size;
DWORD clsid_indicator;
CLSID clsid;
DWORD reserved_display_name;
DWORD reserved2;
DWORD local_update_time;
DWORD local_check_update_time;
DWORD remote_update_time;
} ole_data;
LARGE_INTEGER pos = {{0}};
WCHAR buf[39+6];
DWORD i, ret;
HKEY root;
CLSID clsid;
HRESULT hr;
hr = CreateStreamOnHGlobal(NULL, TRUE, &comp_obj_stream);
ok(hr == S_OK, "CreateStreamOnHGlobal returned %x\n", hr);
hr = IStream_Write(comp_obj_stream, (char*)&comp_obj_data, sizeof(comp_obj_data), NULL);
ok(hr == S_OK, "IStream_Write returned %x\n", hr);
hr = CreateStreamOnHGlobal(NULL, TRUE, &ole_stream);
ok(hr == S_OK, "CreateStreamOnHGlobal returned %x\n", hr);
hr = IStream_Write(ole_stream, (char*)&ole_data, sizeof(ole_data), NULL);
ok(hr == S_OK, "IStream_Write returned %x\n", hr);
clsid = IID_WineTest;
hr = OleDoAutoConvert(NULL, &clsid);
ok(hr == E_INVALIDARG, "OleDoAutoConvert returned %x\n", hr);
ok(IsEqualIID(&clsid, &IID_NULL), "clsid = %s\n", wine_dbgstr_guid(&clsid));
if(0) /* crashes on Win7 */
OleDoAutoConvert(&Storage, NULL);
clsid = IID_WineTest;
SET_EXPECT(Storage_Stat);
hr = OleDoAutoConvert(&Storage, &clsid);
ok(hr == REGDB_E_CLASSNOTREG, "OleDoAutoConvert returned %x\n", hr);
CHECK_CALLED(Storage_Stat);
ok(IsEqualIID(&clsid, &CLSID_WineTestOld), "clsid = %s\n", wine_dbgstr_guid(&clsid));
lstrcpyW(buf, clsidW);
StringFromGUID2(&CLSID_WineTestOld, buf+6, 39);
ret = RegCreateKeyExW(HKEY_CLASSES_ROOT, buf, 0, NULL, 0,
KEY_READ | KEY_WRITE | KEY_CREATE_SUB_KEY, NULL, &root, NULL);
if(ret != ERROR_SUCCESS) {
win_skip("not enough permissions to create CLSID key (%u)\n", ret);
return;
}
clsid = IID_WineTest;
SET_EXPECT(Storage_Stat);
hr = OleDoAutoConvert(&Storage, &clsid);
ok(hr == REGDB_E_KEYMISSING, "OleDoAutoConvert returned %x\n", hr);
CHECK_CALLED(Storage_Stat);
ok(IsEqualIID(&clsid, &CLSID_WineTestOld), "clsid = %s\n", wine_dbgstr_guid(&clsid));
hr = OleSetAutoConvert(&CLSID_WineTestOld, &CLSID_WineTest);
ok_ole_success(hr, "OleSetAutoConvert");
hr = OleGetAutoConvert(&CLSID_WineTestOld, &clsid);
ok_ole_success(hr, "OleGetAutoConvert");
ok(IsEqualIID(&clsid, &CLSID_WineTest), "incorrect clsid: %s\n", wine_dbgstr_guid(&clsid));
clsid = IID_WineTest;
SET_EXPECT(Storage_Stat);
SET_EXPECT(Storage_OpenStream_CompObj);
SET_EXPECT(Storage_SetClass);
SET_EXPECT(Storage_CreateStream_CompObj);
SET_EXPECT(Storage_OpenStream_Ole);
hr = OleDoAutoConvert(&Storage, &clsid);
ok(hr == S_OK, "OleDoAutoConvert returned %x\n", hr);
CHECK_CALLED(Storage_Stat);
CHECK_CALLED(Storage_OpenStream_CompObj);
CHECK_CALLED(Storage_SetClass);
CHECK_CALLED(Storage_CreateStream_CompObj);
CHECK_CALLED(Storage_OpenStream_Ole);
ok(IsEqualIID(&clsid, &CLSID_WineTest), "clsid = %s\n", wine_dbgstr_guid(&clsid));
hr = IStream_Seek(comp_obj_stream, pos, STREAM_SEEK_SET, NULL);
ok(hr == S_OK, "IStream_Seek returned %x\n", hr);
hr = IStream_Read(comp_obj_stream, &comp_obj_data, sizeof(comp_obj_data), NULL);
ok(hr == S_OK, "IStream_Read returned %x\n", hr);
ok(comp_obj_data.reserved1 == 0xfffe0001, "reserved1 = %x\n", comp_obj_data.reserved1);
ok(comp_obj_data.version == 0xa03, "version = %x\n", comp_obj_data.version);
ok(comp_obj_data.reserved2[0] == -1, "reserved2[0] = %x\n", comp_obj_data.reserved2[0]);
ok(IsEqualIID(comp_obj_data.reserved2+1, &CLSID_WineTestOld), "reserved2 = %s\n", wine_dbgstr_guid((CLSID*)(comp_obj_data.reserved2+1)));
ok(!comp_obj_data.ansi_user_type_len, "ansi_user_type_len = %d\n", comp_obj_data.ansi_user_type_len);
ok(!comp_obj_data.ansi_clipboard_format_len, "ansi_clipboard_format_len = %d\n", comp_obj_data.ansi_clipboard_format_len);
ok(!comp_obj_data.reserved3, "reserved3 = %x\n", comp_obj_data.reserved3);
ok(comp_obj_data.unicode_marker == 0x71b239f4, "unicode_marker = %x\n", comp_obj_data.unicode_marker);
ok(!comp_obj_data.unicode_user_type_len, "unicode_user_type_len = %d\n", comp_obj_data.unicode_user_type_len);
ok(!comp_obj_data.unicode_clipboard_format_len, "unicode_clipboard_format_len = %d\n", comp_obj_data.unicode_clipboard_format_len);
ok(!comp_obj_data.reserved4, "reserved4 %d\n", comp_obj_data.reserved4);
ret = IStream_Release(comp_obj_stream);
ok(!ret, "comp_obj_stream was not freed\n");
hr = IStream_Seek(ole_stream, pos, STREAM_SEEK_SET, NULL);
ok(hr == S_OK, "IStream_Seek returned %x\n", hr);
hr = IStream_Read(ole_stream, &ole_data, sizeof(ole_data), NULL);
ok(hr == S_OK, "IStream_Read returned %x\n", hr);
ok(ole_data.version == 0, "version = %x\n", ole_data.version);
ok(ole_data.flags == 4, "flags = %x\n", ole_data.flags);
for(i=2; i<sizeof(ole_data)/sizeof(DWORD); i++)
ok(((DWORD*)&ole_data)[i] == 0, "ole_data[%d] = %x\n", i, ((DWORD*)&ole_data)[i]);
ret = IStream_Release(ole_stream);
ok(!ret, "ole_stream was not freed\n");
ret = RegDeleteKeyA(root, "AutoConvertTo");
ok(ret == ERROR_SUCCESS, "RegDeleteKey error %u\n", ret);
ret = RegDeleteKeyA(root, "");
ok(ret == ERROR_SUCCESS, "RegDeleteKey error %u\n", ret);
RegCloseKey(root);
}
START_TEST(ole2)
{
DWORD dwRegister;
@ -1995,6 +2360,7 @@ START_TEST(ole2)
test_OleRun();
test_OleLockRunning();
test_OleDraw();
test_OleDoAutoConvert();
CoUninitialize();
}