Skip to content

Commit 4cd960b

Browse files
authored
Merge pull request #2451 from berryzplus/feature/add_ole_test
OLEクリップボードのテストを追加する
2 parents ee13fd3 + 027e138 commit 4cd960b

11 files changed

Lines changed: 987 additions & 207 deletions

File tree

sakura_core/_os/CDropTarget.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,15 @@ STDMETHODIMP CDropSource::GiveFeedback( [[maybe_unused]] DWORD dropEffect )
171171
return DRAGDROP_S_USEDEFAULTCURSORS;
172172
}
173173

174+
DWORD CDropSource::DoDragDrop(LPDATAOBJECT pDataObject, DWORD dwDesiredEffects)
175+
{
176+
if (DWORD dwEffects; SUCCEEDED(::DoDragDrop(pDataObject, this, dwDesiredEffects, &dwEffects))) {
177+
return dwEffects;
178+
}
179+
180+
return DROPEFFECT_NONE;
181+
}
182+
174183
/** 転送対象の文字列を設定する
175184
@param lpszText [in] 文字列
176185
@param nTextLen [in] pszTextの長さ
@@ -224,15 +233,6 @@ void CDataObject::SetText( LPCWSTR lpszText, size_t nTextLen, BOOL bColumnSelect
224233
}
225234
}
226235

227-
DWORD CDataObject::DragDrop( BOOL bLeft, DWORD dwEffects )
228-
{
229-
DWORD dwEffect;
230-
CDropSource drop( bLeft );
231-
if( SUCCEEDED( ::DoDragDrop( this, &drop, dwEffects, &dwEffect ) ) )
232-
return dwEffect;
233-
return DROPEFFECT_NONE;
234-
}
235-
236236
/** IDataObject::GetData
237237
@date 2008.03.26 ryoji 複数フォーマット対応
238238
*/

sakura_core/_os/CDropTarget.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
Copyright (C) 2002, aroka
99
Copyright (C) 2008, ryoji
1010
Copyright (C) 2009, ryoji
11-
Copyright (C) 2018-2022, Sakura Editor Organization
11+
Copyright (C) 2018-2026, Sakura Editor Organization
1212
1313
This source code is designed for sakura editor.
1414
Please contact the copyright holder to use this code for other purpose.
@@ -20,6 +20,7 @@
2020

2121
#include <Unknwn.h>
2222
#include "util/design_template.h"
23+
#include "util/os.h"
2324

2425
class CDropTarget;
2526
class CYbInterfaceBase;
@@ -121,6 +122,8 @@ class CDropSource : public CYbInterfaceImpl<IDropSource> {
121122

122123
STDMETHOD( QueryContinueDrag )( BOOL bEscapePressed, DWORD dwKeyState );
123124
STDMETHOD( GiveFeedback )( DWORD dropEffect );
125+
126+
DWORD DoDragDrop(LPDATAOBJECT pDataObject, DWORD dwDesiredEffects);
124127
};
125128

