mirror of
https://github.com/Obfuscator-Collections/VMProtect.git
synced 2025-08-02 04:40:10 +03:00
first commit
Version 3.x.x
This commit is contained in:
241
shellext/bitmap_utils.cc
Normal file
241
shellext/bitmap_utils.cc
Normal file
@@ -0,0 +1,241 @@
|
||||
#include "bitmap_utils.h"
|
||||
|
||||
/**
|
||||
* BitmapUtils
|
||||
*/
|
||||
|
||||
BitmapUtils::BitmapUtils()
|
||||
{
|
||||
hUxTheme_ = LoadLibrary(L"UXTHEME.DLL");
|
||||
|
||||
if (hUxTheme_)
|
||||
{
|
||||
pfnGetBufferedPaintBits_ = (FN_GetBufferedPaintBits)::GetProcAddress(hUxTheme_, "GetBufferedPaintBits");
|
||||
pfnBeginBufferedPaint_ = (FN_BeginBufferedPaint)::GetProcAddress(hUxTheme_, "BeginBufferedPaint");
|
||||
pfnEndBufferedPaint_ = (FN_EndBufferedPaint)::GetProcAddress(hUxTheme_, "EndBufferedPaint");
|
||||
} else
|
||||
{
|
||||
pfnGetBufferedPaintBits_ = NULL;
|
||||
pfnBeginBufferedPaint_ = NULL;
|
||||
pfnEndBufferedPaint_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
BitmapUtils::~BitmapUtils()
|
||||
{
|
||||
std::map<UINT, HBITMAP>::iterator it;
|
||||
for (it = bitmaps_.begin(); it != bitmaps_.end(); ++it){
|
||||
DeleteObject(it->second);
|
||||
}
|
||||
bitmaps_.clear();
|
||||
|
||||
if (hUxTheme_)
|
||||
FreeLibrary(hUxTheme_);
|
||||
}
|
||||
|
||||
bool BitmapUtils::IsVistaOrLater() const
|
||||
{
|
||||
static OSVERSIONINFO vi = {};
|
||||
if(0 == vi.dwOSVersionInfoSize)
|
||||
{
|
||||
vi.dwOSVersionInfoSize = sizeof(vi);
|
||||
GetVersionEx(&vi);
|
||||
}
|
||||
return vi.dwMajorVersion >= 6;
|
||||
}
|
||||
|
||||
HBITMAP BitmapUtils::IconToBitmapPARGB32(HINSTANCE hInst, UINT uIcon)
|
||||
{
|
||||
std::map<UINT, HBITMAP>::iterator it = bitmaps_.lower_bound(uIcon);
|
||||
if (it != bitmaps_.end() && it->first == uIcon)
|
||||
return it->second;
|
||||
|
||||
HBITMAP hBmp = HBMMENU_CALLBACK;
|
||||
if (IsVistaOrLater()) {
|
||||
HICON hIcon = static_cast<HICON>(LoadImageW(hInst, MAKEINTRESOURCE(uIcon), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR));
|
||||
hBmp = IconToBitmapPARGB32(hIcon);
|
||||
DestroyIcon(hIcon);
|
||||
}
|
||||
|
||||
if(hBmp)
|
||||
bitmaps_.insert(std::make_pair(uIcon, hBmp));
|
||||
|
||||
return hBmp;
|
||||
}
|
||||
|
||||
HBITMAP BitmapUtils::IconToBitmapPARGB32(HICON hIcon) const
|
||||
{
|
||||
if (!hIcon || !IsVistaOrLater())
|
||||
return NULL;
|
||||
|
||||
SIZE sizIcon;
|
||||
sizIcon.cx = GetSystemMetrics(SM_CXSMICON);
|
||||
sizIcon.cy = GetSystemMetrics(SM_CYSMICON);
|
||||
|
||||
RECT rcIcon;
|
||||
SetRect(&rcIcon, 0, 0, sizIcon.cx, sizIcon.cy);
|
||||
HBITMAP hBmp = NULL;
|
||||
|
||||
HDC hdcDest = CreateCompatibleDC(NULL);
|
||||
if (hdcDest)
|
||||
{
|
||||
if (SUCCEEDED(Create32BitHBITMAP(hdcDest, &sizIcon, NULL, &hBmp)))
|
||||
{
|
||||
HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcDest, hBmp);
|
||||
if (hbmpOld)
|
||||
{
|
||||
BLENDFUNCTION bfAlpha = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
|
||||
BP_PAINTPARAMS paintParams = {};
|
||||
paintParams.cbSize = sizeof(paintParams);
|
||||
paintParams.dwFlags = BPPF_ERASE;
|
||||
paintParams.pBlendFunction = &bfAlpha;
|
||||
|
||||
HDC hdcBuffer;
|
||||
HPAINTBUFFER hPaintBuffer = pfnBeginBufferedPaint_(hdcDest, &rcIcon, BPBF_DIB, &paintParams, &hdcBuffer);
|
||||
if (hPaintBuffer)
|
||||
{
|
||||
if (DrawIconEx(hdcBuffer, 0, 0, hIcon, sizIcon.cx, sizIcon.cy, 0, NULL, DI_NORMAL))
|
||||
{
|
||||
// If icon did not have an alpha channel we need to convert buffer to PARGB
|
||||
ConvertBufferToPARGB32(hPaintBuffer, hdcDest, hIcon, sizIcon);
|
||||
}
|
||||
|
||||
// This will write the buffer contents to the destination bitmap
|
||||
pfnEndBufferedPaint_(hPaintBuffer, TRUE);
|
||||
}
|
||||
|
||||
SelectObject(hdcDest, hbmpOld);
|
||||
}
|
||||
}
|
||||
|
||||
DeleteDC(hdcDest);
|
||||
}
|
||||
|
||||
return hBmp;
|
||||
}
|
||||
|
||||
HRESULT BitmapUtils::Create32BitHBITMAP(HDC hdc, const SIZE *psize, __deref_opt_out void **ppvBits, __out HBITMAP* phBmp) const
|
||||
{
|
||||
if (psize == 0)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (phBmp == 0)
|
||||
return E_POINTER;
|
||||
|
||||
*phBmp = NULL;
|
||||
|
||||
BITMAPINFO bmi;
|
||||
SecureZeroMemory(&bmi, sizeof(bmi));
|
||||
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmi.bmiHeader.biPlanes = 1;
|
||||
bmi.bmiHeader.biCompression = BI_RGB;
|
||||
|
||||
bmi.bmiHeader.biWidth = psize->cx;
|
||||
bmi.bmiHeader.biHeight = psize->cy;
|
||||
bmi.bmiHeader.biBitCount = 32;
|
||||
|
||||
HDC hdcUsed = hdc ? hdc : GetDC(NULL);
|
||||
if (hdcUsed)
|
||||
{
|
||||
*phBmp = CreateDIBSection(hdcUsed, &bmi, DIB_RGB_COLORS, ppvBits, NULL, 0);
|
||||
if (hdc != hdcUsed)
|
||||
{
|
||||
ReleaseDC(NULL, hdcUsed);
|
||||
}
|
||||
}
|
||||
return (NULL == *phBmp) ? E_OUTOFMEMORY : S_OK;
|
||||
}
|
||||
|
||||
HRESULT BitmapUtils::ConvertBufferToPARGB32(HPAINTBUFFER hPaintBuffer, HDC hdc, HICON hicon, SIZE& sizIcon) const
|
||||
{
|
||||
RGBQUAD *prgbQuad;
|
||||
int cxRow;
|
||||
HRESULT hr = pfnGetBufferedPaintBits_(hPaintBuffer, &prgbQuad, &cxRow);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
Gdiplus::ARGB *pargb = reinterpret_cast<Gdiplus::ARGB *>(prgbQuad);
|
||||
if (!HasAlpha(pargb, sizIcon, cxRow))
|
||||
{
|
||||
ICONINFO info;
|
||||
if (GetIconInfo(hicon, &info))
|
||||
{
|
||||
if (info.hbmMask)
|
||||
{
|
||||
hr = ConvertToPARGB32(hdc, pargb, info.hbmMask, sizIcon, cxRow);
|
||||
DeleteObject(info.hbmMask);
|
||||
}
|
||||
|
||||
DeleteObject(info.hbmColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
bool BitmapUtils::HasAlpha(__in Gdiplus::ARGB *pargb, SIZE& sizImage, int cxRow) const
|
||||
{
|
||||
ULONG cxDelta = cxRow - sizImage.cx;
|
||||
for (ULONG y = sizImage.cy; y; --y)
|
||||
{
|
||||
for (ULONG x = sizImage.cx; x; --x)
|
||||
{
|
||||
if (*pargb++ & 0xFF000000)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
pargb += cxDelta;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
HRESULT BitmapUtils::ConvertToPARGB32(HDC hdc, __inout Gdiplus::ARGB *pargb, HBITMAP hbmp, SIZE& sizImage, int cxRow) const
|
||||
{
|
||||
BITMAPINFO bmi;
|
||||
SecureZeroMemory(&bmi, sizeof(bmi));
|
||||
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmi.bmiHeader.biPlanes = 1;
|
||||
bmi.bmiHeader.biCompression = BI_RGB;
|
||||
|
||||
bmi.bmiHeader.biWidth = sizImage.cx;
|
||||
bmi.bmiHeader.biHeight = sizImage.cy;
|
||||
bmi.bmiHeader.biBitCount = 32;
|
||||
|
||||
HANDLE hHeap = GetProcessHeap();
|
||||
void *pvBits = HeapAlloc(hHeap, 0, bmi.bmiHeader.biWidth * 4 * bmi.bmiHeader.biHeight);
|
||||
if (pvBits == 0)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
HRESULT hr = E_UNEXPECTED;
|
||||
if (GetDIBits(hdc, hbmp, 0, bmi.bmiHeader.biHeight, pvBits, &bmi, DIB_RGB_COLORS) == bmi.bmiHeader.biHeight)
|
||||
{
|
||||
ULONG cxDelta = cxRow - bmi.bmiHeader.biWidth;
|
||||
Gdiplus::ARGB *pargbMask = static_cast<Gdiplus::ARGB *>(pvBits);
|
||||
|
||||
for (ULONG y = bmi.bmiHeader.biHeight; y; --y)
|
||||
{
|
||||
for (ULONG x = bmi.bmiHeader.biWidth; x; --x)
|
||||
{
|
||||
if (*pargbMask++)
|
||||
{
|
||||
// transparent pixel
|
||||
*pargb++ = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// opaque pixel
|
||||
*pargb++ |= 0xFF000000;
|
||||
}
|
||||
}
|
||||
pargb += cxDelta;
|
||||
}
|
||||
|
||||
hr = S_OK;
|
||||
}
|
||||
HeapFree(hHeap, 0, pvBits);
|
||||
|
||||
return hr;
|
||||
}
|
36
shellext/bitmap_utils.h
Normal file
36
shellext/bitmap_utils.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef BITMAP_UTILS_H
|
||||
#define BITMAP_UTILS_H
|
||||
|
||||
#include <windows.h>
|
||||
#include <map>
|
||||
#include <Uxtheme.h>
|
||||
#include <GdiPlus.h>
|
||||
|
||||
#pragma comment(lib, "UxTheme.lib")
|
||||
|
||||
typedef HRESULT (WINAPI *FN_GetBufferedPaintBits) (HPAINTBUFFER hBufferedPaint, RGBQUAD **ppbBuffer, int *pcxRow);
|
||||
typedef HPAINTBUFFER (WINAPI *FN_BeginBufferedPaint) (HDC hdcTarget, const RECT *prcTarget, BP_BUFFERFORMAT dwFormat, BP_PAINTPARAMS *pPaintParams, HDC *phdc);
|
||||
typedef HRESULT (WINAPI *FN_EndBufferedPaint) (HPAINTBUFFER hBufferedPaint, BOOL fUpdateTarget);
|
||||
|
||||
class BitmapUtils
|
||||
{
|
||||
public:
|
||||
BitmapUtils();
|
||||
~BitmapUtils();
|
||||
HBITMAP IconToBitmapPARGB32(HINSTANCE hInst, UINT uIcon);
|
||||
HBITMAP IconToBitmapPARGB32(HICON hIcon) const;
|
||||
private:
|
||||
HRESULT Create32BitHBITMAP(HDC hdc, const SIZE *psize, __deref_opt_out void **ppvBits, __out HBITMAP* phBmp) const;
|
||||
HRESULT ConvertBufferToPARGB32(HPAINTBUFFER hPaintBuffer, HDC hdc, HICON hicon, SIZE& sizIcon) const;
|
||||
bool HasAlpha(Gdiplus::ARGB *pargb, SIZE& sizImage, int cxRow) const;
|
||||
HRESULT ConvertToPARGB32(HDC hdc, __inout Gdiplus::ARGB *pargb, HBITMAP hbmp, SIZE& sizImage, int cxRow) const;
|
||||
std::map<UINT, HBITMAP> bitmaps_;
|
||||
|
||||
bool IsVistaOrLater() const;
|
||||
HMODULE hUxTheme_;
|
||||
FN_GetBufferedPaintBits pfnGetBufferedPaintBits_;
|
||||
FN_BeginBufferedPaint pfnBeginBufferedPaint_;
|
||||
FN_EndBufferedPaint pfnEndBufferedPaint_;
|
||||
};
|
||||
|
||||
#endif
|
320
shellext/context_menu.cc
Normal file
320
shellext/context_menu.cc
Normal file
@@ -0,0 +1,320 @@
|
||||
#include "context_menu.h"
|
||||
#include "resource.h"
|
||||
|
||||
extern HINSTANCE instance;
|
||||
extern long dll_ref_count;
|
||||
|
||||
#define IDM_PROTECT 0
|
||||
|
||||
/**
|
||||
* ContextMenuExt
|
||||
*/
|
||||
|
||||
ContextMenuExt::ContextMenuExt(void) : ref_count_(1)
|
||||
{
|
||||
InterlockedIncrement(&dll_ref_count);
|
||||
}
|
||||
|
||||
ContextMenuExt::~ContextMenuExt(void)
|
||||
{
|
||||
InterlockedDecrement(&dll_ref_count);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP ContextMenuExt::QueryInterface(REFIID riid, void **ppv)
|
||||
{
|
||||
static const QITAB qit[] =
|
||||
{
|
||||
QITABENT(ContextMenuExt, IContextMenu), //-V221
|
||||
QITABENT(ContextMenuExt, IContextMenu2), //-V221
|
||||
QITABENT(ContextMenuExt, IContextMenu3), //-V221
|
||||
QITABENT(ContextMenuExt, IShellExtInit), //-V221
|
||||
{ 0 },
|
||||
#pragma warning( push )
|
||||
#pragma warning( disable: 4838 )
|
||||
};
|
||||
#pragma warning( pop )
|
||||
return QISearch(this, qit, riid, ppv);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) ContextMenuExt::AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&ref_count_);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) ContextMenuExt::Release()
|
||||
{
|
||||
ULONG res = InterlockedDecrement(&ref_count_);
|
||||
if (!res)
|
||||
delete this;
|
||||
return res;
|
||||
}
|
||||
|
||||
#define GetPIDLFolder(pida) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[0])
|
||||
#define GetPIDLItem(pida, i) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[i+1])
|
||||
|
||||
std::wstring PathName(LPCITEMIDLIST parent, LPCITEMIDLIST child)
|
||||
{
|
||||
IShellFolder *shellFolder = NULL;
|
||||
IShellFolder *parentFolder = NULL;
|
||||
STRRET name;
|
||||
TCHAR * szDisplayName = NULL;
|
||||
std::wstring ret;
|
||||
HRESULT hr;
|
||||
|
||||
hr = ::SHGetDesktopFolder(&shellFolder);
|
||||
if (!SUCCEEDED(hr) || shellFolder == NULL)
|
||||
return ret;
|
||||
if (parent)
|
||||
{
|
||||
hr = shellFolder->BindToObject(parent, 0, IID_IShellFolder, (void**) &parentFolder);
|
||||
if (!SUCCEEDED(hr) || parentFolder == NULL)
|
||||
parentFolder = shellFolder;
|
||||
}
|
||||
else
|
||||
{
|
||||
parentFolder = shellFolder;
|
||||
}
|
||||
|
||||
if ((parentFolder != 0)&&(child != 0))
|
||||
{
|
||||
hr = parentFolder->GetDisplayNameOf(child, SHGDN_NORMAL | SHGDN_FORPARSING, &name);
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
parentFolder->Release();
|
||||
return ret;
|
||||
}
|
||||
hr = StrRetToStr (&name, child, &szDisplayName);
|
||||
if (!SUCCEEDED(hr))
|
||||
return ret;
|
||||
}
|
||||
parentFolder->Release();
|
||||
if (szDisplayName == NULL)
|
||||
{
|
||||
CoTaskMemFree(szDisplayName);
|
||||
return ret;
|
||||
}
|
||||
ret = szDisplayName;
|
||||
CoTaskMemFree(szDisplayName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP ContextMenuExt::Initialize(
|
||||
LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hKeyProgID)
|
||||
{
|
||||
file_names_.clear();
|
||||
if (!pDataObj)
|
||||
return E_INVALIDARG;
|
||||
|
||||
static int g_shellidlist = RegisterClipboardFormat(CFSTR_SHELLIDLIST);
|
||||
|
||||
// get selected files/folders
|
||||
if (pDataObj)
|
||||
{
|
||||
STGMEDIUM medium;
|
||||
FORMATETC fmte = {(CLIPFORMAT)g_shellidlist,
|
||||
(DVTARGETDEVICE FAR *)NULL,
|
||||
DVASPECT_CONTENT,
|
||||
-1,
|
||||
TYMED_HGLOBAL};
|
||||
HRESULT hres = pDataObj->GetData(&fmte, &medium);
|
||||
|
||||
if (SUCCEEDED(hres) && medium.hGlobal)
|
||||
{
|
||||
if (pidlFolder)
|
||||
{
|
||||
FORMATETC etc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
||||
STGMEDIUM stg = { TYMED_HGLOBAL };
|
||||
if ( FAILED( pDataObj->GetData ( &etc, &stg )))
|
||||
{
|
||||
ReleaseStgMedium ( &medium );
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
|
||||
HDROP drop = (HDROP)GlobalLock(stg.hGlobal);
|
||||
if ( NULL == drop )
|
||||
{
|
||||
ReleaseStgMedium ( &stg );
|
||||
ReleaseStgMedium ( &medium );
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
int count = DragQueryFile(drop, (UINT)-1, NULL, 0);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
// find the path length in chars
|
||||
UINT len = DragQueryFile(drop, i, NULL, 0);
|
||||
if (len == 0)
|
||||
continue;
|
||||
TCHAR * szFileName = new TCHAR[len+1];
|
||||
if (0 == DragQueryFile(drop, i, szFileName, len+1))
|
||||
{
|
||||
delete [] szFileName;
|
||||
continue;
|
||||
}
|
||||
file_names_.push_back(szFileName);
|
||||
delete [] szFileName;
|
||||
} // for (int i = 0; i < count; i++)
|
||||
GlobalUnlock ( drop );
|
||||
ReleaseStgMedium ( &stg );
|
||||
}
|
||||
else
|
||||
{
|
||||
//Enumerate PIDLs which the user has selected
|
||||
CIDA* cida = (CIDA*)GlobalLock(medium.hGlobal);
|
||||
LPCITEMIDLIST parent( GetPIDLFolder (cida));
|
||||
|
||||
int count = cida->cidl;
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
LPCITEMIDLIST child (GetPIDLItem (cida, i));
|
||||
file_names_.push_back(PathName(parent, child));
|
||||
} // for (int i = 0; i < count; ++i)
|
||||
GlobalUnlock(medium.hGlobal);
|
||||
}
|
||||
|
||||
ReleaseStgMedium ( &medium );
|
||||
if (medium.pUnkForRelease)
|
||||
{
|
||||
IUnknown* relInterface = (IUnknown*)medium.pUnkForRelease;
|
||||
relInterface->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return file_names_.empty() ? E_FAIL : S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP ContextMenuExt::QueryContextMenu(
|
||||
HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
|
||||
{
|
||||
if (CMF_DEFAULTONLY & uFlags)
|
||||
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));
|
||||
|
||||
MENUITEMINFOW mii = {};
|
||||
mii.cbSize = sizeof(mii);
|
||||
mii.fMask = MIIM_BITMAP | MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_STATE;
|
||||
mii.wID = idCmdFirst + IDM_PROTECT;
|
||||
mii.fType = MFT_STRING;
|
||||
mii.dwTypeData = L"Protect with VMProtect";
|
||||
mii.fState = MFS_ENABLED;
|
||||
mii.hbmpItem = utils_.IconToBitmapPARGB32(instance, IDI_ICON);
|
||||
if (!InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
|
||||
MENUITEMINFOW sep = {};
|
||||
sep.cbSize = sizeof(sep);
|
||||
sep.fMask = MIIM_TYPE;
|
||||
sep.fType = MFT_SEPARATOR;
|
||||
if (!InsertMenuItemW(hMenu, indexMenu + 1, TRUE, &sep))
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
|
||||
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(IDM_PROTECT + 1));
|
||||
}
|
||||
|
||||
IFACEMETHODIMP ContextMenuExt::InvokeCommand(LPCMINVOKECOMMANDINFO command_info)
|
||||
{
|
||||
if (HIWORD(command_info->lpVerb))
|
||||
return E_INVALIDARG;
|
||||
|
||||
switch (LOWORD(command_info->lpVerb)) {
|
||||
case IDM_PROTECT:
|
||||
{
|
||||
wchar_t module_name[MAX_PATH];
|
||||
if (GetModuleFileNameW(instance, module_name, _countof(module_name)) != 0) {
|
||||
wchar_t *name = NULL;
|
||||
wchar_t *ptr = module_name;
|
||||
while (*ptr) {
|
||||
if (*ptr == '/' || *ptr == '\\')
|
||||
name = ptr + 1;
|
||||
ptr++;
|
||||
}
|
||||
if (name) {
|
||||
wcscpy_s(name, module_name + MAX_PATH - name - 1, L"VMProtect.exe"); //-V782
|
||||
for (size_t i = 0; i < file_names_.size(); i++) {
|
||||
wchar_t file_name[MAX_PATH * 2 + 2];
|
||||
wnsprintf(file_name, MAX_PATH * 2, L"\"%s\" \"%s\"", module_name, file_names_[i].c_str());
|
||||
PROCESS_INFORMATION pi = PROCESS_INFORMATION();
|
||||
STARTUPINFO si = STARTUPINFO();
|
||||
if (!CreateProcessW(module_name, file_name, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
|
||||
MessageBoxW(command_info->hwnd, L"Error executing VMProtect", L"Error", MB_ICONERROR | MB_OK);
|
||||
break;
|
||||
}
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP ContextMenuExt::GetCommandString(UINT_PTR idCommand,
|
||||
UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax)
|
||||
{
|
||||
if (idCommand == IDM_PROTECT) {
|
||||
switch (uFlags) {
|
||||
case GCS_HELPTEXTA:
|
||||
strncpy_s(reinterpret_cast<PSTR>(pszName), cchMax, "Protect with VMProtect", cchMax);
|
||||
return S_OK;
|
||||
case GCS_HELPTEXTW:
|
||||
wcsncpy_s(reinterpret_cast<PWSTR>(pszName), cchMax, L"Protect with VMProtect", cchMax);
|
||||
return S_OK;
|
||||
default:
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
}
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP ContextMenuExt::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
LRESULT res;
|
||||
return HandleMenuMsg2(uMsg, wParam, lParam, &res);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP ContextMenuExt::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
|
||||
{
|
||||
LRESULT res;
|
||||
if (!pResult)
|
||||
pResult = &res;
|
||||
*pResult = FALSE;
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_MEASUREITEM:
|
||||
{
|
||||
MEASUREITEMSTRUCT* lpmis = (MEASUREITEMSTRUCT*)lParam;
|
||||
if (lpmis==NULL)
|
||||
break;
|
||||
lpmis->itemWidth += 2;
|
||||
if(lpmis->itemHeight < 16)
|
||||
lpmis->itemHeight = 16;
|
||||
*pResult = TRUE;
|
||||
}
|
||||
break;
|
||||
case WM_DRAWITEM:
|
||||
{
|
||||
DRAWITEMSTRUCT* lpdis = (DRAWITEMSTRUCT*)lParam;
|
||||
if (!lpdis || (lpdis->CtlType != ODT_MENU))
|
||||
break; //not for a menu
|
||||
HICON icon = static_cast<HICON>(LoadImageW(instance, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR));
|
||||
if (!icon)
|
||||
break;
|
||||
DrawIconEx(lpdis->hDC,
|
||||
1,
|
||||
lpdis->rcItem.top + (lpdis->rcItem.bottom - lpdis->rcItem.top - 16) / 2,
|
||||
icon, 16, 16,
|
||||
0, 0, DI_NORMAL);
|
||||
DestroyIcon(icon);
|
||||
*pResult = TRUE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
return NOERROR;
|
||||
}
|
44
shellext/context_menu.h
Normal file
44
shellext/context_menu.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#ifndef CONTEXT_H
|
||||
#define CONTEXT_H
|
||||
|
||||
#include <windows.h>
|
||||
#pragma warning( disable : 4091 )
|
||||
#include <shlobj.h>
|
||||
#include <shlwapi.h>
|
||||
#pragma warning( default : 4091 )
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "bitmap_utils.h"
|
||||
|
||||
#pragma comment(lib, "shlwapi.lib")
|
||||
|
||||
class ContextMenuExt : public IShellExtInit, public IContextMenu3
|
||||
{
|
||||
public:
|
||||
// IUnknown
|
||||
IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
||||
IFACEMETHODIMP_(ULONG) AddRef();
|
||||
IFACEMETHODIMP_(ULONG) Release();
|
||||
|
||||
// IShellExtInit
|
||||
IFACEMETHODIMP Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hKeyProgID);
|
||||
|
||||
// IContextMenu
|
||||
IFACEMETHODIMP QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
|
||||
IFACEMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO command_info);
|
||||
IFACEMETHODIMP GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax);
|
||||
IFACEMETHODIMP HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
IFACEMETHODIMP HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* pResult);
|
||||
|
||||
ContextMenuExt(void);
|
||||
|
||||
protected:
|
||||
~ContextMenuExt(void);
|
||||
|
||||
private:
|
||||
long ref_count_;
|
||||
BitmapUtils utils_;
|
||||
std::vector<std::wstring> file_names_;
|
||||
};
|
||||
|
||||
#endif
|
197
shellext/main.cc
Normal file
197
shellext/main.cc
Normal file
@@ -0,0 +1,197 @@
|
||||
#include "main.h"
|
||||
#include "initguid.h"
|
||||
#include "context_menu.h"
|
||||
#include <shlwapi.h>
|
||||
|
||||
long dll_ref_count = 0;
|
||||
HMODULE instance = NULL;
|
||||
|
||||
// {6416B534-5A38-47BA-A8DB-4253F49DC7D3}
|
||||
DEFINE_GUID(CLSID_VMPContextMenu,
|
||||
0x6416B534, 0x5A38, 0x47BA, 0xA8, 0xDB, 0x42, 0x53, 0xF4, 0x9D, 0xC7, 0xD3);
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)
|
||||
{
|
||||
switch (dwReason) {
|
||||
case DLL_PROCESS_ATTACH:
|
||||
instance = hModule;
|
||||
DisableThreadLibraryCalls(hModule);
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* export functions
|
||||
*/
|
||||
|
||||
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
|
||||
{
|
||||
if (IsEqualCLSID(CLSID_VMPContextMenu, rclsid)) {
|
||||
ClassFactory *class_factory;
|
||||
try {
|
||||
class_factory = new ClassFactory();
|
||||
} catch(...) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
if (class_factory) {
|
||||
HRESULT res = class_factory->QueryInterface(riid, ppv);
|
||||
class_factory->Release();
|
||||
return res;
|
||||
} else {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
}
|
||||
return CLASS_E_CLASSNOTAVAILABLE;
|
||||
}
|
||||
|
||||
STDAPI DllCanUnloadNow(void)
|
||||
{
|
||||
return dll_ref_count ? S_FALSE : S_OK;
|
||||
}
|
||||
|
||||
static HRESULT SetRegistryKeyAndValue(HKEY root, PCWSTR sub_key, PCWSTR value_name, PCWSTR data)
|
||||
{
|
||||
HKEY key = NULL;
|
||||
HRESULT res = HRESULT_FROM_WIN32(RegCreateKeyExW(root, sub_key, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, NULL));
|
||||
if (SUCCEEDED(res)) {
|
||||
if (data) {
|
||||
DWORD size = lstrlenW(data) * sizeof(*data);
|
||||
res = HRESULT_FROM_WIN32(RegSetValueExW(key, value_name, 0, REG_SZ, reinterpret_cast<const BYTE *>(data), size));
|
||||
}
|
||||
RegCloseKey(key);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static HRESULT GetRegistryKeyAndValue(HKEY root, PCWSTR sub_key, PCWSTR value_name, PWSTR data, DWORD size)
|
||||
{
|
||||
HKEY key = NULL;
|
||||
HRESULT res = HRESULT_FROM_WIN32(RegOpenKeyExW(root, sub_key, 0, KEY_READ, &key));
|
||||
if (SUCCEEDED(res)){
|
||||
res = HRESULT_FROM_WIN32(RegQueryValueExW(key, value_name, NULL, NULL, reinterpret_cast<BYTE *>(data), &size));
|
||||
RegCloseKey(key);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static wchar_t *shell_ext_name = L"VMProtect Shell Extension";
|
||||
static wchar_t *cls_id_mask = L"CLSID\\%s";
|
||||
static wchar_t *cls_id_inproc_mask = L"CLSID\\%s\\InprocServer32";
|
||||
static wchar_t *context_menu_key_name = L"*\\shellex\\ContextMenuHandlers\\VMProtect";
|
||||
|
||||
STDAPI DllRegisterServer(void)
|
||||
{
|
||||
wchar_t file_name[MAX_PATH];
|
||||
if (GetModuleFileNameW(instance, file_name, _countof(file_name)) == 0)
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
|
||||
wchar_t cls_id[MAX_PATH];
|
||||
StringFromGUID2(CLSID_VMPContextMenu, cls_id, _countof(cls_id));
|
||||
|
||||
wchar_t sub_key[MAX_PATH];
|
||||
wsprintfW(sub_key, cls_id_mask, cls_id);
|
||||
HRESULT res = SetRegistryKeyAndValue(HKEY_CLASSES_ROOT, sub_key, NULL, shell_ext_name);
|
||||
if (SUCCEEDED(res)) {
|
||||
wsprintfW(sub_key, cls_id_inproc_mask, cls_id);
|
||||
res = SetRegistryKeyAndValue(HKEY_CLASSES_ROOT, sub_key, NULL, file_name);
|
||||
}
|
||||
if (SUCCEEDED(res))
|
||||
res = SetRegistryKeyAndValue(HKEY_CLASSES_ROOT, sub_key, L"ThreadingModel", L"Apartment");
|
||||
if (SUCCEEDED(res))
|
||||
res = SetRegistryKeyAndValue(HKEY_CLASSES_ROOT, context_menu_key_name, NULL, cls_id);
|
||||
return res;
|
||||
}
|
||||
|
||||
STDAPI DllUnregisterServer(void)
|
||||
{
|
||||
wchar_t cls_id[MAX_PATH];
|
||||
StringFromGUID2(CLSID_VMPContextMenu, cls_id, _countof(cls_id));
|
||||
|
||||
wchar_t sub_key[MAX_PATH];
|
||||
wsprintfW(sub_key, cls_id_inproc_mask, cls_id);
|
||||
HRESULT res = HRESULT_FROM_WIN32(RegDeleteKeyW(HKEY_CLASSES_ROOT, sub_key));
|
||||
if (SUCCEEDED(res)) {
|
||||
wsprintfW(sub_key, cls_id_mask, cls_id);
|
||||
res = HRESULT_FROM_WIN32(RegDeleteKeyW(HKEY_CLASSES_ROOT, sub_key));
|
||||
}
|
||||
if (SUCCEEDED(res))
|
||||
res = HRESULT_FROM_WIN32(RegDeleteKeyW(HKEY_CLASSES_ROOT, context_menu_key_name));
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* ClassFactory
|
||||
*/
|
||||
|
||||
ClassFactory::ClassFactory()
|
||||
: ref_count_(1)
|
||||
{
|
||||
InterlockedIncrement(&dll_ref_count);
|
||||
}
|
||||
|
||||
ClassFactory::~ClassFactory()
|
||||
{
|
||||
InterlockedDecrement(&dll_ref_count);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP ClassFactory::QueryInterface(REFIID riid, void **ppv)
|
||||
{
|
||||
static const QITAB qit[] =
|
||||
{
|
||||
QITABENT(ClassFactory, IClassFactory), //-V221
|
||||
{ 0 },
|
||||
#pragma warning( push )
|
||||
#pragma warning( disable: 4838 )
|
||||
};
|
||||
#pragma warning( pop )
|
||||
return QISearch(this, qit, riid, ppv);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) ClassFactory::AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&ref_count_);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) ClassFactory::Release()
|
||||
{
|
||||
ULONG res = InterlockedDecrement(&ref_count_);
|
||||
if (!res)
|
||||
delete this;
|
||||
return res;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP ClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv)
|
||||
{
|
||||
if (pUnkOuter)
|
||||
return CLASS_E_NOAGGREGATION;
|
||||
|
||||
ContextMenuExt *ext;
|
||||
try {
|
||||
ext = new ContextMenuExt();
|
||||
} catch (...) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
if (ext) {
|
||||
HRESULT res = ext->QueryInterface(riid, ppv);
|
||||
ext->Release();
|
||||
return res;
|
||||
} else {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
IFACEMETHODIMP ClassFactory::LockServer(BOOL lock)
|
||||
{
|
||||
if (lock)
|
||||
InterlockedIncrement(&dll_ref_count);
|
||||
else
|
||||
InterlockedDecrement(&dll_ref_count);
|
||||
return S_OK;
|
||||
}
|
25
shellext/main.h
Normal file
25
shellext/main.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef MAIN_H
|
||||
#define MAIN_H
|
||||
|
||||
#include <unknwn.h>
|
||||
|
||||
class ClassFactory : public IClassFactory
|
||||
{
|
||||
public:
|
||||
// IUnknown
|
||||
IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
||||
IFACEMETHODIMP_(ULONG) AddRef();
|
||||
IFACEMETHODIMP_(ULONG) Release();
|
||||
|
||||
// IClassFactory
|
||||
IFACEMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv);
|
||||
IFACEMETHODIMP LockServer(BOOL fLock);
|
||||
|
||||
ClassFactory();
|
||||
protected:
|
||||
~ClassFactory();
|
||||
private:
|
||||
long ref_count_;
|
||||
};
|
||||
|
||||
#endif
|
1
shellext/resource.h
Normal file
1
shellext/resource.h
Normal file
@@ -0,0 +1 @@
|
||||
#define IDI_ICON 101
|
5
shellext/shellext.def
Normal file
5
shellext/shellext.def
Normal file
@@ -0,0 +1,5 @@
|
||||
EXPORTS
|
||||
DllGetClassObject PRIVATE
|
||||
DllCanUnloadNow PRIVATE
|
||||
DllRegisterServer PRIVATE
|
||||
DllUnregisterServer PRIVATE
|
BIN
shellext/shellext.rc
Normal file
BIN
shellext/shellext.rc
Normal file
Binary file not shown.
Reference in New Issue
Block a user