You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
399 lines
9.5 KiB
399 lines
9.5 KiB
//
|
|
// Generic Windows program template
|
|
//
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <windows.h>
|
|
|
|
#include <winddi.h>
|
|
#include <tchar.h>
|
|
#include <winbase.h>
|
|
#include <winreg.h>
|
|
|
|
CHAR* programName; // program name
|
|
HINSTANCE appInstance; // handle to the application instance
|
|
|
|
LPSTR driverName = "Microsoft Mirror Driver";
|
|
|
|
LPSTR dispCode[7] = {
|
|
"Change Successful",
|
|
"Must Restart",
|
|
"Bad Flags",
|
|
"Bad Parameters",
|
|
"Failed",
|
|
"Bad Mode",
|
|
"Not Updated"};
|
|
|
|
LPSTR GetDispCode(INT code)
|
|
{
|
|
switch (code) {
|
|
|
|
case DISP_CHANGE_SUCCESSFUL: return dispCode[0];
|
|
|
|
case DISP_CHANGE_RESTART: return dispCode[1];
|
|
|
|
case DISP_CHANGE_BADFLAGS: return dispCode[2];
|
|
|
|
case DISP_CHANGE_BADPARAM: return dispCode[3];
|
|
|
|
case DISP_CHANGE_FAILED: return dispCode[4];
|
|
|
|
case DISP_CHANGE_BADMODE: return dispCode[5];
|
|
|
|
case DISP_CHANGE_NOTUPDATED: return dispCode[6];
|
|
|
|
default:
|
|
static char tmp[MAX_PATH];
|
|
sprintf(&tmp[0],"Unknown code: %08x\n", code);
|
|
return (LPTSTR)&tmp[0];
|
|
|
|
}
|
|
|
|
return NULL; // can't happen
|
|
}
|
|
|
|
//
|
|
// Handle window repaint event
|
|
//
|
|
|
|
VOID
|
|
DoPaint(
|
|
HWND hwnd
|
|
)
|
|
|
|
{
|
|
HDC hdc;
|
|
PAINTSTRUCT ps;
|
|
|
|
hdc = BeginPaint(hwnd, &ps);
|
|
|
|
COLORREF red = 0x00FF0000;
|
|
|
|
HBRUSH hbr = CreateSolidBrush(red);
|
|
|
|
RECT r;
|
|
r.left = ps.rcPaint.left;
|
|
r.top = ps.rcPaint.top;
|
|
r.right = ps.rcPaint.right;
|
|
r.bottom = ps.rcPaint.bottom;
|
|
|
|
FillRect(hdc, &r, hbr);
|
|
|
|
EndPaint(hwnd, &ps);
|
|
}
|
|
|
|
|
|
//
|
|
// Window callback procedure
|
|
//
|
|
|
|
LRESULT CALLBACK
|
|
MyWindowProc(
|
|
HWND hwnd,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_PAINT:
|
|
DoPaint(hwnd);
|
|
break;
|
|
|
|
case WM_DISPLAYCHANGE:
|
|
{
|
|
WORD cxScreen = LOWORD(lParam);
|
|
WORD cyScreen = HIWORD(lParam);
|
|
WPARAM format = wParam;
|
|
|
|
// Add hook to re-initialize the mirror driver's surface
|
|
|
|
}
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
PostQuitMessage(0);
|
|
break;
|
|
|
|
default:
|
|
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// Create main application window
|
|
//
|
|
|
|
VOID
|
|
CreateMyWindow(
|
|
//********************************************************************
|
|
PCSTR title
|
|
)
|
|
|
|
#define MYWNDCLASSNAME "Mirror Sample"
|
|
|
|
{
|
|
//********************************************************************
|
|
|
|
//
|
|
// Register window class if necessary
|
|
//
|
|
|
|
static BOOL wndclassRegistered = FALSE;
|
|
|
|
if (!wndclassRegistered)
|
|
{
|
|
WNDCLASS wndClass =
|
|
{
|
|
0,
|
|
MyWindowProc,
|
|
0,
|
|
0,
|
|
appInstance,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
MYWNDCLASSNAME
|
|
};
|
|
|
|
RegisterClass(&wndClass);
|
|
wndclassRegistered = TRUE;
|
|
}
|
|
|
|
HWND hwnd;
|
|
INT width = 300, height = 300;
|
|
|
|
//********************************************************************
|
|
|
|
hwnd = CreateWindow(
|
|
MYWNDCLASSNAME,
|
|
title,
|
|
WS_OVERLAPPED | WS_SYSMENU | WS_VISIBLE,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
width,
|
|
height,
|
|
NULL,
|
|
NULL,
|
|
appInstance,
|
|
NULL);
|
|
|
|
if (hwnd == NULL)
|
|
{
|
|
printf("Can't create main window.\n");
|
|
exit(-1);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Main program entrypoint
|
|
//
|
|
|
|
VOID _cdecl
|
|
main(
|
|
INT argc,
|
|
CHAR **argv
|
|
)
|
|
|
|
{
|
|
programName = *argv++;
|
|
argc--;
|
|
appInstance = GetModuleHandle(NULL);
|
|
|
|
//
|
|
// Create the main application window
|
|
//
|
|
//********************************************************************
|
|
|
|
DEVMODE devmode;
|
|
|
|
FillMemory(&devmode, sizeof(DEVMODE), 0);
|
|
|
|
devmode.dmSize = sizeof(DEVMODE);
|
|
devmode.dmDriverExtra = 0;
|
|
|
|
BOOL change = EnumDisplaySettings(NULL,
|
|
ENUM_CURRENT_SETTINGS,
|
|
&devmode);
|
|
|
|
devmode.dmFields = DM_BITSPERPEL |
|
|
DM_PELSWIDTH |
|
|
DM_PELSHEIGHT;
|
|
|
|
if (change)
|
|
{
|
|
// query all display devices in the system until we hit
|
|
// our favourate mirrored driver, then extract the device name string
|
|
// of the format '\\.\DISPLAY#'
|
|
|
|
DISPLAY_DEVICE dispDevice;
|
|
|
|
FillMemory(&dispDevice, sizeof(DISPLAY_DEVICE), 0);
|
|
|
|
dispDevice.cb = sizeof(DISPLAY_DEVICE);
|
|
|
|
LPSTR deviceName = NULL;
|
|
|
|
devmode.dmDeviceName[0] = '\0';
|
|
|
|
INT devNum = 0;
|
|
BOOL result;
|
|
|
|
while (result = EnumDisplayDevices(NULL,
|
|
devNum,
|
|
&dispDevice,
|
|
0))
|
|
{
|
|
if (strcmp(&dispDevice.DeviceString[0], driverName) == 0)
|
|
break;
|
|
|
|
devNum++;
|
|
}
|
|
|
|
if (!result)
|
|
{
|
|
printf("No '%s' found.\n", driverName);
|
|
exit(0);
|
|
}
|
|
|
|
printf("DevNum:%d\nName:%s\nString:%s\nID:%s\nKey:%s\n\n",
|
|
devNum,
|
|
&dispDevice.DeviceName[0],
|
|
&dispDevice.DeviceString[0],
|
|
&dispDevice.DeviceID[0],
|
|
&dispDevice.DeviceKey[0]);
|
|
|
|
CHAR deviceNum[MAX_PATH];
|
|
LPSTR deviceSub;
|
|
|
|
// Simply extract 'DEVICE#' from registry key. This will depend
|
|
// on how many mirrored devices your driver has and which ones
|
|
// you intend to use.
|
|
|
|
_strupr(&dispDevice.DeviceKey[0]);
|
|
|
|
deviceSub = strstr(&dispDevice.DeviceKey[0],
|
|
"\\DEVICE");
|
|
|
|
if (!deviceSub)
|
|
strcpy(&deviceNum[0], "DEVICE0");
|
|
else
|
|
strcpy(&deviceNum[0], ++deviceSub);
|
|
|
|
// Add 'Attach.ToDesktop' setting.
|
|
//
|
|
|
|
HKEY hKeyProfileMirror = (HKEY)0;
|
|
if (RegCreateKey(HKEY_LOCAL_MACHINE,
|
|
_T("SYSTEM\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet\\Services\\mirror"),
|
|
&hKeyProfileMirror) != ERROR_SUCCESS)
|
|
{
|
|
printf("Can't access registry.\n");
|
|
return;
|
|
}
|
|
|
|
HKEY hKeyDevice = (HKEY)0;
|
|
if (RegCreateKey(hKeyProfileMirror,
|
|
_T(&deviceNum[0]),
|
|
&hKeyDevice) != ERROR_SUCCESS)
|
|
{
|
|
printf("Can't access DEVICE# hardware profiles key.\n");
|
|
return;
|
|
}
|
|
|
|
DWORD one = 1;
|
|
if (RegSetValueEx(hKeyDevice,
|
|
_T("Attach.ToDesktop"),
|
|
0,
|
|
REG_DWORD,
|
|
(unsigned char *)&one,
|
|
4) != ERROR_SUCCESS)
|
|
{
|
|
printf("Can't set Attach.ToDesktop to 0x1\n");
|
|
return;
|
|
}
|
|
|
|
strcpy((LPSTR)&devmode.dmDeviceName[0], "mirror");
|
|
deviceName = (LPSTR)&dispDevice.DeviceName[0];
|
|
|
|
// add 'Default.*' settings to the registry under above hKeyProfile\mirror\device
|
|
INT code =
|
|
ChangeDisplaySettingsEx(deviceName,
|
|
&devmode,
|
|
NULL,
|
|
CDS_UPDATEREGISTRY,
|
|
NULL
|
|
);
|
|
|
|
printf("Update Register on device mode: %s\n", GetDispCode(code));
|
|
|
|
code = ChangeDisplaySettingsEx(deviceName,
|
|
&devmode,
|
|
NULL,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
printf("Raw dynamic mode change on device mode: %s\n", GetDispCode(code));
|
|
|
|
HDC hdc = CreateDC("DISPLAY",
|
|
deviceName,
|
|
NULL,
|
|
NULL);
|
|
|
|
// we should be hooked as layered at this point
|
|
HDC hdc2 = CreateCompatibleDC(hdc);
|
|
|
|
// call DrvCreateDeviceBitmap
|
|
HBITMAP hbm = CreateCompatibleBitmap(hdc, 100, 100);
|
|
|
|
SelectObject(hdc2, hbm);
|
|
|
|
BitBlt(hdc2, 0, 0, 50, 50, hdc, 0, 0, SRCCOPY);
|
|
|
|
// delete the device context
|
|
DeleteDC(hdc2);
|
|
DeleteDC(hdc);
|
|
//
|
|
// CreateMyWindow("Mirror Sample");
|
|
// ^^^^ Use this to test catching window initializiation messages.
|
|
//
|
|
|
|
// Disable attachment to desktop so we aren't attached on
|
|
// the next bootup. Our test app is done!
|
|
|
|
DWORD zero = 0;
|
|
if (RegSetValueEx(hKeyDevice,
|
|
_T("Attach.ToDesktop"),
|
|
0,
|
|
REG_DWORD,
|
|
(unsigned char *)&zero,
|
|
4) != ERROR_SUCCESS)
|
|
{
|
|
printf("Can't set Attach.ToDesktop to 0x0\n");
|
|
return;
|
|
}
|
|
|
|
RegCloseKey(hKeyProfileMirror);
|
|
RegCloseKey(hKeyDevice);
|
|
|
|
printf("Performed bit blit. Finished. \n");
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
printf("Can't get display settings.\n");
|
|
}
|
|
|
|
return;
|
|
}
|