Or find the window of the parent process.
Code: Select all
/* CmdBkg (c) 2016 Mikael Sollenborn */
#ifndef UNICODE
#define UNICODE
#endif
#ifndef _UNICODE
#define _UNICODE
#endif
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0600
// Usage: cmdbkg "file.bmp" [transparency 0-100 (default 33) [includeBorders]]
// Specify no arguments to remove previous background.
// Specify /? as first argument to see this help.
// Compilation: gcc -o cmdbkg.exe cmdbkg.c -lgdi32 -ldwmapi -mwindows
// TODO/Issues:
// 1. Allow centered placement of image, no stretching?
// 2. Background window visible a short time after restoring minimized console window. Minimize background if console window is minimized?
// 3. Inelegant polling. Use SetWinEventHook instead?
// 4. Find a better way to kill the old background window than this horrible title polling hack
// 5. Program blocks if run from a batch script, need to use: start "" cmdbkg
#include <windows.h>
#include <stdio.h>
#include <dwmapi.h>
#include <tlhelp32.h>
#define POLL_INTERVAL 20
#define KILL_TITLE_MESSAGE L"Kill"
// structure to be passed to EnumWindows() and EnumWindowsCallback()
typedef struct tag_CALLBACKDATA
{
DWORD pid;
HWND hwnd;
} CALLBACKDATA;
// callback function that is called from EnumWindows() in order to find the main window of a process
BOOL CALLBACK EnumWindowsCallback(HWND hwnd, LPARAM lParam)
{
CALLBACKDATA *pData = (CALLBACKDATA*)lParam;
DWORD process_id = 0;
GetWindowThreadProcessId(hwnd, &process_id);
if (pData->pid == process_id && !GetWindow(hwnd, GW_OWNER))
{
pData->hwnd = hwnd;
return FALSE;
}
return TRUE;
}
// Functions Fn_LoadBmp and f_SetConsoleTransparency by user "aGerman" at dostips.com
int Fn_LoadBmp(HWND hWnd, wchar_t *szBmpPath, long x, long y, long z, long w, long h)
{
HDC hDc = NULL, hDcBmp = NULL;
HBITMAP hBmp1 = NULL, hBmp2 = NULL;
HGDIOBJ hGdiObj = NULL;
BITMAP bmp = {0};
int iRet = EXIT_FAILURE;
if (hWnd)
{
if ((hDc = GetDC(hWnd)))
{
if ((hDcBmp = CreateCompatibleDC(hDc)))
{
if ((hBmp1 = (HBITMAP)LoadImage(NULL, szBmpPath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE)))
{
if (GetObject(hBmp1, sizeof(bmp), &bmp))
{
if (w == -1) {
if ((w = bmp.bmWidth * z / 100.0 + 0.5) <= 0 || (h = bmp.bmHeight * z / 100.0 + 0.5) <= 0)
{
w = bmp.bmWidth;
h = bmp.bmHeight;
}
}
if ((hBmp2 = (HBITMAP)CopyImage((HANDLE)hBmp1, IMAGE_BITMAP, w, h, LR_COPYDELETEORG)))
{
if ((hGdiObj = SelectObject(hDcBmp, hBmp2)) && hGdiObj != HGDI_ERROR)
{
if (BitBlt(hDc, (int)x, (int)y, (int)w, (int)h, hDcBmp, 0, 0, SRCCOPY))
iRet = EXIT_SUCCESS;
DeleteObject(hGdiObj);
}
DeleteObject(hBmp2);
}
}
DeleteObject(hBmp1);
}
ReleaseDC(hWnd, hDcBmp);
}
ReleaseDC(hWnd, hDc);
}
}
return iRet;
}
BOOL f_SetConsoleTransparency(HWND hConsoleWnd, long percentage)
{
BYTE bAlpha = 0;
LONG lNewLong = 0;
if (hConsoleWnd && percentage > -1 && percentage < 101)
{
bAlpha = (BYTE)(2.55 * (100 - percentage) + 0.5);
lNewLong = GetWindowLong(hConsoleWnd, GWL_EXSTYLE) | WS_EX_LAYERED;
if (!SetWindowLong(hConsoleWnd, GWL_EXSTYLE, lNewLong)) return FALSE;
return SetLayeredWindowAttributes(hConsoleWnd, 0, bAlpha, LWA_ALPHA);
}
return FALSE;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
int bx, by, bw, bh, ret;
int nbx, nby, nbw, nbh;
int fw = 0, fh = 0, fth = 0;
HWND hConsoleWnd, hBkgWnd, currFgWnd, tempWnd;
RECT bounds, extendBounds;
LPWSTR *szArgList;
int argCount, initialRedraw = 10, compTitle = 1, transparency = 33;
wchar_t titleBuffer[1024];
WNDCLASS wc={0};
UINT_PTR timerId;
BOOL bIsWeirdoBorders = FALSE;
BOOL res;
MSG msg;
// hConsoleWnd = GetForegroundWindow();
//////////////////////////
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 procentry = {0};
procentry.dwSize = sizeof(PROCESSENTRY32);
DWORD pid = GetCurrentProcessId(), ppid = 0;
if (Process32First(hProcessSnap, &procentry))
{
do
{
if (procentry.th32ProcessID == pid)
ppid = procentry.th32ParentProcessID;
} while (ppid == 0 && Process32Next(hProcessSnap, &procentry));
}
if (hProcessSnap != INVALID_HANDLE_VALUE)
CloseHandle(hProcessSnap);
if (ppid == 0)
{
MessageBox(NULL, L"Unable to find cmd.exe process.", L"Error", MB_OK);
return 1;
}
CALLBACKDATA data = {ppid, NULL};
EnumWindows(EnumWindowsCallback, (LPARAM)&data);
hConsoleWnd = data.hwnd;
//////////////////////////
if (hConsoleWnd) {
GetWindowRect(hConsoleWnd, &bounds);
bx = bounds.left;
by = bounds.top;
bw = bounds.right-bounds.left;
bh = bounds.bottom-bounds.top;
} else {
MessageBox(NULL, L"Unable to prepare window creation", L"Error", MB_OK);
return 1;
}
DwmGetWindowAttribute(hConsoleWnd, DWMWA_EXTENDED_FRAME_BOUNDS, &extendBounds, sizeof(extendBounds));
if (extendBounds.left != bounds.left) bIsWeirdoBorders = TRUE;
szArgList = CommandLineToArgvW(GetCommandLine(), &argCount);
if (szArgList == NULL)
{
MessageBox(NULL, L"Unable to get arguments", L"Error", MB_OK);
return 1;
}
if (argCount == 2 && wcscmp(szArgList[1], L"/?") == 0) {
MessageBox(NULL, L"Usage: cmdbkg \"file.bmp\" [transparency 0-100 (default 33) [includeBorders]]\n\nSpecify no arguments to remove previous background.\n\n(C)opyright 2016 Mikael Sollenborn", L"CmdBkg Arguments", MB_OK);
return 0;
}
f_SetConsoleTransparency(hConsoleWnd, 0);
GetWindowText(hConsoleWnd, titleBuffer, 1023);
SetWindowText(hConsoleWnd, KILL_TITLE_MESSAGE);
Sleep(500);
SetWindowText(hConsoleWnd, titleBuffer);
if (argCount < 2) {
f_SetConsoleTransparency(hConsoleWnd, 0);
return 0;
}
if (argCount > 2) {
transparency = wcstol (szArgList[2], NULL, 10);
}
f_SetConsoleTransparency(hConsoleWnd, transparency);
if (argCount <= 3 || (argCount > 3 && bIsWeirdoBorders)) {
fw = GetSystemMetrics(SM_CXSIZEFRAME);
if(argCount <= 3) fth = GetSystemMetrics(SM_CYSIZEFRAME) + GetSystemMetrics(SM_CYCAPTION);
fh = fth + GetSystemMetrics(SM_CYSIZEFRAME);
}
wc.lpszClassName=L"CmdBkgWindowBackground";
wc.lpfnWndProc=DefWindowProc; // Use default Window proc
wc.hInstance=hInstance;
wc.hbrBackground=(HBRUSH)(COLOR_3DFACE+1);
wc.hCursor=LoadCursor(NULL,IDC_ARROW);
if (!RegisterClass(&wc)) { MessageBox(NULL, L"Unable to prepare window creation", L"Error", MB_OK); LocalFree(szArgList); return 1; }
hBkgWnd=CreateWindowEx(0,wc.lpszClassName,0,WS_POPUP|WS_VISIBLE,bx+fw,by+fth,bw-fw*2,bh-fh,0,0,0,0);
if (!hBkgWnd) { MessageBox(NULL, L"Unable to create background window", L"Error", MB_OK); LocalFree(szArgList); return 1; }
ret = Fn_LoadBmp(hBkgWnd, szArgList[1], 0, 0, 100, bw-fw*2, bh-fth);
if (ret == EXIT_FAILURE) { MessageBox(NULL, L"Unable to load bitmap", L"Error", MB_OK); LocalFree(szArgList); return 1; }
ShowWindow(hBkgWnd, SW_HIDE);
SetWindowLongPtr(hBkgWnd, GWL_EXSTYLE, WS_EX_TOOLWINDOW);
ShowWindow(hBkgWnd, SW_SHOW);
SetForegroundWindow(hConsoleWnd);
currFgWnd = GetForegroundWindow();
while((IsWindow(hConsoleWnd) || IsIconic(hConsoleWnd)) && ret == EXIT_SUCCESS && compTitle != 0) {
timerId = SetTimer(NULL, 0, POLL_INTERVAL, NULL);
res = GetMessage(&msg,0,0,0);
KillTimer(NULL, timerId);
if (!(res && msg.message == WM_TIMER && msg.hwnd == NULL && msg.wParam == timerId))
DispatchMessage(&msg);
GetWindowText(hConsoleWnd, titleBuffer, 1023);
compTitle = wcscmp(titleBuffer, KILL_TITLE_MESSAGE);
GetWindowRect(hConsoleWnd, &bounds);
nbx = bounds.left;
nby = bounds.top;
nbw = bounds.right-bounds.left;
nbh = bounds.bottom-bounds.top;
tempWnd = GetForegroundWindow();
if (currFgWnd != tempWnd) {
if (initialRedraw < 5) initialRedraw = 5;
currFgWnd = tempWnd;
}
SetWindowPos(hBkgWnd, hConsoleWnd, nbx+fw, nby+fth, nbw-fw*2, nbh-fh, SWP_SHOWWINDOW);
if (initialRedraw > 0 || nbx != bx || nby != by || nbw != bw || nbh != bh) {
int w = nbw-fw*2, h = nbh-fth;
if (w < 1) w = 1;
if (h < 1) h = 1;
ret = Fn_LoadBmp(hBkgWnd, szArgList[1], 0, 0, 100, w, h);
bx = nbx; by = nby; bw = nbw; bh = nbh;
if (initialRedraw > 0) initialRedraw--;
}
}
LocalFree(szArgList);
return 0;
}
//EDIT slightly changed ...