Windows* 8 Desktop App - Desktop Rotation Sample Whitepaper

 

Download Article and Source


 Windows* 8 Desktop App - Desktop Rotation Sample Whitepaper [PDF 426KB]
Windows 8 Desktop App Sample Page

Introduction

The Desktop Rotation sample app shows how screen orientation changes can be detected in the desktop environment. The app uses reported values to modify the window display.

Desktop Rotation Application Code and Explanations


The Desktop Rotation app (Desktop_Rotation.cpp) is written in C++. When the code starts, the app creates a default dimensions window with three child windows arranged in a preset way. The app detects screen rotation, modifies parent window size to hardcoded values, changes window orientation, and rearranges child windows in a different preset way.

C++ Functions


MyRegisterClass()

When the Desktop Rotation app is launched, MyRegisterClass() is called to register the main window class.

ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;
	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style		= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra	= 0;
	wcex.cbWndExtra	= 0;
	wcex.hInstance	= hInstance;
wcex.hIcon	= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_DESKTOP_ROTATION));
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_DESKTOP_ROTATION);
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

	return RegisterClassEx(&wcex);
}

InitInstancePortrait(HINSTANCE, int)


This function saves the instance handle in a global variable and creates and displays the main program window and three MDI child windows on app launch when the device is rotated to portrait mode. In Portrait mode the child windows are arranged vertically on top of one another.

BOOL InitInstancePortrait(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // Store instance handle in our global variable

   CLIENTCREATESTRUCT ccs;

   ccs.hWindowMenu  = GetSubMenu(GetMenu(hWnd), 2);
   ccs.idFirstChild = ID_MDI_FIRSTCHILD;

   // Create Frame Window
   hWnd = CreateWindow(szWindowClass, szTitle, 
         WS_OVERLAPPEDWINDOW&~WS_MAXIMIZEBOX&~WS_MINIMIZEBOX,30, 30, 
         700, 700, NULL, NULL, hInstance, NULL);

   // Create MDI Client Window
   hWndMDIClient = CreateWindowEx(WS_EX_CLIENTEDGE, L"mdiclient", NULL,
        WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,
        0, 0, 700, 700, hWnd, (HMENU)IDC_MAIN_MDI, GetModuleHandle(NULL), 
        (LPVOID)&ccs);

   // Create three MDI child windows
   hWndMDIChild1 = CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", L"", 
        WS_CHILD | WS_VISIBLE, 0, 0, 685, 300,
        hWnd, (HMENU)IDC_CHILD_EDIT, GetModuleHandle(NULL), (LPVOID)&ccs);

   hWndMDIChild2 = CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", L"",
        WS_CHILD | WS_VISIBLE, 0, 300, 685, 200,
        hWnd, (HMENU)IDC_CHILD_EDIT, GetModuleHandle(NULL), (LPVOID)&ccs);

   hWndMDIChild3 = CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", L"",
        WS_CHILD | WS_VISIBLE, 0, 500, 685, 200,
        hWnd, (HMENU)IDC_CHILD_EDIT, GetModuleHandle(NULL), (LPVOID)&ccs);

   SetMenu(hWnd, NULL); //Hide menu bar
   ShowWindow(hWnd, nCmdShow);

   ShowWindow(hWndMDIClient, nCmdShow);
   ShowWindow(hWndMDIChild1, nCmdShow);
   ShowWindow(hWndMDIChild2, nCmdShow);
   ShowWindow(hWndMDIChild3, nCmdShow);

   return TRUE;
}

InitInstanceLandscape(HINSTANCE, int)


This function saves the instance handle in a global variable and creates and displays the main program window and three MDI child windows on app launch when the device is rotated to landscape mode. In Landscape mode the child windows are arranged in more of a side-by-side fashion to better take advantage of the extra horizontal space.

BOOL InitInstanceLandscape(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // Store instance handle in our global variable

   CLIENTCREATESTRUCT ccs;

   ccs.hWindowMenu  = GetSubMenu(GetMenu(hWnd), 2);
   ccs.idFirstChild = ID_MDI_FIRSTCHILD;

   // Create Frame Window
   hWnd = CreateWindow(szWindowClass, szTitle, 
          WS_OVERLAPPEDWINDOW&~WS_MAXIMIZEBOX&~WS_MINIMIZEBOX,
          30, 30, 700, 700, NULL, NULL, hInstance, NULL);

   // Create MDI Client Window
   hWndMDIClient = CreateWindowEx(WS_EX_CLIENTEDGE, L"mdiclient", NULL,
        WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,
        0, 0, 700, 700, hWnd, (HMENU)IDC_MAIN_MDI, GetModuleHandle(NULL), 
        (LPVOID)&ccs);
 
   // Create three MDI child windows
   hWndMDIChild1 = CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", L"",
        WS_CHILD | WS_VISIBLE, 0, 0, 350, 660, 
        hWnd, (HMENU)IDC_CHILD_EDIT, GetModuleHandle(NULL), (LPVOID)&ccs);

   hWndMDIChild2 = CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", L"",
        WS_CHILD | WS_VISIBLE, 350, 0, 485, 350, 
		hWnd, (HMENU)IDC_CHILD_EDIT, GetModuleHandle(NULL), (LPVOID)&ccs);

   hWndMDIChild3 = CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", L"",
        WS_CHILD | WS_VISIBLE, 350, 350, 485, 310,
        hWnd, (HMENU)IDC_CHILD_EDIT, GetModuleHandle(NULL), (LPVOID)&ccs);

   SetMenu(hWnd, NULL); //Hide menu bar
   ShowWindow(hWnd, nCmdShow);

   ShowWindow(hWndMDIClient, nCmdShow);
   ShowWindow(hWndMDIChild1, nCmdShow);
   ShowWindow(hWndMDIChild2, nCmdShow);
   ShowWindow(hWndMDIChild3, nCmdShow);

   return TRUE;
}

