mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-22 07:01:30 +00:00
[idd] helper: synchronize clipboard files
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -21,16 +21,20 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "CClipboardChannel.h"
|
#include "CClipboardChannel.h"
|
||||||
|
#include "CClipboardFiles.h"
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <deque>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class CClipboardSpool;
|
class CClipboardSpool;
|
||||||
@@ -38,6 +42,9 @@ class CClipboardSpool;
|
|||||||
class CClipboardManager final : private IClipboardChannelHandler
|
class CClipboardManager final : private IClipboardChannelHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
struct MarshaledDataObject;
|
||||||
|
class RemoteFileProvider;
|
||||||
|
|
||||||
enum class WorkType
|
enum class WorkType
|
||||||
{
|
{
|
||||||
STATE,
|
STATE,
|
||||||
@@ -45,6 +52,8 @@ private:
|
|||||||
RECORD,
|
RECORD,
|
||||||
SEND,
|
SEND,
|
||||||
SEND_DATA,
|
SEND_DATA,
|
||||||
|
SEND_FILE_DATA,
|
||||||
|
CANCEL_FILE_MANIFEST,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class UIType
|
enum class UIType
|
||||||
@@ -53,6 +62,8 @@ private:
|
|||||||
OFFER,
|
OFFER,
|
||||||
CLEAR,
|
CLEAR,
|
||||||
REQUEST,
|
REQUEST,
|
||||||
|
FILE_OFFER,
|
||||||
|
FILES,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Work
|
struct Work
|
||||||
@@ -64,6 +75,7 @@ private:
|
|||||||
KVMFRClipboardMessage record = {};
|
KVMFRClipboardMessage record = {};
|
||||||
std::vector<uint8_t> data;
|
std::vector<uint8_t> data;
|
||||||
std::shared_ptr<CClipboardSpool> spool;
|
std::shared_ptr<CClipboardSpool> spool;
|
||||||
|
std::shared_ptr<std::vector<uint8_t>> fileData;
|
||||||
uint64_t deadline = 0;
|
uint64_t deadline = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -73,6 +85,7 @@ private:
|
|||||||
bool available = false;
|
bool available = false;
|
||||||
uint64_t epoch = 0;
|
uint64_t epoch = 0;
|
||||||
KVMFRClipboardMessage record = {};
|
KVMFRClipboardMessage record = {};
|
||||||
|
std::shared_ptr<MarshaledDataObject> dataObject;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PendingCancel
|
struct PendingCancel
|
||||||
@@ -110,13 +123,55 @@ private:
|
|||||||
~IncomingTransfer();
|
~IncomingTransfer();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct IncomingFileRequest
|
||||||
|
{
|
||||||
|
uint64_t dataset = 0;
|
||||||
|
uint64_t transfer = 0;
|
||||||
|
uint64_t node = 0;
|
||||||
|
KVMFRClipboardFileOperation operation = 0;
|
||||||
|
uint64_t nextOffset = 0;
|
||||||
|
uint32_t nextSequence = 0;
|
||||||
|
uint64_t sizeHint = KVMFR_CLIPBOARD_SIZE_UNKNOWN;
|
||||||
|
uint32_t requestedBytes = 0;
|
||||||
|
bool began = false;
|
||||||
|
bool complete = false;
|
||||||
|
bool manifest = false;
|
||||||
|
KVMFRClipboardFileError error = KVMFR_CLIPBOARD_FILE_ERROR_NONE;
|
||||||
|
HANDLE event = nullptr;
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
|
||||||
|
~IncomingFileRequest();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RemoteFileManifest
|
||||||
|
{
|
||||||
|
uint64_t dataset = 0;
|
||||||
|
uint64_t acquisition = 0;
|
||||||
|
uint64_t currentRequest = 0;
|
||||||
|
uint64_t currentParent = 0;
|
||||||
|
uint64_t deadline = 0;
|
||||||
|
KVMFRClipboardMessage offer = {};
|
||||||
|
std::deque<uint64_t> directories;
|
||||||
|
std::vector<ClipboardRemoteFileEntry> entries;
|
||||||
|
std::unordered_set<uint64_t> nodes;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OutgoingFileRequest
|
||||||
|
{
|
||||||
|
uint64_t dataset = 0;
|
||||||
|
bool cancelled = false;
|
||||||
|
};
|
||||||
|
|
||||||
static constexpr UINT WM_CLIPBOARD_WORK = WM_APP + 0x4c;
|
static constexpr UINT WM_CLIPBOARD_WORK = WM_APP + 0x4c;
|
||||||
static constexpr size_t MAX_WORK = 16;
|
static constexpr size_t MAX_WORK = 16;
|
||||||
static constexpr size_t MAX_UI_WORK = 16;
|
static constexpr size_t MAX_UI_WORK = 16;
|
||||||
static constexpr size_t MAX_PENDING_CANCEL = 8;
|
static constexpr size_t MAX_PENDING_CANCEL =
|
||||||
|
KVMFR_CLIPBOARD_FILE_MAX_REQUESTS +
|
||||||
|
KVMFR_CLIPBOARD_FILE_MAX_ACQUISITIONS + 1U;
|
||||||
static constexpr size_t MAX_PENDING_CONTROL = 16;
|
static constexpr size_t MAX_PENDING_CONTROL = 16;
|
||||||
static constexpr DWORD RENDER_TIMEOUT_MS = 15000;
|
static constexpr DWORD RENDER_TIMEOUT_MS = 15000;
|
||||||
static constexpr DWORD SEND_TIMEOUT_MS = RENDER_TIMEOUT_MS;
|
static constexpr DWORD SEND_TIMEOUT_MS = RENDER_TIMEOUT_MS;
|
||||||
|
static constexpr DWORD FILE_MANIFEST_TIMEOUT_MS = 30000;
|
||||||
|
|
||||||
HWND m_hwnd;
|
HWND m_hwnd;
|
||||||
CClipboardChannel& m_channel;
|
CClipboardChannel& m_channel;
|
||||||
@@ -142,6 +197,20 @@ private:
|
|||||||
std::shared_ptr<IncomingTransfer> m_incoming;
|
std::shared_ptr<IncomingTransfer> m_incoming;
|
||||||
std::mutex m_outgoingLock;
|
std::mutex m_outgoingLock;
|
||||||
|
|
||||||
|
std::mutex m_fileLock;
|
||||||
|
std::unordered_map<uint64_t, std::shared_ptr<CLocalClipboardFiles>>
|
||||||
|
m_localFileDatasets;
|
||||||
|
std::unordered_map<uint64_t, uint64_t> m_localFileAcquisitions;
|
||||||
|
std::unordered_map<uint64_t, std::shared_ptr<IncomingFileRequest>>
|
||||||
|
m_incomingFileRequests;
|
||||||
|
std::unordered_map<uint64_t, uint64_t> m_remoteFileAcquisitions;
|
||||||
|
std::unordered_map<uint64_t, OutgoingFileRequest> m_outgoingFileRequests;
|
||||||
|
std::unique_ptr<RemoteFileManifest> m_remoteFileManifest;
|
||||||
|
std::shared_ptr<RemoteFileProvider> m_remoteFileProvider;
|
||||||
|
uint64_t m_localFileDataset = 0;
|
||||||
|
IDataObject * m_oleClipboard = nullptr;
|
||||||
|
bool m_oleInitialized = false;
|
||||||
|
|
||||||
UINT m_formatPNG = 0;
|
UINT m_formatPNG = 0;
|
||||||
UINT m_formatJPEG = 0;
|
UINT m_formatJPEG = 0;
|
||||||
UINT m_formatOrigin = 0;
|
UINT m_formatOrigin = 0;
|
||||||
@@ -152,6 +221,8 @@ private:
|
|||||||
uint64_t m_epoch = 0;
|
uint64_t m_epoch = 0;
|
||||||
uint64_t m_localGeneration = 0;
|
uint64_t m_localGeneration = 0;
|
||||||
DWORD m_localSequence = 0;
|
DWORD m_localSequence = 0;
|
||||||
|
DWORD m_localRetrySequence = 0;
|
||||||
|
uint64_t m_localRetryDeadline = 0;
|
||||||
uint64_t m_remoteGeneration = 0;
|
uint64_t m_remoteGeneration = 0;
|
||||||
uint32_t m_remoteFormats = 0;
|
uint32_t m_remoteFormats = 0;
|
||||||
DWORD m_ownedSequence = 0;
|
DWORD m_ownedSequence = 0;
|
||||||
@@ -166,11 +237,14 @@ private:
|
|||||||
void Thread();
|
void Thread();
|
||||||
|
|
||||||
bool QueueWork(Work&& work);
|
bool QueueWork(Work&& work);
|
||||||
|
bool QueueCancellation(const KVMFRClipboardMessage& record,
|
||||||
|
uint64_t deadline);
|
||||||
bool QueueCancel(const KVMFRClipboardMessage& record, uint32_t reason,
|
bool QueueCancel(const KVMFRClipboardMessage& record, uint32_t reason,
|
||||||
uint64_t deadline = 0);
|
uint64_t deadline = 0);
|
||||||
void QueueControl(WorkType type, bool available,
|
void QueueControl(WorkType type, bool available,
|
||||||
uint64_t epoch, uint32_t reason);
|
uint64_t epoch, uint32_t reason);
|
||||||
bool QueueUI(UIWork&& work);
|
bool QueueUI(UIWork&& work);
|
||||||
|
void DiscardPendingRemoteUI();
|
||||||
void DrainUI();
|
void DrainUI();
|
||||||
void ProcessWork(Work&& work);
|
void ProcessWork(Work&& work);
|
||||||
void ProcessRecord(const KVMFRClipboardMessage& record,
|
void ProcessRecord(const KVMFRClipboardMessage& record,
|
||||||
@@ -179,6 +253,32 @@ private:
|
|||||||
const uint8_t * data);
|
const uint8_t * data);
|
||||||
void ProcessSend(Work&& work);
|
void ProcessSend(Work&& work);
|
||||||
void ProcessSendData(Work&& work);
|
void ProcessSendData(Work&& work);
|
||||||
|
void ProcessSendFileData(Work&& work);
|
||||||
|
void ProcessFileRecord(const KVMFRClipboardMessage& record,
|
||||||
|
const uint8_t * data);
|
||||||
|
void ProcessFileData(const KVMFRClipboardMessage& record,
|
||||||
|
const uint8_t * data);
|
||||||
|
bool QueueFileCancel(const KVMFRClipboardMessage& record,
|
||||||
|
KVMFRClipboardFileError error);
|
||||||
|
void HandleFileAcquire(const KVMFRClipboardMessage& record);
|
||||||
|
void HandleFileRelease(const KVMFRClipboardMessage& record);
|
||||||
|
void HandleFileRequest(const KVMFRClipboardMessage& record);
|
||||||
|
void StartRemoteFileOffer(const KVMFRClipboardMessage& record);
|
||||||
|
void StartRemoteFileList(uint64_t parent);
|
||||||
|
void ContinueRemoteFileManifest(
|
||||||
|
const std::shared_ptr<IncomingFileRequest>& request);
|
||||||
|
void FinishRemoteFileManifest();
|
||||||
|
void FailRemoteFileManifest(KVMFRClipboardFileError error);
|
||||||
|
DWORD RemoteFileManifestWait() const;
|
||||||
|
void CheckRemoteFileManifestTimeout();
|
||||||
|
void CancelFileRequests(KVMFRClipboardFileError error,
|
||||||
|
uint64_t transfer = 0);
|
||||||
|
HRESULT ReadRemoteFile(uint64_t dataset, uint64_t acquisition,
|
||||||
|
uint64_t node, uint64_t offset, void * data, ULONG length, ULONG& read);
|
||||||
|
void ReleaseRemoteFileDataset(uint64_t dataset, uint64_t acquisition);
|
||||||
|
uint64_t NextHelperTransfer();
|
||||||
|
void PruneLocalFileDatasets();
|
||||||
|
void RetireLocalFileDataset();
|
||||||
void CancelIncoming(uint32_t reason, uint64_t transfer = 0);
|
void CancelIncoming(uint32_t reason, uint64_t transfer = 0);
|
||||||
void ReleaseOutgoing(uint64_t transfer);
|
void ReleaseOutgoing(uint64_t transfer);
|
||||||
|
|
||||||
@@ -186,21 +286,30 @@ private:
|
|||||||
void HandleOffer(const KVMFRClipboardMessage& record);
|
void HandleOffer(const KVMFRClipboardMessage& record);
|
||||||
void HandleClear(const KVMFRClipboardMessage& record);
|
void HandleClear(const KVMFRClipboardMessage& record);
|
||||||
void HandleRequest(const KVMFRClipboardMessage& record);
|
void HandleRequest(const KVMFRClipboardMessage& record);
|
||||||
|
void HandlePendingFileOffer(const KVMFRClipboardMessage& record);
|
||||||
|
void HandleFileDataObject(UIWork& work);
|
||||||
void HandleClipboardUpdate();
|
void HandleClipboardUpdate();
|
||||||
void HandleDestroyClipboard();
|
void HandleDestroyClipboard();
|
||||||
void RenderFormat(UINT format, uint64_t deadline = 0);
|
void RenderFormat(UINT format, uint64_t deadline = 0);
|
||||||
void RenderAllFormats();
|
void RenderAllFormats();
|
||||||
|
void RetryLocalClipboard();
|
||||||
void RetryRemoteOffer();
|
void RetryRemoteOffer();
|
||||||
|
|
||||||
bool OpenClipboardRetry() const;
|
bool OpenClipboardRetry() const;
|
||||||
bool IsOurClipboard();
|
bool IsOurClipboard();
|
||||||
uint32_t EnumerateFormats() const;
|
uint32_t EnumerateFormats() const;
|
||||||
|
std::shared_ptr<CLocalClipboardFiles> CaptureClipboardFiles(
|
||||||
|
DWORD sequence, bool& viaOLE, bool& openedOLE,
|
||||||
|
KVMFRClipboardFileError& error, DWORD& winError, HRESULT& oleError);
|
||||||
void PublishLocalClipboard();
|
void PublishLocalClipboard();
|
||||||
void PublishClear(uint64_t generation);
|
void PublishClear(uint64_t generation);
|
||||||
bool ApplyRemoteOffer(uint32_t formats, uint64_t generation);
|
bool ApplyRemoteOffer(uint32_t formats, uint64_t generation);
|
||||||
void ClearOwnedClipboard();
|
void ClearOwnedClipboard();
|
||||||
void InvalidateOutgoing(uint32_t reason);
|
void InvalidateOutgoing(uint32_t reason);
|
||||||
void InvalidateLocalClipboard(uint32_t reason);
|
void InvalidateLocalClipboard(uint32_t reason);
|
||||||
|
void ClearLocalRetry();
|
||||||
|
void DeferLocalClipboard(DWORD sequence, bool openedOLE);
|
||||||
|
void ExpireLocalRetry(DWORD sequence);
|
||||||
void ClearRemoteRetry();
|
void ClearRemoteRetry();
|
||||||
bool SetOriginMarker(uint64_t generation) const;
|
bool SetOriginMarker(uint64_t generation) const;
|
||||||
|
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ copy /Y "$(ProjectDir)VERSION" "$(SolutionDir)$(Platform)\$(Configuration)\LGIdd
|
|||||||
<CallingConvention>StdCall</CallingConvention>
|
<CallingConvention>StdCall</CallingConvention>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<AdditionalDependencies>%(AdditionalDependencies);Ole32.lib;Shell32.lib;Wtsapi32.lib</AdditionalDependencies>
|
<AdditionalDependencies>%(AdditionalDependencies);Bcrypt.lib;Ole32.lib;Shell32.lib;Wtsapi32.lib</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
#include <Ole2.h>
|
||||||
#include <wrl.h>
|
#include <wrl.h>
|
||||||
#include <UserEnv.h>
|
#include <UserEnv.h>
|
||||||
|
|
||||||
@@ -58,6 +59,11 @@ static HandleT<EventTraits> l_childStopEvent;
|
|||||||
static DWORD l_desiredSession = NO_CONSOLE_SESSION;
|
static DWORD l_desiredSession = NO_CONSOLE_SESSION;
|
||||||
static DWORD l_childSession = NO_CONSOLE_SESSION;
|
static DWORD l_childSession = NO_CONSOLE_SESSION;
|
||||||
|
|
||||||
|
struct OleScope
|
||||||
|
{
|
||||||
|
~OleScope() { OleUninitialize(); }
|
||||||
|
};
|
||||||
|
|
||||||
static bool Launch(DWORD sessionId);
|
static bool Launch(DWORD sessionId);
|
||||||
static bool StopChild();
|
static bool StopChild();
|
||||||
|
|
||||||
@@ -122,6 +128,23 @@ int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const HRESULT ole = OleInitialize(nullptr);
|
||||||
|
if (FAILED(ole))
|
||||||
|
{
|
||||||
|
DEBUG_ERROR_HR(ole, "Failed to initialize OLE");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
const OleScope oleScope;
|
||||||
|
|
||||||
|
const HRESULT security = CoInitializeSecurity(nullptr, 0, nullptr, nullptr,
|
||||||
|
RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IDENTIFY, nullptr, EOAC_NONE,
|
||||||
|
nullptr);
|
||||||
|
if (FAILED(security))
|
||||||
|
{
|
||||||
|
DEBUG_ERROR_HR(security, "Failed to initialize COM security");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
if (!CNotifyWindow::registerClass())
|
if (!CNotifyWindow::registerClass())
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to register message window class");
|
DEBUG_ERROR("Failed to register message window class");
|
||||||
|
|||||||
Reference in New Issue
Block a user