225 lines
6.4 KiB
C++
225 lines
6.4 KiB
C++
|
/*
|
||
|
* genthunk - Generic thunks
|
||
|
*/
|
||
|
|
||
|
#ifndef WIN32
|
||
|
|
||
|
#include "tweakui.h"
|
||
|
|
||
|
const char CODESEG szKernel32[] = "KERNEL32";
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* hwnd32Hwnd converts a 16-bit hwnd to a 32-bit hwnd. Note that we
|
||
|
* extend with 0xFFFF to be compatible with NT.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
#define hwnd32Hwnd(hwnd) MAKELONG(hwnd, 0xFFFF)
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* CallProcEx32W (a.k.a. ThunkMeHarder)
|
||
|
*
|
||
|
* Generic wrapper for thunking.
|
||
|
*
|
||
|
* lpszDll -> ASCIIZ DLL name
|
||
|
* lpszProc -> ASCIIZ procedure name
|
||
|
* c = number of arguments
|
||
|
* dwMask = bitmask; if argument N is a pointer, then bit c-N is set.
|
||
|
* Yes, it's backwards.
|
||
|
* arg0, arg1, arg2, ... = arguments
|
||
|
*
|
||
|
* Returns whatever the procedure returns, or 0 on error.
|
||
|
*
|
||
|
* To aid in building dwMask, the macro ARGPTR(k,n) builds the
|
||
|
* appropriate bitmask that indicates that argument k of n is
|
||
|
* a pointer. k is zero-based, of course.
|
||
|
*
|
||
|
* This is pretty gross evil code that is Intel x86-specific.
|
||
|
* But hey, it's Win16. That's to be expected.
|
||
|
*
|
||
|
* CallProc32W is insane. It's a variadic function that uses
|
||
|
* the pascal calling convention. (It probably makes more sense
|
||
|
* when you're stoned.)
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
DWORD PASCAL GetProcAddressEx32W(DWORD hinst, LPCSTR lpsz);
|
||
|
|
||
|
DWORD WINAPI LoadLibraryEx32W(LPCSTR lpszLib, DWORD dw1, DWORD dw2);
|
||
|
DWORD WINAPI GetProcAddress32W(DWORD hinst, LPCSTR lpsz);
|
||
|
DWORD WINAPI FreeLibrary32W(DWORD hinst);
|
||
|
DWORD WINAPI CallProc32W(DWORD pfn, DWORD dwMask, DWORD c);
|
||
|
|
||
|
#define CallProcEx32W ThunkMeHarder
|
||
|
#define ARGPTR(k,n) (1<<(n-k-1))
|
||
|
|
||
|
DWORD _cdecl
|
||
|
ThunkMeHarder(LPCSTR lpszDll, LPCSTR lpszProc, UINT c, DWORD dwMask, ...)
|
||
|
{
|
||
|
DWORD dwRc = 0;
|
||
|
DWORD hdll, pfn;
|
||
|
if (SELECTOROF(lpszDll) ?
|
||
|
(HIWORD(hdll = LoadLibraryEx32W(lpszDll, 0, 0)) &&
|
||
|
HIWORD(pfn = GetProcAddressEx32W(hdll, lpszProc)))
|
||
|
: (hdll = 0, pfn = (DWORD)lpszProc, 1)) {
|
||
|
_asm {
|
||
|
mov cx, c /* cx = number of arguments */
|
||
|
xor si, si /* si = number of bytes pushed */
|
||
|
jcxz PushesDone
|
||
|
PushHarder:
|
||
|
_emit 0x66 /* 32-bit override */
|
||
|
push word ptr dwMask[4+si]
|
||
|
add si, 4
|
||
|
loop PushHarder
|
||
|
PushesDone:
|
||
|
}
|
||
|
dwRc = CallProc32W(pfn, dwMask, c);
|
||
|
}
|
||
|
if (HIWORD(hdll)) FreeLibrary32W(hdll);
|
||
|
return dwRc;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* GetProcAddressEx32W
|
||
|
*
|
||
|
* The same as GetProcAddress32W, except it also understands ordinals.
|
||
|
*
|
||
|
* Yes, this is a rather close relationship we have with ThunkMeHarder,
|
||
|
*
|
||
|
*
|
||
|
* (The Shell VxD does a very similar thing)
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
const char CODESEG szGetProcAddress[] = "GetProcAddress";
|
||
|
|
||
|
DWORD PASCAL
|
||
|
GetProcAddressEx32W(DWORD hinst, LPCSTR lpsz)
|
||
|
{
|
||
|
if (SELECTOROF(lpsz)) { /* Optimization */
|
||
|
return GetProcAddress32W(hinst, lpsz);
|
||
|
} else {
|
||
|
return ThunkMeHarder(szKernel32, szGetProcAddress, 2, 0, hinst, lpsz);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* CopyFile
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
const char CODESEG szCopyFileA[] = "CopyFileA";
|
||
|
|
||
|
BOOL PASCAL
|
||
|
CopyFile(LPCSTR lpszSrc, LPCSTR lpszDst, BOOL fFailExists)
|
||
|
{
|
||
|
return CallProcEx32W(szKernel32, szCopyFileA, 3, ARGPTR(0,3)|ARGPTR(1,3),
|
||
|
lpszSrc, lpszDst, (DWORD)fFailExists) != 0;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* SHChangeNotify
|
||
|
*
|
||
|
* Actually, we are slimy because we *know* that uFlags is always
|
||
|
* SHCNF_PIDL, so no parameters need to be thunked.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
const char CODESEG szSHChangeNotify[] = "SHChangeNotify";
|
||
|
|
||
|
void PASCAL SHChangeNotify(LONG wEventId, UINT uFlags,
|
||
|
const void FAR *dwItem1, const void FAR *dwItem2)
|
||
|
{
|
||
|
CallProcEx32W(szShell32, szSHChangeNotify, 4, 0,
|
||
|
wEventId, (DWORD)uFlags, dwItem1, dwItem2);
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* SHGetSpecialFolderLocation
|
||
|
*
|
||
|
* Ignore the return value; just check the pidl.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
const char CODESEG szSHGetSpecialFolderLocation[]
|
||
|
= "SHGetSpecialFolderLocation";
|
||
|
|
||
|
void PASCAL
|
||
|
SHGetSpecialFolderLocation(HWND hwnd, int nFolder, PIDL FAR *ppidl)
|
||
|
{
|
||
|
CallProcEx32W(szShell32, szSHGetSpecialFolderLocation, 3, ARGPTR(2,3),
|
||
|
hwnd32Hwnd(hwnd), (LONG)nFolder, (LPVOID)ppidl);
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* SHGetPathFromIDList
|
||
|
*
|
||
|
* Ignore the return value; just check the pidl.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
const char CODESEG szSHGetPathFromIDList[] = "SHGetPathFromIDList";
|
||
|
|
||
|
void PASCAL
|
||
|
SHGetPathFromIDList(PIDL pidl, LPSTR pszBuf)
|
||
|
{
|
||
|
CallProcEx32W(szShell32, szSHGetPathFromIDList, 2, ARGPTR(1,2),
|
||
|
pidl, pszBuf);
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* ILFree
|
||
|
*
|
||
|
* This is exported by ordinal.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
void WINAPI
|
||
|
ILFree(PIDL pidl)
|
||
|
{
|
||
|
CallProcEx32W(szShell32, MAKEINTRESOURCE(155), 1, 0, pidl);
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* Shell_GetImageLists
|
||
|
*
|
||
|
* This is exported by ordinal.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
BOOL PASCAL
|
||
|
Shell_GetImageLists(HIMAGELIST FAR *phiml, HIMAGELIST FAR *phimlSmall)
|
||
|
{
|
||
|
return (BOOL)CallProcEx32W(szShell32, MAKEINTRESOURCE(71), 2,
|
||
|
ARGPTR(0,2)|ARGPTR(1,2), phiml, phimlSmall);
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* ExtractIconEx
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
const char CODESEG szExtractIconExA[] = "ExtractIconExA";
|
||
|
|
||
|
int PASCAL
|
||
|
ExtractIconEx(LPCSTR pszFile, int iIcon,
|
||
|
HICON FAR *phiconLarge, HICON FAR *phiconSmall, int nIcons)
|
||
|
{
|
||
|
return (int)CallProcEx32W(szShell32, szExtractIconExA, 5,
|
||
|
ARGPTR(0,5)|ARGPTR(2,5)|ARGPTR(3,5),
|
||
|
pszFile, (LONG)iIcon, phiconLarge, phiconSmall,
|
||
|
(LONG)nIcons);
|
||
|
}
|
||
|
|
||
|
#endif /* !WIN32 */
|