126129
class CDataObject : public CYbInterfaceImpl<IDataObject> {
@@ -147,7 +150,6 @@ class CDataObject : public CYbInterfaceImpl<IDataObject> {
147150
}
148151
~CDataObject(){SetText( nullptr, 0, FALSE );}
149152
void SetText( LPCWSTR lpszText, size_t nTextLen, BOOL bColumnSelect );
150-
DWORD DragDrop( BOOL bLeft, DWORD dwEffects );
151153

152154
STDMETHOD( GetData )( LPFORMATETC, LPSTGMEDIUM );
153155
STDMETHOD( GetDataHere )( LPFORMATETC, LPSTGMEDIUM );

sakura_core/doc/CEditDoc.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,3 +1022,83 @@ void CEditDoc::SetCurDirNotitle()
10221022
::SetCurrentDirectory( pszDir );
10231023
}
10241024
}
1025+
1026+
namespace cxx {
1027+
1028+
/*!
1029+
* @brief 指定したファイルパスのIDataObjectを作成する
1030+
*
1031+
* Windowsシステムにファイルパスを表すIDataObjectを作ってもらう。
1032+
*/
1033+
HRESULT MakeDataObject(_Outptr_ LPDATAOBJECT *ppDataObject, const std::filesystem::path& path)
1034+
{
1035+
// 出力値をクリアする
1036+
*ppDataObject = nullptr;
1037+
1038+
cxx::com_pointer<IShellFolder> pDesktop;
1039+
if (const auto hr = ::SHGetDesktopFolder(&pDesktop); FAILED(hr)) return hr;
1040+
1041+
std::wstring directory{ path.parent_path() };
1042+
1043+
const auto unusedArg1 = nullptr;
1044+
1045+
LPITEMIDLIST PathID;
1046+
DWORD Attribs = 0;
1047+
if (const auto hr = pDesktop->ParseDisplayName(nullptr, nullptr, std::data(directory), unusedArg1, &PathID, &Attribs); FAILED(hr)) return hr;
1048+
1049+
cxx::com_pointer<IShellFolder> pFolder;
1050+
if (const auto hr = pDesktop->BindToObject(PathID, nullptr, IID_PPV_ARGS(&pFolder)); FAILED(hr)) return hr;
1051+
::CoTaskMemFree(PathID);
1052+
1053+
std::wstring title = path.filename();
1054+
LPITEMIDLIST ItemID = nullptr;
1055+
if (const auto hr = pFolder->ParseDisplayName(nullptr, nullptr, std::data(title), unusedArg1, &ItemID, &Attribs); FAILED(hr)) return hr;
1056+
1057+
std::array idList = {
1058+
LPCITEMIDLIST(ItemID)
1059+
};
1060+
1061+
// ここで IDataObject を取得する
1062+
if (const auto hr = pFolder->GetUIObjectOf(nullptr, UINT(std::size(idList)), std::data(idList), IID_IDataObject, nullptr, (void**)ppDataObject); FAILED(hr)) return hr;
1063+
::CoTaskMemFree(ItemID);
1064+
1065+
return S_OK;
1066+
}
1067+
1068+
} // namespace cxx
1069+
1070+
/*!
1071+
* @brief ドキュメントのIDataObjectを取得する
1072+
*
1073+
* Windowsシステムからドキュメントのファイルパスを表すIDataObjectを取得する。
1074+
*
1075+
* 独自に CF_UNICODETEXT 形式でファイルパスを格納するようになっている。
1076+
*/
1077+
HRESULT CEditDoc::GetDataObject(LPDATAOBJECT *ppDataObject) const
1078+
{
1079+
// 出力値をクリアする
1080+
*ppDataObject = nullptr;
1081+
1082+
const auto cFilePath = m_cDocFile.GetFilePathClass();
1083+
if (!cFilePath.IsValidPath()) {
1084+
return S_FALSE;
1085+
}
1086+
1087+
const auto path = std::filesystem::path(cFilePath);
1088+
if (const auto hr = cxx::MakeDataObject(ppDataObject, path); FAILED(hr)) return hr;
1089+
1090+
// UNICODETEXT 形式のデータを作って追加する
1091+
cxx::GlobalWString hGlobal{ path.native() };
1092+
1093+
FORMATETC format{};
1094+
format.cfFormat = CF_UNICODETEXT;
1095+
format.dwAspect = DVASPECT_CONTENT;
1096+
format.lindex = -1;
1097+
format.tymed = TYMED_HGLOBAL;
1098+
1099+
STGMEDIUM medium{};
1100+
medium.tymed = TYMED_HGLOBAL;
1101+
medium.hGlobal = hGlobal.release();
1102+
1103+
return (*ppDataObject)->SetData(&format, &medium, TRUE);
1104+
}

sakura_core/doc/CEditDoc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ class CEditDoc
100100

101101
void SetCurDirNotitle();
102102

103+
HRESULT GetDataObject(LPDATAOBJECT *ppDataObj) const;
104+
103105
// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- //
104106
// メンバ変数群 //
105107
// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- //

