first commit

Version 3.x.x
This commit is contained in:
VNGhostMans
2023-05-14 20:21:09 +07:00
parent a3037a8db3
commit 5ec92ee05e
1166 changed files with 1036539 additions and 0 deletions

241
shellext/bitmap_utils.cc Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View File

@@ -0,0 +1 @@
#define IDI_ICON 101

5
shellext/shellext.def Normal file
View File

@@ -0,0 +1,5 @@
EXPORTS
DllGetClassObject PRIVATE
DllCanUnloadNow PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE

BIN
shellext/shellext.rc Normal file

Binary file not shown.