//
// 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;
}