sakura_core/util/os.cpp

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,3 +346,128 @@ BOOL ImeSetOpen(HWND hWnd, BOOL bOpen, BOOL* pBackup)
346346
bRet &= ImmReleaseContext(hWnd, hIMC);
347347
return bRet;
348348
}
349+
350+
namespace cxx {
351+
352+
GlobalDropFiles MakeDropFiles(std::span<const std::filesystem::path> files)
353+
{
354+
assert(!files.empty());
355+
356+
auto strFiles = std::accumulate(files.begin() + 1, files.end(), std::wstring(files.front()), [](const std::wstring& a, const std::filesystem::path& b) { return a + L'\0' + b.native(); }) + L'\0' + L'\0';
357+
358+
const size_t allocSize = sizeof(DROPFILES) + std::size(strFiles) * sizeof(WCHAR);
359+
GlobalDropFiles drop(allocSize);
360+
drop.Lock([strFiles](DROPFILES* p) {
361+
p->pFiles = DWORD(sizeof(DROPFILES));
362+
p->fWide = TRUE;
363+
std::ranges::copy(strFiles, LPWSTR(LPBYTE(p) + p->pFiles));
364+
});
365+
return drop;
366+
}
367+
368+
//文字列を指定して構築(指定した文字列を確保したメモリにコピーする)
369+
GlobalWString::GlobalWString(std::wstring_view text)
370+
: GlobalWString(text.size())
371+
{
372+
SetText(text);
373+
}
374+
375+
//文字列を指定して更新する
376+
void GlobalWString::SetText(std::wstring_view text) const
377+
{
378+
Lock([text](LPWSTR pStr, size_t cbSize) {
379+
if (cbSize / sizeof(WCHAR) <= std::size(text)) throw std::length_error("text length is too long.");
380+
std::ranges::copy(text, pStr);
381+
return true;
382+
});
383+
}
384+
385+
//格納されている文字列データのコピーを取得する
386+
std::wstring GlobalWString::wstring() const & {
387+
return Lock([](LPCWSTR pStr, size_t cbSize) {
388+
return std::wstring(pStr, ::wcsnlen(pStr, cbSize / sizeof(WCHAR)));
389+
});
390+
}
391+
392+
//文字列を指定して構築(指定した文字列を確保したメモリにコピーする)
393+
GlobalString::GlobalString(std::string_view text)
394+
: GlobalString(text.size())
395+
{
396+
SetText(text);
397+
}
398+
399+
//文字列を指定して更新する
400+
void GlobalString::SetText(std::string_view text) const
401+
{
402+
Lock([text](LPSTR pStr, size_t cbSize) {
403+
if (cbSize <= std::size(text)) throw std::length_error("text length is too long.");
404+
std::ranges::copy(text, pStr);
405+
return true;
406+
});
407+
}
408+
409+
//格納されている文字列データのコピーを取得する
410+
std::string GlobalString::string() const & {
411+
return Lock([](LPCSTR pStr, size_t cbSize) {
412+
return std::string(pStr, ::strnlen(pStr, cbSize));
413+
});
414+
}
415+
416+
//格納されているデータのコピーを取得する
417+
std::vector<std::filesystem::path> GlobalDropFiles::data() const & {
418+
const auto hDrop = static_cast<HDROP>(get());
419+
return Lock([hDrop](const DROPFILES* p [[maybe_unused]], size_t cbSize [[maybe_unused]]) {
420+
std::vector<std::filesystem::path> files;
421+
std::wstring buffer(_MAX_PATH, L'\0');
422+
const auto uFiles = ::DragQueryFileW(hDrop, 0xFFFFFFFF, nullptr, 0);
423+
for (UINT i = 0; i < uFiles; ++i) {
424+
// 必要サイズを取得する
425+
const auto required = ::DragQueryFileW(hDrop, i, nullptr, 0);
426+
427+
// バッファを確保して取得する
428+
buffer.resize(required);
429+
::DragQueryFileW(hDrop, i, std::data(buffer), UINT(std::size(buffer) + 1));
430+
431+
// パスリストに追加する
432+
files.emplace_back(buffer);
433+
}
434+
435+
return files;
436+
});
437+
}
438+
439+
//文字列を指定して必要サイズを計算する
440+
/* static */ size_t GlobalSakura::CalcSize(std::wstring_view text) noexcept
441+
{
442+
return sizeof(size_type) + (std::size(text) + 1) * sizeof(WCHAR);
443+
}
444+
445+
//文字列を指定して構築(指定した文字列を確保したメモリにコピーする)
446+
GlobalSakura::GlobalSakura(std::wstring_view text)
447+
: GlobalMemory(CalcSize(text))
448+
{
449+
SetText(text);
450+
}
451+
452+
// 文字列を指定して更新する
453+
void GlobalSakura::SetText(std::wstring_view text) const
454+
{
455+
Lock([text](LPWSTR pStr, size_t cbSize) {
456+
if (cbSize < CalcSize(text)) throw std::length_error("text length is too long.");
457+
*(size_type*)pStr = size_type(std::size(text));
458+
std::ranges::copy(text, LPWSTR(pStr + sizeof(size_type) / sizeof(WCHAR)));
459+
return true;
460+
});
461+
}
462+
463+
//格納されている文字列データのコピーを取得する
464+
std::wstring GlobalSakura::wstring() const & {
465+
return Lock([](LPCWSTR pStr, size_t cbSize) -> std::wstring {
466+
if (cbSize < sizeof(size_type) + sizeof(WCHAR)) return L"";
467+
const auto length = *(const size_type*)pStr;
468+
if (cbSize < sizeof(size_type) + (length + 1) * sizeof(WCHAR)) return L"";
469+
return std::wstring(LPCWSTR(pStr + sizeof(size_type) / sizeof(WCHAR)), length);
470+
});
471+
}
472+
473+
} // namespace cxx

0 commit comments

Comments
 (0)