diff --git a/dll/shellext/fontext/CDataObject.cpp b/dll/shellext/fontext/CDataObject.cpp index f6851f19985..bff70910043 100644 --- a/dll/shellext/fontext/CDataObject.cpp +++ b/dll/shellext/fontext/CDataObject.cpp @@ -2,7 +2,7 @@ * PROJECT: ReactOS Font Shell Extension * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: CFontMenu implementation - * COPYRIGHT: Copyright 2019,2020 Mark Jansen (mark.jansen@reactos.org) + * COPYRIGHT: Copyright 2019-2021 Mark Jansen */ #include "precomp.h" @@ -58,7 +58,7 @@ HRESULT _CDataObject_CreateInstance(PCIDLIST_ABSOLUTE folder, UINT cidl, PCUITEM const FontPidlEntry* fontEntry = _FontFromIL(apidl[n]); if (fontEntry) { - CStringW File = g_FontCache->Filename(fontEntry, true); + CStringW File = g_FontCache->Filename(g_FontCache->Find(fontEntry), true); if (!File.IsEmpty()) { // Now append the path (+ nullterminator) to the buffer @@ -94,36 +94,8 @@ HRESULT _CDataObject_CreateInstance(PCIDLIST_ABSOLUTE folder, UINT cidl, PCUITEM pDrop->pt.x = pDrop->pt.y = 0; pDrop-> fNC = NULL; - // Prepare the format descriptors - STGMEDIUM medium = {0}; - medium.tymed = TYMED_HGLOBAL; - - // Copy the data to an HGLOBAL - medium.hGlobal = GlobalAlloc(GHND, offset); - if (medium.hGlobal) - { - LPVOID blob = GlobalLock(medium.hGlobal); - if (blob) - { - CopyMemory(blob, (BYTE*)data, offset); - GlobalUnlock(medium.hGlobal); - - CComPtr spDataObject(*(IDataObject**)ppvOut); - if (spDataObject) - { - FORMATETC etc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; - hr = spDataObject->SetData(&etc, &medium, TRUE); - } - } - else - { - ERR("Unable to lock the hGlobal?!\n"); - } - } - else - { - ERR("Unable to allocate %u bytes for the hGlobal\n", offset); - } + hr = DataObject_SetData(*(IDataObject**)ppvOut, CF_HDROP, data, offset); + FAILED_UNEXPECTEDLY(hr); return hr; } diff --git a/dll/shellext/fontext/CEnumFonts.cpp b/dll/shellext/fontext/CEnumFonts.cpp index 7e197187cdf..1b81a09318b 100644 --- a/dll/shellext/fontext/CEnumFonts.cpp +++ b/dll/shellext/fontext/CEnumFonts.cpp @@ -2,7 +2,7 @@ * PROJECT: ReactOS Font Shell Extension * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: CEnumFonts implementation - * COPYRIGHT: Copyright 2019 Mark Jansen (mark.jansen@reactos.org) + * COPYRIGHT: Copyright 2019 Mark Jansen */ #include "precomp.h" diff --git a/dll/shellext/fontext/CFontCache.cpp b/dll/shellext/fontext/CFontCache.cpp index 218be7bb638..53a7a5a6aec 100644 --- a/dll/shellext/fontext/CFontCache.cpp +++ b/dll/shellext/fontext/CFontCache.cpp @@ -2,7 +2,7 @@ * PROJECT: ReactOS Font Shell Extension * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: font list cache handling - * COPYRIGHT: Copyright 2019,2020 Mark Jansen (mark.jansen@reactos.org) + * COPYRIGHT: Copyright 2019-2021 Mark Jansen */ #include "precomp.h" @@ -14,7 +14,11 @@ CFontCache* g_FontCache = NULL; CFontInfo::CFontInfo(LPCWSTR name) : m_Name(name) , m_FileRead(false) + , m_AttrsRead(false) + , m_FileWriteTime({}) + , m_dwFileAttributes(0) { + m_FileSize.QuadPart = 0; } const CStringW& CFontInfo::Name() const @@ -62,7 +66,52 @@ const CStringW& CFontInfo::File() return m_File; } +void CFontInfo::ReadAttrs() +{ + CStringW File = g_FontCache->Filename(this, true); + m_AttrsRead = true; + + WIN32_FIND_DATAW findFileData; + HANDLE hFile = FindFirstFileW(File, &findFileData); + if (hFile != INVALID_HANDLE_VALUE) + { + + // File write time + FileTimeToLocalFileTime(&findFileData.ftLastWriteTime, &m_FileWriteTime); + + // File size + m_FileSize.HighPart = findFileData.nFileSizeHigh; + m_FileSize.LowPart = findFileData.nFileSizeLow; + + m_dwFileAttributes = findFileData.dwFileAttributes; + FindClose(hFile); + } +} + +const LARGE_INTEGER& CFontInfo::FileSize() +{ + if (!m_AttrsRead) + ReadAttrs(); + + return m_FileSize; +} + +const FILETIME& CFontInfo::FileWriteTime() +{ + if (!m_AttrsRead) + ReadAttrs(); + + return m_FileWriteTime; +} + +DWORD CFontInfo::FileAttributes() +{ + if (!m_AttrsRead) + ReadAttrs(); + + return m_dwFileAttributes; +} CFontCache::CFontCache() { @@ -93,30 +142,39 @@ CStringW CFontCache::Name(size_t Index) return m_Fonts[Index].Name(); } -CStringW CFontCache::Filename(const FontPidlEntry* fontEntry, bool alwaysFullPath) +CFontInfo* CFontCache::Find(const FontPidlEntry* fontEntry) { - CStringW File; - if (fontEntry->Index < m_Fonts.GetCount()) { - CFontInfo& info = m_Fonts[fontEntry->Index]; - - if (info.Name().CompareNoCase(fontEntry->Name) == 0) - File = info.File(); + if (m_Fonts[fontEntry->Index].Name().CompareNoCase(fontEntry->Name) == 0) + return &m_Fonts[fontEntry->Index]; } - for (UINT n = 0; File.IsEmpty() && n < Size(); ++n) + for (UINT n = 0; n < Size(); ++n) { if (m_Fonts[n].Name().CompareNoCase(fontEntry->Name) == 0) - File = m_Fonts[n].File(); - } - - if (!File.IsEmpty() && alwaysFullPath) - { - // Ensure this is a full path - if (PathIsRelativeW(File)) { - File = m_FontFolderPath + File; + return &m_Fonts[n]; + } + } + return nullptr; +} + + +CStringW CFontCache::Filename(CFontInfo* info, bool alwaysFullPath) +{ + CStringW File; + if (info) + { + File = info->File(); + + if (!File.IsEmpty() && alwaysFullPath) + { + // Ensure this is a full path + if (PathIsRelativeW(File)) + { + File = m_FontFolderPath + File; + } } } diff --git a/dll/shellext/fontext/CFontCache.hpp b/dll/shellext/fontext/CFontCache.hpp index 9454660a653..e047e6b4b1d 100644 --- a/dll/shellext/fontext/CFontCache.hpp +++ b/dll/shellext/fontext/CFontCache.hpp @@ -2,7 +2,7 @@ * PROJECT: ReactOS Font Shell Extension * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: font list cache handling - * COPYRIGHT: Copyright 2019,2020 Mark Jansen (mark.jansen@reactos.org) + * COPYRIGHT: Copyright 2019-2021 Mark Jansen */ #pragma once @@ -14,12 +14,24 @@ private: CStringW m_Name; CStringW m_File; bool m_FileRead; + + bool m_AttrsRead; + LARGE_INTEGER m_FileSize; + FILETIME m_FileWriteTime; + DWORD m_dwFileAttributes; + + void ReadAttrs(); + public: CFontInfo(LPCWSTR name = L""); - const CStringW& Name() const; - const CStringW& File(); + const CStringW& Name() const; // Font display name stored in the registry const bool Valid() const; + + const CStringW& File(); // Full path or file, depending on how it's stored in the registry + const LARGE_INTEGER& FileSize(); + const FILETIME& FileWriteTime(); + DWORD FileAttributes(); }; @@ -40,8 +52,10 @@ public: const CStringW& FontPath() const { return m_FontFolderPath; } size_t Size(); - CStringW Name(size_t Index); - CStringW Filename(const FontPidlEntry* fontEntry, bool alwaysFullPath = false); + CStringW Name(size_t Index); // Font display name stored in the registry + + CFontInfo* Find(const FontPidlEntry* fontEntry); + CStringW Filename(CFontInfo* info, bool alwaysFullPath = false); friend class CFontExtModule; }; diff --git a/dll/shellext/fontext/CFontExt.cpp b/dll/shellext/fontext/CFontExt.cpp index 03d03f420b1..b2681055cd2 100644 --- a/dll/shellext/fontext/CFontExt.cpp +++ b/dll/shellext/fontext/CFontExt.cpp @@ -2,7 +2,7 @@ * PROJECT: ReactOS Font Shell Extension * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: CFontExt implementation - * COPYRIGHT: Copyright 2019,2020 Mark Jansen (mark.jansen@reactos.org) + * COPYRIGHT: Copyright 2019-2021 Mark Jansen * Copyright 2019 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) */ @@ -11,6 +11,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(fontext); +#ifndef SHCIDS_ALLFIELDS +#define SHCIDS_ALLFIELDS 0x80000000L +#endif struct FolderViewColumns { @@ -20,6 +23,15 @@ struct FolderViewColumns int fmt; }; +enum font_columns +{ + FONTEXT_COL_NAME, + FONTEXT_COL_FILENAME, + FONTEXT_COL_SIZE, + FONTEXT_COL_MODIFIED, + FONTEXT_COL_ATTR, +}; + static FolderViewColumns g_ColumnDefs[] = { { IDS_COL_NAME, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 25, LVCFMT_LEFT }, @@ -140,7 +152,7 @@ STDMETHODIMP CFontExt::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDET } // Name, ReactOS specific? - if (iColumn == 0) + if (iColumn == FONTEXT_COL_NAME) return GetDisplayNameOf(pidl, 0, &psd->str); const FontPidlEntry* fontEntry = _FontFromIL(pidl); @@ -151,41 +163,28 @@ STDMETHODIMP CFontExt::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDET } // If we got here, we are in details view! - // Let's see if we got info about this file that we can re-use - if (m_LastDetailsFontName != fontEntry->Name) + auto info = g_FontCache->Find(fontEntry); + if (info == nullptr) { - CStringW File = g_FontCache->Filename(fontEntry, true); - HANDLE hFile = FindFirstFileW(File, &m_LastDetailsFileData); - if (hFile == INVALID_HANDLE_VALUE) - { - m_LastDetailsFontName.Empty(); - ERR("Unable to query info about %S\n", File.GetString()); - return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); - } - FindClose(hFile); - m_LastDetailsFontName = fontEntry->Name; + ERR("Unable to query info about %S\n", fontEntry->Name); + return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } - // Most code borrowed from CFSFolder::GetDetailsOf - FILETIME lft; - SYSTEMTIME time; int ret; - LARGE_INTEGER FileSize; CStringA AttrLetters; + DWORD dwAttributes; + SYSTEMTIME time; switch (iColumn) { - case 1: // Filename - return SHSetStrRet(&psd->str, m_LastDetailsFileData.cFileName); - case 2: // Size + case FONTEXT_COL_FILENAME: + return SHSetStrRet(&psd->str, PathFindFileNameW(info->File())); + case FONTEXT_COL_SIZE: psd->str.uType = STRRET_CSTR; - FileSize.HighPart = m_LastDetailsFileData.nFileSizeHigh; - FileSize.LowPart = m_LastDetailsFileData.nFileSizeLow; - StrFormatKBSizeA(FileSize.QuadPart, psd->str.cStr, MAX_PATH); + StrFormatKBSizeA(info->FileSize().QuadPart, psd->str.cStr, MAX_PATH); return S_OK; - case 3: // Modified - FileTimeToLocalFileTime(&m_LastDetailsFileData.ftLastWriteTime, &lft); - FileTimeToSystemTime (&lft, &time); + case FONTEXT_COL_MODIFIED: psd->str.uType = STRRET_CSTR; + FileTimeToSystemTime(&info->FileWriteTime(), &time); ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &time, NULL, psd->str.cStr, MAX_PATH); if (ret < 1) { @@ -195,7 +194,7 @@ STDMETHODIMP CFontExt::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDET psd->str.cStr[ret-1] = ' '; GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &time, NULL, &psd->str.cStr[ret], MAX_PATH - ret); return S_OK; - case 4: // Attributes + case FONTEXT_COL_ATTR: AttrLetters.LoadString(IDS_COL_ATTR_LETTERS); if (AttrLetters.GetLength() != 5) { @@ -203,16 +202,17 @@ STDMETHODIMP CFontExt::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDET return E_FAIL; } psd->str.uType = STRRET_CSTR; + dwAttributes = info->FileAttributes(); ret = 0; - if (m_LastDetailsFileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) + if (dwAttributes & FILE_ATTRIBUTE_READONLY) psd->str.cStr[ret++] = AttrLetters[0]; - if (m_LastDetailsFileData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) + if (dwAttributes & FILE_ATTRIBUTE_HIDDEN) psd->str.cStr[ret++] = AttrLetters[1]; - if (m_LastDetailsFileData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) + if (dwAttributes & FILE_ATTRIBUTE_SYSTEM) psd->str.cStr[ret++] = AttrLetters[2]; - if (m_LastDetailsFileData.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) + if (dwAttributes & FILE_ATTRIBUTE_ARCHIVE) psd->str.cStr[ret++] = AttrLetters[3]; - if (m_LastDetailsFileData.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) + if (dwAttributes & FILE_ATTRIBUTE_COMPRESSED) psd->str.cStr[ret++] = AttrLetters[4]; psd->str.cStr[ret] = '\0'; return S_OK; @@ -262,7 +262,53 @@ STDMETHODIMP CFontExt::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUID if (!fontEntry1 || !fontEntry2) return E_INVALIDARG; - int result = (int)fontEntry1->Index - (int)fontEntry2->Index; + int result; + DWORD sortMode = lParam & 0xFFFF0000; + DWORD column = lParam & 0x0000FFFF; + if (sortMode == SHCIDS_ALLFIELDS) + { + UNIMPLEMENTED; + result = (int)fontEntry1->Index - (int)fontEntry2->Index; + } + else + { + auto info1 = g_FontCache->Find(fontEntry1); + auto info2 = g_FontCache->Find(fontEntry2); + + if (!info1 || !info2) + { + ERR("Unable to find font %S or %S in cache!\n", fontEntry1->Name, fontEntry2->Name); + return E_INVALIDARG; + } + + switch (column) + { + case 0xffff: + /* ROS bug? */ + case FONTEXT_COL_NAME: + // These items are already ordered by name + result = (int)fontEntry1->Index - (int)fontEntry2->Index; + break; + case FONTEXT_COL_FILENAME: + result = wcsicmp(PathFindFileNameW(info1->File()), PathFindFileNameW(info2->File())); + break; + case FONTEXT_COL_SIZE: + result = (int)info1->FileSize().HighPart - info2->FileSize().HighPart; + if (result == 0) + result = (int)info1->FileSize().LowPart - info2->FileSize().LowPart; + break; + case FONTEXT_COL_MODIFIED: + result = CompareFileTime(&info1->FileWriteTime(), &info2->FileWriteTime()); + break; + case FONTEXT_COL_ATTR: + // FIXME: how to compare attributes? + result = (int)info1->FileAttributes() - info2->FileAttributes(); + break; + default: + ERR("Unimplemented column %u\n", column); + return E_INVALIDARG; + } + } return MAKE_COMPARE_HRESULT(result); } @@ -341,7 +387,7 @@ STDMETHODIMP CFontExt::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ if (fontEntry) { DWORD dwAttributes = FILE_ATTRIBUTE_NORMAL; - CStringW File = g_FontCache->Filename(fontEntry); + CStringW File = g_FontCache->Filename(g_FontCache->Find(fontEntry)); // Just create a default icon extractor based on the filename // We might want to create a preview with the font to get really fancy one day. return SHCreateFileExtractIconW(File, dwAttributes, riid, ppvOut); @@ -385,6 +431,15 @@ STDMETHODIMP CFontExt::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPS if (!fontEntry) return E_FAIL; + if (dwFlags == SHGDN_FORPARSING) + { + CStringW File = g_FontCache->Filename(g_FontCache->Find(fontEntry), true); + if (!File.IsEmpty()) + { + return SHSetStrRet(strRet, File); + } + } + return SHSetStrRet(strRet, fontEntry->Name); } diff --git a/dll/shellext/fontext/CFontExt.hpp b/dll/shellext/fontext/CFontExt.hpp index ba868628957..a3e5431c90f 100644 --- a/dll/shellext/fontext/CFontExt.hpp +++ b/dll/shellext/fontext/CFontExt.hpp @@ -2,7 +2,7 @@ * PROJECT: ReactOS Font Shell Extension * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: CFontExt definition - * COPYRIGHT: Copyright 2019,2020 Mark Jansen (mark.jansen@reactos.org) + * COPYRIGHT: Copyright 2019,2020 Mark Jansen * Copyright 2019 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) */ @@ -16,8 +16,6 @@ class CFontExt : public IDropTarget { CComHeapPtr m_Folder; - CStringW m_LastDetailsFontName; - WIN32_FIND_DATAW m_LastDetailsFileData; public: diff --git a/dll/shellext/fontext/CFontMenu.cpp b/dll/shellext/fontext/CFontMenu.cpp index 05b968e27d3..62464a099ee 100644 --- a/dll/shellext/fontext/CFontMenu.cpp +++ b/dll/shellext/fontext/CFontMenu.cpp @@ -2,7 +2,7 @@ * PROJECT: ReactOS Font Shell Extension * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: CFontMenu implementation - * COPYRIGHT: Copyright 2019,2020 Mark Jansen (mark.jansen@reactos.org) + * COPYRIGHT: Copyright 2019,2020 Mark Jansen */ #include "precomp.h" @@ -69,7 +69,7 @@ static void RunFontViewer(HWND hwnd, const FontPidlEntry* fontEntry) WCHAR FontViewerPath[MAX_PATH] = L"%SystemRoot%\\System32\\fontview.exe"; WCHAR FontPathArg[MAX_PATH + 3]; - CStringW Path = g_FontCache->Filename(fontEntry, true); + CStringW Path = g_FontCache->Filename(g_FontCache->Find(fontEntry), true); if (!Path.IsEmpty()) { // '/d' disables the install button @@ -108,7 +108,7 @@ static HRESULT CALLBACK FontFolderMenuCallback(IShellFolder *psf, HWND hwnd, IDa return S_OK; } case DFM_INVOKECOMMAND: - // Preview is the only item we can handle + // Preview is the only item we handle if (wParam == 0) { CComHeapPtr cida; @@ -123,6 +123,15 @@ static HRESULT CALLBACK FontFolderMenuCallback(IShellFolder *psf, HWND hwnd, IDa } return S_OK; } + else if (wParam == DFM_CMD_PROPERTIES) + { + ERR("Default properties handling!\n"); + return S_FALSE; + } + else + { + ERR("Unhandled DFM_INVOKECOMMAND(wParam=0x%x)\n", wParam); + } return S_FALSE; case DFM_INVOKECOMMANDEX: diff --git a/dll/shellext/fontext/fontext.cpp b/dll/shellext/fontext/fontext.cpp index d3659199e2d..0b68e40a7cb 100644 --- a/dll/shellext/fontext/fontext.cpp +++ b/dll/shellext/fontext/fontext.cpp @@ -2,7 +2,7 @@ * PROJECT: ReactOS Font Shell Extension * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: Shell extension entry point - * COPYRIGHT: Copyright 2019,2020 Mark Jansen (mark.jansen@reactos.org) + * COPYRIGHT: Copyright 2019,2020 Mark Jansen */ #include "precomp.h" diff --git a/dll/shellext/fontext/fontpidl.cpp b/dll/shellext/fontext/fontpidl.cpp index 38bb7814c84..6354e848bf2 100644 --- a/dll/shellext/fontext/fontpidl.cpp +++ b/dll/shellext/fontext/fontpidl.cpp @@ -2,7 +2,7 @@ * PROJECT: ReactOS Font Shell Extension * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: pidl handling - * COPYRIGHT: Copyright 2019,2020 Mark Jansen (mark.jansen@reactos.org) + * COPYRIGHT: Copyright 2019,2020 Mark Jansen */ #include "precomp.h" diff --git a/dll/shellext/fontext/fontpidl.hpp b/dll/shellext/fontext/fontpidl.hpp index f5ef556ddff..1546f646f78 100644 --- a/dll/shellext/fontext/fontpidl.hpp +++ b/dll/shellext/fontext/fontpidl.hpp @@ -2,7 +2,7 @@ * PROJECT: ReactOS Font Shell Extension * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: pidl handling - * COPYRIGHT: Copyright 2019 Mark Jansen (mark.jansen@reactos.org) + * COPYRIGHT: Copyright 2019 Mark Jansen */ #pragma once @@ -12,7 +12,7 @@ struct FontPidlEntry { WORD cb; WORD Magic; - ULONG Index; // Informative only + ULONG Index; // Informative only, used for sorting WCHAR Name[1]; }; diff --git a/sdk/include/reactos/shellutils.h b/sdk/include/reactos/shellutils.h index 82f2f708eee..c4e4026fd14 100644 --- a/sdk/include/reactos/shellutils.h +++ b/sdk/include/reactos/shellutils.h @@ -546,4 +546,69 @@ static inline PCUIDLIST_RELATIVE HIDA_GetPIDLItem(CIDA const* pida, SIZE_T i) } +#ifdef __cplusplus + +inline +HRESULT DataObject_GetData(IDataObject* pDataObject, CLIPFORMAT clipformat, PVOID pBuffer, SIZE_T dwBufferSize) +{ + FORMATETC fmt = { clipformat, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + STGMEDIUM medium = { TYMED_NULL }; + + HRESULT hr = pDataObject->GetData(&fmt, &medium); + if (SUCCEEDED(hr)) + { + LPVOID blob = GlobalLock(medium.hGlobal); + if (blob) + { + SIZE_T size = GlobalSize(medium.hGlobal); + if (size <= dwBufferSize) + { + CopyMemory(pBuffer, blob, size); + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + } + GlobalUnlock(medium.hGlobal); + } + else + { + hr = STG_E_INVALIDHANDLE; + } + + ReleaseStgMedium(&medium); + } + return hr; +} + +inline +HRESULT DataObject_SetData(IDataObject* pDataObject, CLIPFORMAT clipformat, PVOID pBuffer, SIZE_T dwBufferSize) +{ + STGMEDIUM medium = { TYMED_HGLOBAL }; + + medium.hGlobal = GlobalAlloc(GHND, dwBufferSize); + if (!medium.hGlobal) + return E_OUTOFMEMORY; + + HRESULT hr = E_UNEXPECTED; + LPVOID blob = GlobalLock(medium.hGlobal); + if (blob) + { + CopyMemory(blob, pBuffer, dwBufferSize); + GlobalUnlock(medium.hGlobal); + + FORMATETC etc = { clipformat, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + hr = pDataObject->SetData(&etc, &medium, TRUE); + } + + if (FAILED(hr)) + GlobalFree(medium.hGlobal); + + return hr; +} + +#endif + + #endif /* __ROS_SHELL_UTILS_H */