InitInstance(HINSTANCE, int)


This function saves the instance handle in a global variable and creates and displays the main program window and three MDI child windows on app launch. The function detects screen orientation and launches the app either in portrait or landscape mode.

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   DEVMODE devmode;
   //DEVMODE structure
   ZeroMemory(&devmode, sizeof(DEVMODE));
   devmode.dmSize = sizeof(DEVMODE);
   devmode.dmFields = DM_DISPLAYORIENTATION;

   //Check display orientation
   EnumDisplaySettingsEx(NULL, ENUM_CURRENT_SETTINGS, &devmode, EDS_RAWMODE); 

   // Store instance handle in a global variable
   hInst = hInstance; 
   
  if((devmode.dmDisplayOrientation==DMDO_90)||(devmode.dmDisplayOrientation==DMDO_270))
  {
	   InitInstancePortrait(hInst, SW_SHOW);
  }
  else if ((devmode.dmDisplayOrientation == DMDO_DEFAULT) || 
     (devmode.dmDisplayOrientation == DMDO_180))
  {
	   InitInstanceLandscape(hInst, SW_SHOW);
  }

   return TRUE;
}

WndProc(HWND, UINT, WPARAM, LPARAM)

WndProc function processes messages for the main window. WM_COMMAND processes the application menu.
WM_PAINT paints three MDI child windows with embedded images.
WM_DISPLAYCHANGE - changes the main window dimensions and rearranges MDI child windows inside the main window on 90, 180, and 270 degrees rotation. By monitoring WM_DISPLAYCHANGE, the app knows exactly when the desktop has been rotated and can adjust its content for the new mode. Monitoring a sensor could cause the application to rotate when the desktop hasn’t rotated yet or vice versa. When a user rotates the tablet 90, 180, or 270 degrees from the original position, the main and MDI child windows change size and orientation, and MDI child windows get rearranged. WM_DESTROY posts a quit message and returns.

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps1, ps2, ps3;
	HDC hdc1, hdc2, hdc3;

	BITMAP bitmap1, bitmap2, bitmap3;
    	HDC hdcMem1, hdcMem2, hdcMem3;
    	HGDIOBJ oldBitmap1, oldBitmap2, oldBitmap3;

	unsigned long scrWidth = 0;
	unsigned long scrHeight = 0;

	HBITMAP hBitmap1 = NULL;
	HBITMAP hBitmap2 = NULL;
	HBITMAP hBitmap3 = NULL;

	RECT rect1; 
	RECT rect2;
	RECT rect3;

	switch (message)
	{
	case WM_COMMAND:
		wmId    = LOWORD(wParam);
		wmEvent = HIWORD(wParam);
		// Parse the menu selections:
		switch LOWORD(wmId)
		{
		case IDM_ABOUT:
			DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
			break;
		case IDM_EXIT:
			DeleteObject(hBitmap1);
			DeleteObject(hBitmap2);
			DeleteObject(hBitmap3);
			DestroyWindow(hWndMDIChild1);
			DestroyWindow(hWndMDIChild2);
			DestroyWindow(hWndMDIChild3);
			DestroyWindow(hWndMDIClient);
			DestroyWindow(hWnd);		
			break;
		default:
	        return DefFrameProc(hWnd, hWndMDIClient, message, wParam, lParam);
		}
		break;
	case WM_PAINT:
		// *** Paint Child Window 1 *** //
		GetClientRect(hWndMDIChild1, &rect1);

		hdc1 = BeginPaint(hWndMDIChild1, &ps1);

		//create memory DC
		hdcMem1 = CreateCompatibleDC(hdc1); 

		//embed the image into the project
		hBitmap1 = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BITMAP1));
		
		//Select HBITMAP for memory DC.
        	oldBitmap1 = SelectObject(hdcMem1, hBitmap1); 

        	GetObject(hBitmap1, sizeof(bitmap1), &bitmap1);
		//copy image from memory DC to windows DC - display on the screen 
		BitBlt(hdc1, 0, 0, rect1.right-rect1.left, rect1.bottom-rect1.top, 
                       hdcMem1, 0, 0, SRCCOPY); 

        	SelectObject(hdcMem1, oldBitmap1);
        	DeleteDC(hdcMem1);
		DeleteObject(hBitmap1);
		ReleaseDC(hWndMDIChild1, hdc1);
	
		EndPaint(hWndMDIChild1, &ps1);
		
		// *** Paint Child Window 2 *** //
		GetClientRect(hWndMDIChild2, &rect2);

		hdc2 = BeginPaint(hWndMDIChild2, &ps2);

		//create memory DC
		hdcMem2 = CreateCompatibleDC(hdc2); 

		//embed the image into the project
		hBitmap2 = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BITMAP2));
		
		//Select HBITMAP for memory DC.
        	oldBitmap2 = SelectObject(hdcMem2, hBitmap2); 

        	GetObject(hBitmap2, sizeof(bitmap2), &bitmap2);
		//copy image from memory DC to windows DC - display on the screen
		BitBlt(hdc2, 0, 0, rect2.right-rect2.left, rect2.bottom-rect2.top, 
                hdcMem2, 0, 0, SRCCOPY); 

        	SelectObject(hdcMem2, oldBitmap2);
        	DeleteDC(hdcMem2);
		DeleteObject(hBitmap2);
		ReleaseDC(hWndMDIChild2, hdc2);

		EndPaint(hWndMDIChild2, &ps2);

		// *** Paint Child Window 3 *** //
		GetClientRect(hWndMDIChild3, &rect3);

		hdc3 = BeginPaint(hWndMDIChild3, &ps3);

		//create memory DC
		hdcMem3 = CreateCompatibleDC(hdc3); 
		//embed the image into the project
		hBitmap3 = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BITMAP3));
		
		//Select HBITMAP for memory DC.
        	oldBitmap3 = SelectObject(hdcMem3, hBitmap3); 

        	GetObject(hBitmap3, sizeof(bitmap3), &bitmap3);
		//copy image from memory DC to windows DC - display on the screen
		BitBlt(hdc3, 0, 0, rect3.right-rect3.left, rect3.bottom-rect3.top, 
                hdcMem3, 0, 0, SRCCOPY); 

        	SelectObject(hdcMem3, oldBitmap3);
        	DeleteDC(hdcMem3);
		DeleteObject(hBitmap3);
		ReleaseDC(hWndMDIChild3, hdc3);

		EndPaint(hWndMDIChild3, &ps3);
		break;

