windows-nt/Source/XPSP1/NT/shell/cpls/deskadp/deskadp.cpp
2020-09-26 16:20:57 +08:00

805 lines
21 KiB
C++

/******************************************************************************
Source File: deskadp.cpp
Main code for the advanced desktop adapter page
Copyright (c) 1997-1998 by Microsoft Corporation
Change History:
12-16-97 AndreVa - Created It
******************************************************************************/
#include "deskadp.h"
#define DECL_CRTFREE
#include <crtfree.h>
#include "shfusion.h"
DWORD ApplyNowThd(LPVOID lpThreadParameter);
//
// The function DevicePropertiesW() is implemented in DevMgr.dll; Since we don't have a devmgr.h, we
// explicitly declare it here.
//
typedef int (WINAPI *DEVPROPERTIESW)(
HWND hwndParent,
LPCTSTR MachineName,
LPCTSTR DeviceID,
BOOL ShowDeviceTree
);
// OLE-Registry magic number
// 42071712-76d4-11d1-8b24-00a0c9068ff3
//
GUID g_CLSID_CplExt = { 0x42071712, 0x76d4, 0x11d1,
{ 0x8b, 0x24, 0x00, 0xa0, 0xc9, 0x06, 0x8f, 0xf3}
};
DESK_EXTENSION_INTERFACE DeskInterface;
static const DWORD sc_AdapterHelpIds[] =
{
ID_ADP_ADPINFGRP, IDH_DISPLAY_SETTINGS_ADVANCED_ADAPTER_ADAPTER_INFO,
ID_ADP_AI1, IDH_DISPLAY_SETTINGS_ADVANCED_ADAPTER_ADAPTER_INFO,
ID_ADP_AI2, IDH_DISPLAY_SETTINGS_ADVANCED_ADAPTER_ADAPTER_INFO,
ID_ADP_AI3, IDH_DISPLAY_SETTINGS_ADVANCED_ADAPTER_ADAPTER_INFO,
ID_ADP_AI4, IDH_DISPLAY_SETTINGS_ADVANCED_ADAPTER_ADAPTER_INFO,
ID_ADP_AI5, IDH_DISPLAY_SETTINGS_ADVANCED_ADAPTER_ADAPTER_INFO,
ID_ADP_CHIP, IDH_DISPLAY_SETTINGS_ADVANCED_ADAPTER_ADAPTER_INFO,
ID_ADP_DAC, IDH_DISPLAY_SETTINGS_ADVANCED_ADAPTER_ADAPTER_INFO,
ID_ADP_MEM, IDH_DISPLAY_SETTINGS_ADVANCED_ADAPTER_ADAPTER_INFO,
ID_ADP_ADP_STRING, IDH_DISPLAY_SETTINGS_ADVANCED_ADAPTER_ADAPTER_INFO,
ID_ADP_BIOS_INFO, IDH_DISPLAY_SETTINGS_ADVANCED_ADAPTER_ADAPTER_INFO,
ID_ADP_ADPGRP, IDH_DISPLAY_SETTINGS_ADVANCED_ADAPTER_ADAPTER_TYPE,
IDI_ADAPTER, IDH_DISPLAY_SETTINGS_ADVANCED_ADAPTER_ADAPTER_TYPE,
ID_ADP_ADAPTOR, IDH_DISPLAY_SETTINGS_ADVANCED_ADAPTER_ADAPTER_TYPE,
IDC_LIST_ALL, IDH_DISPLAY_SETTINGS_ADVANCED_ADAPTER_LIST_MODES,
IDC_PROPERTIES, IDH_DISPLAY_SETTINGS_ADVANCED_ADAPTER_PROPERTIES,
0, 0
};
static const DWORD sc_ListAllHelpIds[] =
{
ID_MODE_LIST, IDH_DISPLAY_SETTINGS_ADVANCED_ADAPTER_LISTMODE_DIALOGBOX,
ID_MODE_LISTGRP, IDH_DISPLAY_SETTINGS_ADVANCED_ADAPTER_LISTMODE_DIALOGBOX,
0, 0
};
///////////////////////////////////////////////////////////////////////////////
//
// Messagebox wrapper
//
///////////////////////////////////////////////////////////////////////////////
int
FmtMessageBox(
HWND hwnd,
UINT fuStyle,
DWORD dwTitleID,
DWORD dwTextID)
{
TCHAR Title[256];
TCHAR Text[1500];
LoadString(g_hInst, dwTextID, Text, ARRAYSIZE(Text));
LoadString(g_hInst, dwTitleID, Title, ARRAYSIZE(Title));
return (MessageBox(hwnd, Text, Title, fuStyle));
}
///////////////////////////////////////////////////////////////////////////////
//
// Main dialog box Windows Proc
//
///////////////////////////////////////////////////////////////////////////////
INT_PTR
CALLBACK
ListAllModesProc(
HWND hDlg,
UINT uMessage,
WPARAM wParam,
LPARAM lParam
)
{
LPDEVMODEW lpdm, lpdmCur;
HWND hList;
DWORD i;
LRESULT item;
switch (uMessage)
{
case WM_INITDIALOG:
//
// Save the lParam - we will store the new mode here
//
SetWindowLongPtr(hDlg, DWLP_USER, lParam);
lpdmCur = *((LPDEVMODEW *)lParam);
Assert (lpdmCur != NULL);
//
// Build the list of modes to display
//
i = 0;
hList = GetDlgItem(hDlg, ID_MODE_LIST);
while (lpdm = DeskInterface.lpfnEnumAllModes(DeskInterface.pContext, i))
{
TCHAR achFreData[50];
TCHAR achFre[50];
TCHAR achStr[80];
TCHAR achText[120];
DWORD idColor;
DWORD idFreq;
//
// convert bit count to number of colors and make it a string
//
switch (lpdm->dmBitsPerPel)
{
case 32: idColor = IDS_MODE_TRUECOLOR32; break;
case 24: idColor = IDS_MODE_TRUECOLOR24; break;
case 16: idColor = IDS_MODE_16BIT_COLOR; break;
case 15: idColor = IDS_MODE_15BIT_COLOR; break;
case 8: idColor = IDS_MODE_8BIT_COLOR; break;
case 4: idColor = IDS_MODE_4BIT_COLOR; break;
default:
FmtMessageBox(hDlg,
MB_OK | MB_ICONINFORMATION,
IDS_BAD_COLOR,
IDS_BAD_COLOR);
EndDialog(hDlg, -1);
break;
}
if (lpdm->dmDisplayFrequency == 0)
{
FmtMessageBox(hDlg,
MB_OK | MB_ICONINFORMATION,
IDS_BAD_REFRESH,
IDS_BAD_REFRESH);
EndDialog(hDlg, -1);
break;
}
else if (lpdm->dmDisplayFrequency == 1)
{
LoadString(g_hInst, IDS_MODE_REFRESH_DEF, achFre, ARRAYSIZE(achFre));
}
else
{
if (lpdm->dmDisplayFrequency <= 50)
idFreq = IDS_MODE_REFRESH_INT;
else
idFreq = IDS_MODE_REFRESH_HZ;
LoadString(g_hInst, idFreq, achFreData, ARRAYSIZE(achFreData));
wsprintf(achFre, achFreData, lpdm->dmDisplayFrequency);
}
LoadString(g_hInst, idColor, achStr, ARRAYSIZE(achStr));
wsprintf(achText, achStr, lpdm->dmPelsWidth, lpdm->dmPelsHeight, achFre);
item = ListBox_AddString(hList, achText);
if (lpdm == lpdmCur)
ListBox_SetCurSel(hList, item);
ListBox_SetItemData(hList, item, lpdm);
i++;
}
//
// If no modes are available, put up a popup and exit.
//
if (i == 0)
{
EndDialog(hDlg, -1);
}
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_MODE_LIST:
if (HIWORD(wParam) != LBN_DBLCLK)
{
return FALSE;
}
//
// fall through, as DBLCLK means select.
//
case IDOK:
//
// Save the mode back
//
item = SendDlgItemMessage(hDlg, ID_MODE_LIST, LB_GETCURSEL, 0, 0);
if ((item != LB_ERR) &&
(lpdm = (LPDEVMODEW) SendDlgItemMessage(hDlg, ID_MODE_LIST, LB_GETITEMDATA, item, 0)))
{
*((LPDEVMODEW *)GetWindowLongPtr(hDlg, DWLP_USER)) = lpdm;
EndDialog(hDlg, TRUE);
break;
}
//
// fall through
//
case IDCANCEL:
EndDialog(hDlg, FALSE);
break;
default:
return FALSE;
}
break;
case WM_HELP:
WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle,
TEXT("display.hlp"),
HELP_WM_HELP,
(DWORD_PTR)(LPTSTR)sc_ListAllHelpIds);
break;
case WM_CONTEXTMENU:
WinHelp((HWND)wParam,
TEXT("display.hlp"),
HELP_CONTEXTMENU,
(DWORD_PTR)(LPTSTR)sc_ListAllHelpIds);
break;
default:
return FALSE;
}
return TRUE;
}
void Adaptor_OnApply(HWND hDlg)
{
HINSTANCE hInst;
LPDISPLAY_SAVE_SETTINGS lpfnDisplaySaveSettings = NULL;
long lRet = PSNRET_INVALID_NOCHANGEPAGE;
hInst = LoadLibrary(TEXT("desk.cpl"));
if (hInst)
{
lpfnDisplaySaveSettings = (LPDISPLAY_SAVE_SETTINGS)
GetProcAddress(hInst, "DisplaySaveSettings");
if (lpfnDisplaySaveSettings)
{
LONG lSave = lpfnDisplaySaveSettings(DeskInterface.pContext, hDlg);
if (lSave == DISP_CHANGE_SUCCESSFUL)
{
//
// Save the current mode - to restore it in case the user cancels the p. sheet
//
LPDEVMODEW lpdmOnCancel = DeskInterface.lpfnGetSelectedMode(DeskInterface.pContext);
SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)lpdmOnCancel);
lRet = PSNRET_NOERROR;
}
else if (lSave == DISP_CHANGE_RESTART)
{
//
// User wants to reboot system.
//
PropSheet_RestartWindows(GetParent(hDlg));
lRet = PSNRET_NOERROR;
}
}
FreeLibrary(hInst);
}
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, lRet);
}
void Adaptor_OnInitDialog(HWND hDlg)
{
Assert (DeskInterface.cbSize == 0);
//
// Get the CPL extension interfaces from IDataObject.
//
FORMATETC fmte = {(CLIPFORMAT)RegisterClipboardFormat(DESKCPLEXT_INTERFACE),
(DVTARGETDEVICE FAR *) NULL,
DVASPECT_CONTENT,
-1,
TYMED_HGLOBAL};
STGMEDIUM stgm;
HRESULT hres = g_lpdoTarget->GetData(&fmte, &stgm);
if (SUCCEEDED(hres) && stgm.hGlobal)
{
//
// The storage now contains Display device path (\\.\DisplayX) in UNICODE.
//
PDESK_EXTENSION_INTERFACE pInterface =
(PDESK_EXTENSION_INTERFACE) GlobalLock(stgm.hGlobal);
if (pInterface != NULL)
{
RtlCopyMemory(&DeskInterface,
pInterface,
min(pInterface->cbSize,
sizeof(DESK_EXTENSION_INTERFACE)));
GlobalUnlock(stgm.hGlobal);
SendDlgItemMessageW(hDlg, ID_ADP_CHIP, WM_SETTEXT, 0, (LPARAM)&(DeskInterface.Info.ChipType[0]));
SendDlgItemMessageW(hDlg, ID_ADP_DAC, WM_SETTEXT, 0, (LPARAM)&(DeskInterface.Info.DACType[0]));
SendDlgItemMessageW(hDlg, ID_ADP_MEM, WM_SETTEXT, 0, (LPARAM)&(DeskInterface.Info.MemSize[0]));
SendDlgItemMessageW(hDlg, ID_ADP_ADP_STRING, WM_SETTEXT, 0, (LPARAM)&(DeskInterface.Info.AdapString[0]));
SendDlgItemMessageW(hDlg, ID_ADP_BIOS_INFO, WM_SETTEXT, 0, (LPARAM)&(DeskInterface.Info.BiosString[0]));
//
// Save the initial selected mode - to restore it in case the user cancels the p. sheet
//
LPDEVMODEW lpdmOnCancel = DeskInterface.lpfnGetSelectedMode(DeskInterface.pContext);
SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)lpdmOnCancel);
}
ReleaseStgMedium(&stgm);
}
//
// Get device description from IDataObject.
//
LPWSTR pDeviceDescription;
FORMATETC fmte2 = {(CLIPFORMAT)RegisterClipboardFormat(DESKCPLEXT_DISPLAY_NAME),
(DVTARGETDEVICE FAR *) NULL,
DVASPECT_CONTENT,
-1,
TYMED_HGLOBAL};
hres = g_lpdoTarget->GetData(&fmte2, &stgm);
if (SUCCEEDED(hres) && stgm.hGlobal)
{
pDeviceDescription = (LPWSTR) GlobalLock(stgm.hGlobal);
SendDlgItemMessageW(hDlg, ID_ADP_ADAPTOR, WM_SETTEXT, 0, (LPARAM)pDeviceDescription);
GlobalUnlock(stgm.hGlobal);
ReleaseStgMedium(&stgm);
}
//
// Enable/disable the properties button
//
BOOL bEnable = FALSE;
LPWSTR pwDeviceID = NULL;
FORMATETC fmte3 = {(CLIPFORMAT)RegisterClipboardFormat(DESKCPLEXT_DISPLAY_ID),
(DVTARGETDEVICE FAR *)NULL,
DVASPECT_CONTENT,
-1,
TYMED_HGLOBAL};
hres = g_lpdoTarget->GetData(&fmte3, &stgm);
if (SUCCEEDED(hres) && stgm.hGlobal)
{
pwDeviceID = (LPWSTR)GlobalLock(stgm.hGlobal);
bEnable = ((pwDeviceID != NULL) && (*pwDeviceID != L'\0'));
GlobalUnlock(stgm.hGlobal);
ReleaseStgMedium(&stgm);
}
HWND hPropButton = GetDlgItem(hDlg, IDC_PROPERTIES);
if (hPropButton != NULL)
EnableWindow(hPropButton, bEnable);
}
void Adaptor_OnCancel(HWND hDlg)
{
//
// Restore initial mode
//
LPDEVMODEW lpdmOnCancel = (LPDEVMODEW) GetWindowLongPtr(hDlg, DWLP_USER);
DeskInterface.lpfnSetSelectedMode(DeskInterface.pContext, lpdmOnCancel);
}
void Adaptor_OnListAllModes(HWND hDlg)
{
LPDEVMODEW lpdmBefore, lpdmAfter;
lpdmAfter = lpdmBefore = DeskInterface.lpfnGetSelectedMode(DeskInterface.pContext);
if (DialogBoxParam(g_hInst,
MAKEINTRESOURCE(DLG_SET_MODE_LIST),
hDlg,
ListAllModesProc,
(LPARAM) &lpdmAfter) == 1 &&
lpdmAfter && (lpdmAfter != lpdmBefore))
{
//
// If the user selected a new setting, tell the property sheet
// we have outstanding changes. This will enable the Apply button.
//
PropSheet_Changed(GetParent(hDlg), hDlg);
DeskInterface.lpfnSetSelectedMode(DeskInterface.pContext, lpdmAfter);
}
}
void Adaptor_OnProperties(HWND hDlg)
{
// Invoke the device manager property sheets to show the properties of the
// given hardware.
LPWSTR pwDeviceID;
HRESULT hres;
STGMEDIUM stgm;
FORMATETC fmte2 = {(CLIPFORMAT)RegisterClipboardFormat(DESKCPLEXT_DISPLAY_ID),
(DVTARGETDEVICE FAR *) NULL,
DVASPECT_CONTENT,
-1,
TYMED_HGLOBAL};
hres = g_lpdoTarget->GetData(&fmte2, &stgm);
if (SUCCEEDED(hres) && stgm.hGlobal)
{
pwDeviceID = (LPWSTR) GlobalLock(stgm.hGlobal);
HINSTANCE hinstDevMgr = LoadLibrary(TEXT("DEVMGR.DLL"));
if (hinstDevMgr)
{
DEVPROPERTIESW pfnDevPropW =
(DEVPROPERTIESW)GetProcAddress(hinstDevMgr, "DevicePropertiesW");
if (pfnDevPropW)
{
//Display the property sheets for this device.
(*pfnDevPropW)(hDlg, NULL, pwDeviceID, FALSE);
}
FreeLibrary(hinstDevMgr);
}
GlobalUnlock(stgm.hGlobal);
ReleaseStgMedium(&stgm);
}
}
#if TEST_MODE
void Adaptor_OnTestMode(HWND hDlg)
{
//
// Warn the user
//
if (FmtMessageBox(hDlg,
MB_OKCANCEL | MB_ICONINFORMATION,
IDS_TEST_MODE,
IDS_TEST_WARNING) == IDCANCEL) {
return;
}
//
// The user wants to test his new selection. We need to
// create a new desktop with the selected resolution, switch
// to it, and put up a dialog box so he can see if it works with
// his hardware.
//
// All this needs to be done in a separate thread since you can't
// switch a thread with open windows to a new desktop.
//
//
// Create the test thread. It will do the work of creating the desktop
//
//
// Get device name from IDataObject.
//
LPWSTR pDeviceName = NULL;
FORMATETC fmte = {(CLIPFORMAT)RegisterClipboardFormat(DESKCPLEXT_DISPLAY_DEVICE),
(DVTARGETDEVICE FAR *) NULL,
DVASPECT_CONTENT,
-1,
TYMED_HGLOBAL};
STGMEDIUM stgm;
HRESULT hres = g_lpdoTarget->GetData(&fmte, &stgm);
if (SUCCEEDED(hres) && stgm.hGlobal) {
//
// The storage now contains Display device path (\\.\DisplayX) in UNICODE.
//
pDeviceName = (LPWSTR) GlobalLock(stgm.hGlobal);
}
desktopParam.lpdevmode = DeskInterface.lpfnGetSelectedMode(DeskInterface.pContext);
desktopParam.pwszDevice = pDeviceName;
hThread = CreateThread(NULL,
4096,
ApplyNowThd,
(LPVOID) (&desktopParam),
SYNCHRONIZE | THREAD_QUERY_INFORMATION,
&idThread);
WaitForSingleObject(hThread, INFINITE);
GetExitCodeThread(hThread, &bTest);
//
// clean up memory
//
if (pDeviceName)
{
GlobalUnlock(stgm.hGlobal);
ReleaseStgMedium(&stgm);
}
CloseHandle(hThread);
if (!bTest)
{
FmtMessageBox(hDlg,
MB_ICONEXCLAMATION | MB_OK,
IDS_TEST_MODE,
IDS_TEST_FAILED);
}
SetForegroundWindow(hDlg);
}
#endif
//---------------------------------------------------------------------------
//
// PropertySheeDlgProc()
//
// The dialog procedure for the "Adapter" property sheet page.
//
//---------------------------------------------------------------------------
INT_PTR
CALLBACK
PropertySheeDlgProc(
HWND hDlg,
UINT uMessage,
WPARAM wParam,
LPARAM lParam
)
{
switch (uMessage)
{
case WM_INITDIALOG:
RtlZeroMemory(&DeskInterface, sizeof(DESK_EXTENSION_INTERFACE));
if (!g_lpdoTarget)
{
return FALSE;
}
else
{
Adaptor_OnInitDialog(hDlg);
}
break;
case WM_COMMAND:
if (DeskInterface.cbSize > 0)
{
switch( LOWORD(wParam) )
{
#if TEST_MODE
case IDC_TEST_MODE:
Adaptor_OnTestMode(hDlg);
break;
#endif
case IDC_LIST_ALL:
Adaptor_OnListAllModes(hDlg);
break;
case IDC_PROPERTIES:
Adaptor_OnProperties(hDlg);
break;
default:
return FALSE;
}
}
break;
case WM_NOTIFY:
if (DeskInterface.cbSize > 0)
{
switch (((NMHDR FAR *)lParam)->code)
{
case PSN_APPLY:
Adaptor_OnApply(hDlg);
break;
case PSN_RESET:
Adaptor_OnCancel(hDlg);
break;
default:
return FALSE;
}
}
break;
case WM_HELP:
WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle,
TEXT("display.hlp"),
HELP_WM_HELP,
(DWORD_PTR)(LPTSTR)sc_AdapterHelpIds);
break;
case WM_CONTEXTMENU:
WinHelp((HWND)wParam,
TEXT("display.hlp"),
HELP_CONTEXTMENU,
(DWORD_PTR)(LPTSTR)sc_AdapterHelpIds);
break;
default:
return FALSE;
}
return TRUE;
}
//
// This functionality has been deprectaed by the new style of testing a video
// settings (apply the changes, bring up a countdown dialog to confirm). If
// need to dipslay a bmp still exists, import TestDisplaySettings from desk.cpl
// via LoadLibrary and GetProcAddress...
//
#if TEST_MODE
/****************************************************************************\
*
* DWORD WINAPI ApplyNowThd(LPVOID lpThreadParameter)
*
* Thread that gets started when the use hits the Apply Now button.
* This thread creates a new desktop with the new video mode, switches to it
* and then displays a dialog box asking if the display looks OK. If the
* user does not respond within the time limit, then 'NO' is assumed to be
* the answer.
*
\****************************************************************************/
DWORD ApplyNowThd(LPVOID lpThreadParameter)
{
PNEW_DESKTOP_PARAM lpDesktopParam = (PNEW_DESKTOP_PARAM) lpThreadParameter;
HDESK hdsk = NULL;
HDESK hdskDefault = NULL;
BOOL bTest = FALSE;
HDC hdc;
//
// HACK:
// We need to make a USER call before calling the desktop stuff so we can
// sure our threads internal data structure are associated with the default
// desktop.
// Otherwise USER has problems closing the desktop with our thread on it.
//
GetSystemMetrics(SM_CXSCREEN);
//
// Create the desktop
//
hdskDefault = GetThreadDesktop(GetCurrentThreadId());
if (hdskDefault != NULL) {
hdsk = CreateDesktopW(L"Display.Cpl Desktop",
lpDesktopParam->pwszDevice,
lpDesktopParam->lpdevmode,
0,
MAXIMUM_ALLOWED,
NULL);
if (hdsk != NULL) {
//
// use the desktop for this thread
//
if (SetThreadDesktop(hdsk)) {
hdc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
if (hdc) {
DrawBmp(hdc);
DeleteDC(hdc);
bTest = TRUE;
}
//
// Sleep for some seconds so you have time to look at the screen.
//
Sleep(7000);
}
}
//
// Reset the thread to the right desktop
//
SetThreadDesktop(hdskDefault);
SwitchDesktop(hdskDefault);
//
// Can only close the desktop after we have switched to the new one.
//
if (hdsk != NULL)
CloseDesktop(hdsk);
}
ExitThread((DWORD) bTest);
return 0;
}
#endif