In case anyone is looking for closure to this SB_SETTEXTW débâcle... it only took 4 hours, and a heck of a lot of perusing MSDN pages, but I got there in the end. I won't go into excruciating detail about what is going on here, but suffice it to say that the original method is much easier.
In short: The SB_SETTEXTW method requires allocating space within the x2 process to store the status-text, and finally calling the SendMessage with the address of that memory. Along the way there's all sorts of crazy stuff to do just that. Technically speaking, the temporary privilege adjustment employed here ("SeDebugPrivilege") of the calling process may not be strictly necessary on single-accounts, but it's useful to know how to do nonetheless.
The following is a stripped down version (for clarity, no error-checking/recovery code is included) of "the hard way" using C and WinAPI.
Special thanks to
namsupo for pointing me in the proper direction, and thus giving me experience with learning a half-dozen extra API functions. I need sleep.
Code: Select all
#include <windows.h>
#include <Commctrl.h>
#define STATUSBAR 59393
BOOL SetPrivilege(HANDLE hToken, LPCTSTR Privilege, BOOL bEnablePrivilege) {
TOKEN_PRIVILEGES tp = { 0 };
LUID luid;
if (!LookupPrivilegeValue(NULL, Privilege, &luid))
return FALSE;
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = bEnablePrivilege ? SE_PRIVILEGE_ENABLED : 0;
AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
if (GetLastError() != ERROR_SUCCESS)
return FALSE;
return TRUE;
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) {
HWND hWin = FindWindowW(L"ATL:ExplorerFrame", NULL);
if (!hWin) return 0;
wchar_t *StatusBarText = L"Carthago delenda est... and the End is Nigh";
HANDLE hToken, hProcess;
DWORD dwProcessId;
GetWindowThreadProcessId(hWin, &dwProcessId);
OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken);
SetPrivilege(hToken, SE_DEBUG_NAME, TRUE);
hProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, TRUE, dwProcessId);
SetPrivilege(hToken, SE_DEBUG_NAME, FALSE);
size_t Bytes = (wcslen(StatusBarText) + 1) * sizeof(wchar_t);
LPVOID lpMemory = VirtualAllocEx(hProcess, NULL, Bytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(hProcess, lpMemory, StatusBarText, Bytes, NULL);
SetForegroundWindow(hWin);
HWND hStatusBar = GetDlgItem(hWin, STATUSBAR);
if (hStatusBar) SendMessageW(hStatusBar, SB_SETTEXTW, (WPARAM) 0, (LPARAM) lpMemory);
VirtualFreeEx(hProcess, lpMemory, 0, MEM_RELEASE);
CloseHandle(hToken);
CloseHandle(hProcess);
return 1;
}