// case WM_DISPLAYCHANGE: This is the code that detects the display change and 
// determines whether to arrange child window horizontally or vertically.      
	case WM_DISPLAYCHANGE: 
		scrWidth = LOWORD(lParam);
		scrHeight = HIWORD(lParam);

		if(scrWidth < scrHeight)
		{	
			//portrait mode
			MoveWindow(hWnd, 30, 30, 700, 700, TRUE);
			MoveWindow(hWndMDIClient, 0, 0, 700, 700, TRUE);
			MoveWindow(hWndMDIChild1, 0, 0, 685, 300, TRUE);
			MoveWindow(hWndMDIChild2, 0, 300, 685, 200, TRUE);
			MoveWindow(hWndMDIChild3, 0, 500, 685, 200, TRUE);
		}
		else
		{
			//landscape mode
			MoveWindow(hWnd, 30, 30, 700, 700, TRUE);
			MoveWindow(hWndMDIClient, 0, 0, 700, 700, TRUE);
			MoveWindow(hWndMDIChild1, 0, 0, 350, 660, TRUE);
			MoveWindow(hWndMDIChild2, 350, 0, 485, 350, TRUE);
			MoveWindow(hWndMDIChild3, 350, 350, 485, 310, TRUE);
		}
		break;
	case WM_DESTROY:
		DeleteObject(hBitmap1);
		DeleteObject(hBitmap2);
		DeleteObject(hBitmap3);
		DestroyWindow(hWndMDIChild1);
		DestroyWindow(hWndMDIChild2);
		DestroyWindow(hWndMDIChild3);
		DestroyWindow(hWndMDIClient);
		DestroyWindow(hWnd);		
		PostQuitMessage(0);
		break;
	default:
		return DefFrameProc(hWnd, hWndMDIClient, message, wParam, lParam);
	}
	return 0;
}

INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM)

This function is a message handler for an about box.

INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(lParam);
	switch (message)
	{
	case WM_INITDIALOG:
		return (INT_PTR)TRUE;

	case WM_COMMAND:
		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
		{
			EndDialog(hDlg, LOWORD(wParam));
			return (INT_PTR)TRUE;
		}
		break;
	}
	return (INT_PTR)FALSE;
}

Basic Life Cycle


The application starts by creating a parent window with three MDI child windows. The app detects display orientation and opens the window in either portrait or landscape mode. When a user rotates the tablet 90, 180, or 270 degrees from the original position, the app changes the orientation and size of the main and three MDI windows, and rearranges child windows in a different preset way. In Portrait mode the child windows are arranged vertically on top of one another. In Landscape mode the child windows are arranged in more of a side-by-side fashion to better take advantage of the extra horizontal space. By monitoring display changes based on screen width and height, the app knows exactly when the desktop has been rotated and can adjust its content for the new mode. The images indicate where each child window moved.

Nähere Informationen zur Compiler-Optimierung finden Sie in unserem Optimierungshinweis.