mirror of https://github.com/lianthony/NT4.0
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.
6328 lines
152 KiB
6328 lines
152 KiB
|
|
extern "C" {
|
|
|
|
#include "nt.h"
|
|
#include "ntrtl.h"
|
|
#include "nturtl.h"
|
|
|
|
}
|
|
|
|
#include <windows.h>
|
|
#include <winsecp.h>
|
|
|
|
#include <cplp.h>
|
|
#include "wingdip.h"
|
|
#include "settings.h"
|
|
#include "setinc.h"
|
|
#include "setcdcl.hxx"
|
|
|
|
extern "C" {
|
|
|
|
#include "stdio.h"
|
|
#include "stdlib.h"
|
|
|
|
#include <commctrl.h>
|
|
#include <setupapi.h>
|
|
#include <syssetup.h>
|
|
|
|
#include "shlobj.h" // IsUserAnAdmin
|
|
#include "shellp.h" // IsUserAnAdmin
|
|
|
|
#include "..\..\..\inc\help.h"
|
|
|
|
}
|
|
|
|
/****************************************************************\
|
|
*
|
|
* Global vars and structures used only in this file
|
|
*
|
|
\****************************************************************/
|
|
|
|
TCHAR gpszError[] = TEXT("Unknown Error");
|
|
|
|
extern "C" {
|
|
|
|
extern TCHAR szControlHlp[];
|
|
extern UINT wHelpMessage;
|
|
extern HWND hwndDevModeNotify;
|
|
}
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
|
|
//
|
|
// Currently there is a bug in the system that occationally causes the
|
|
// control panel applet to be resized. The resize causes the control
|
|
// panel to display at about half its usual size, and the user can not
|
|
// see any of the buttons, etc. This code will work around the problem.
|
|
//
|
|
// However, after we ship, we should really determine why this is
|
|
// happening.
|
|
//
|
|
|
|
#define RESIZE_PROBLEM 1
|
|
|
|
#if RESIZE_PROBLEM
|
|
LRESULT WINAPI MyProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
|
|
WNDPROC gOldProc=NULL;
|
|
#endif
|
|
|
|
HWND ghwndPropSheet;
|
|
|
|
ULONG gUnattenedConfigureAtLogon = 0;
|
|
ULONG gUnattenedInstall = 0;
|
|
TCHAR gUnattenedPszInf[512];
|
|
TCHAR gUnattenedPszOption[512];
|
|
ULONG gUnattenedBitsPerPel = 0;
|
|
ULONG gUnattenedXResolution = 0;
|
|
ULONG gUnattenedYResolution = 0;
|
|
ULONG gUnattenedVRefresh = 0;
|
|
ULONG gUnattenedFlags = 0;
|
|
ULONG gUnattenedAutoConfirm = 0;
|
|
|
|
DWORD g_aiSetHelpIds[] = {
|
|
|
|
ID_DSP_CHANGE, IDH_DSKTPMONITOR_CHANGE_DISPLAY,
|
|
ID_DSP_COLORBOX, IDH_DSKTPMONITOR_COLOR,
|
|
ID_DSP_CLRPALGRP, IDH_DSKTPMONITOR_COLOR,
|
|
ID_DSP_COLORBAR, IDH_DSKTPMONITOR_COLOR,
|
|
ID_DSP_AREA_SB, IDH_DSKTPMONITOR_AREA,
|
|
ID_DSP_DSKAREAGRP, IDH_DSKTPMONITOR_AREA,
|
|
ID_DSP_X_BY_Y, IDH_DSKTPMONITOR_AREA,
|
|
ID_DSP_REFFREQGRP, IDH_DSKTPMONITOR_REFRESH,
|
|
ID_DSP_FREQ, IDH_DSKTPMONITOR_REFRESH,
|
|
ID_DSP_LIST_ALL, IDH_DSKTPMONITOR_LIST_MODES,
|
|
IDC_SCREENSAMPLE, IDH_DSKTPMONITOR_MONITOR,
|
|
ID_DSP_TEST, IDH_DSKTPMONITOR_TEST,
|
|
ID_DSP_FONTSIZEGRP, IDH_DSKTPMONITOR_FONTSIZE,
|
|
ID_DSP_FONTSIZE, IDH_DSKTPMONITOR_FONTSIZE,
|
|
ID_ADP_ADPGRP, IDH_DSKTPMONITOR_ADTYPE,
|
|
ID_ADP_ADAPTOR, IDH_DSKTPMONITOR_ADTYPE,
|
|
ID_ADP_CHGADP, IDH_DSKTPMONITOR_CHANGE1,
|
|
ID_ADP_DETECT, IDH_DSKTPMONITOR_DETECT,
|
|
ID_ADP_ADPINFGRP, IDH_DSKTPMONITOR_AD_FACTS,
|
|
ID_ADP_CHIP, IDH_DSKTPMONITOR_AD_FACTS,
|
|
ID_ADP_DAC, IDH_DSKTPMONITOR_AD_FACTS,
|
|
ID_ADP_MEM, IDH_DSKTPMONITOR_AD_FACTS,
|
|
ID_ADP_ADP_STRING, IDH_DSKTPMONITOR_AD_FACTS,
|
|
ID_ADP_BIOS_INFO, IDH_DSKTPMONITOR_AD_FACTS,
|
|
ID_ADP_AI1, IDH_DSKTPMONITOR_AD_FACTS,
|
|
ID_ADP_AI2, IDH_DSKTPMONITOR_AD_FACTS,
|
|
ID_ADP_AI3, IDH_DSKTPMONITOR_AD_FACTS,
|
|
ID_ADP_AI4, IDH_DSKTPMONITOR_AD_FACTS,
|
|
ID_ADP_AI5, IDH_DSKTPMONITOR_AD_FACTS,
|
|
ID_ADP_DRVINFGRP, IDH_DSKTPMONITOR_DRIVER,
|
|
ID_ADP_MANUFACT, IDH_DSKTPMONITOR_DRIVER,
|
|
ID_ADP_VERSION, IDH_DSKTPMONITOR_DRIVER,
|
|
ID_ADP_CURFILES, IDH_DSKTPMONITOR_DRIVER,
|
|
ID_ADP_DI1, IDH_DSKTPMONITOR_DRIVER,
|
|
ID_ADP_DI2, IDH_DSKTPMONITOR_DRIVER,
|
|
ID_ADP_DI3, IDH_DSKTPMONITOR_DRIVER,
|
|
|
|
|
|
// not implemented yet: IDH_DSKTPMONITOR_CUSTOM
|
|
// IDH_DSKTPMONITOR_ENERGY
|
|
// IDH_DSKTPMONITOR_CHANGE2
|
|
// IDH_DSKTPMONITOR_MONTYPE
|
|
0, 0
|
|
};
|
|
|
|
|
|
/*****************************************************************\
|
|
*
|
|
* Pure "C" functions used only in this file
|
|
*
|
|
\*****************************************************************/
|
|
LPTSTR SubStrEnd( LPTSTR pszTarget, LPTSTR pszScan);
|
|
DWORD WINAPI ApplyNowThd( LPVOID lpThreadParameter);
|
|
|
|
/*****************************************************************\
|
|
*
|
|
* List class
|
|
*
|
|
\*****************************************************************/
|
|
|
|
typedef struct tagLISTELEM LISTELEM;
|
|
|
|
struct tagLISTELEM
|
|
{
|
|
LPDEVMODE value;
|
|
LISTELEM *next;
|
|
};
|
|
|
|
class CList
|
|
{
|
|
private:
|
|
LISTELEM *Head;
|
|
|
|
public:
|
|
CList() { Head = (LISTELEM *) NULL; }
|
|
~CList();
|
|
|
|
void Insert(LPDEVMODE p);
|
|
LPDEVMODE Pop();
|
|
void Process();
|
|
|
|
BOOL InOrder(LISTELEM *a, LISTELEM *b);
|
|
BOOL EquivExists(LISTELEM *p);
|
|
};
|
|
|
|
CList::~CList()
|
|
{
|
|
LISTELEM *temp;
|
|
|
|
//
|
|
// We should have removed all elements in the list
|
|
// before the list object was destroyed.
|
|
//
|
|
|
|
ASSERT(Head == NULL);
|
|
}
|
|
|
|
BOOL CList::InOrder(LISTELEM *a, LISTELEM *b)
|
|
{
|
|
//
|
|
// Sort on color depth...
|
|
//
|
|
|
|
if (a->value->dmBitsPerPel != b->value->dmBitsPerPel)
|
|
{
|
|
return (a->value->dmBitsPerPel < b->value->dmBitsPerPel);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// ...then on resolution (area)...
|
|
//
|
|
|
|
if ((a->value->dmPelsWidth * a->value->dmPelsHeight) !=
|
|
(b->value->dmPelsWidth * b->value->dmPelsHeight))
|
|
{
|
|
return ((a->value->dmPelsWidth * a->value->dmPelsHeight) <
|
|
(b->value->dmPelsWidth * b->value->dmPelsHeight));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// ...then on frequency
|
|
//
|
|
|
|
if (a->value->dmDisplayFrequency != b->value->dmDisplayFrequency)
|
|
{
|
|
return (a->value->dmDisplayFrequency < b->value->dmDisplayFrequency);
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CList::Insert(LPDEVMODE p)
|
|
{
|
|
LISTELEM *pElem;
|
|
LISTELEM *pCurrElem;
|
|
|
|
pElem = (LISTELEM *) malloc(sizeof(LISTELEM));
|
|
pElem->value = (LPDEVMODE) malloc(sizeof(DEVMODE) + p->dmDriverExtra);
|
|
|
|
memcpy(pElem->value, p, sizeof(DEVMODE) + p->dmDriverExtra);
|
|
|
|
if (!Head || InOrder(pElem, Head))
|
|
{
|
|
pElem->next = Head;
|
|
Head = pElem;
|
|
}
|
|
else
|
|
{
|
|
pCurrElem = Head;
|
|
|
|
while (pCurrElem->next && !InOrder(pElem, pCurrElem->next))
|
|
{
|
|
pCurrElem = pCurrElem->next;
|
|
}
|
|
|
|
pElem->next = pCurrElem->next;
|
|
pCurrElem->next = pElem;
|
|
}
|
|
}
|
|
|
|
LPDEVMODE CList::Pop()
|
|
{
|
|
LISTELEM *pCurrElem;
|
|
LPDEVMODE ret;
|
|
|
|
if (Head)
|
|
{
|
|
pCurrElem = Head;
|
|
Head = Head->next;
|
|
|
|
ret = pCurrElem->value;
|
|
free(pCurrElem);
|
|
|
|
return ret;
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
BOOL CList::EquivExists(LISTELEM *p)
|
|
{
|
|
LISTELEM *pCurrElem = Head;
|
|
|
|
//
|
|
// We are only looking for equivalent 8bpp modes, so stop
|
|
// looking once we've passed the 8bpp modes.
|
|
//
|
|
|
|
while (pCurrElem && (pCurrElem->value->dmBitsPerPel <= 8))
|
|
{
|
|
if ((p != pCurrElem) && // A will not be considered equivalent to A
|
|
(p->value->dmPelsWidth == pCurrElem->value->dmPelsWidth &&
|
|
p->value->dmPelsHeight == pCurrElem->value->dmPelsHeight))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
pCurrElem = pCurrElem->next;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Lets perform the following operations on the list
|
|
//
|
|
// (1) Remove identical modes
|
|
// (2) Remove 16 color modes for which there is a 256
|
|
// color equivalent.
|
|
// (3) Remove modes with less then 480 scan lines
|
|
//
|
|
|
|
void CList::Process()
|
|
{
|
|
LISTELEM *pCurrElem;
|
|
LISTELEM *pPrevElem;
|
|
LISTELEM *dup;
|
|
HKEY hkeyDriver;
|
|
BOOL bDisplay4BppModes = FALSE;
|
|
|
|
//
|
|
// Check the registry to see if the user wants us
|
|
// to show 16 color modes.
|
|
//
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
SZ_DISPLAY_4BPP_MODES,
|
|
0,
|
|
KEY_READ,
|
|
&hkeyDriver) == ERROR_SUCCESS)
|
|
{
|
|
bDisplay4BppModes = TRUE;
|
|
RegCloseKey(hkeyDriver);
|
|
}
|
|
|
|
pCurrElem = Head;
|
|
|
|
while (pCurrElem)
|
|
{
|
|
//
|
|
// If any of the following conditions are true, then we want to
|
|
// remove the current mode.
|
|
//
|
|
|
|
if (((pCurrElem->next) &&
|
|
(pCurrElem->value->dmBitsPerPel == pCurrElem->next->value->dmBitsPerPel) &&
|
|
(pCurrElem->value->dmPelsWidth == pCurrElem->next->value->dmPelsWidth) &&
|
|
(pCurrElem->value->dmPelsHeight == pCurrElem->next->value->dmPelsHeight) &&
|
|
(pCurrElem->value->dmDisplayFrequency == pCurrElem->next->value->dmDisplayFrequency))
|
|
||
|
|
((pCurrElem->value->dmBitsPerPel == 4) &&
|
|
(!bDisplay4BppModes) &&
|
|
(EquivExists(pCurrElem)))
|
|
||
|
|
(pCurrElem->value->dmPelsHeight < 480))
|
|
{
|
|
dup = pCurrElem;
|
|
|
|
if (pCurrElem == Head)
|
|
{
|
|
Head = pCurrElem->next;
|
|
}
|
|
else
|
|
{
|
|
pPrevElem->next = pCurrElem->next;
|
|
}
|
|
|
|
pCurrElem = pCurrElem->next;
|
|
|
|
free(dup->value);
|
|
free(dup);
|
|
}
|
|
else
|
|
{
|
|
pPrevElem = pCurrElem;
|
|
pCurrElem = pCurrElem->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************\
|
|
*
|
|
* CDEVMODE class
|
|
*
|
|
\*****************************************************************/
|
|
typedef class CDEVMODE *PCDEVMODE;
|
|
|
|
class CDEVMODE {
|
|
|
|
private:
|
|
PCDEVMODE pcdmNext;
|
|
BOOL bTested;
|
|
PDEVMODE pdm;
|
|
|
|
public:
|
|
CDEVMODE() : pdm(NULL), pcdmNext(NULL), bTested(FALSE) {};
|
|
|
|
~CDEVMODE() { if (pcdmNext != NULL) { free(pcdmNext->pdm); delete pcdmNext; } }
|
|
|
|
void AddElement(LPDEVMODE pdm) {
|
|
|
|
PCDEVMODE pcdm = new CDEVMODE;
|
|
|
|
pcdm->pdm = pdm;
|
|
pcdm->pcdmNext = this->pcdmNext;
|
|
this->pcdmNext = pcdm;
|
|
}
|
|
|
|
PCDEVMODE NextDevMode() { return this->pcdmNext; }
|
|
|
|
LPDEVMODE GetData() { return this->pdm; }
|
|
|
|
VOID vTestMode(BOOL bSuccess) { this->bTested = bSuccess; }
|
|
BOOL bModeTested() { return this->bTested; }
|
|
};
|
|
|
|
/*****************************************************************\
|
|
*
|
|
* CDEVMODEIDAT class
|
|
*
|
|
\*****************************************************************/
|
|
typedef class CDEVMODEIDAT *PCDEVMODEIDAT;
|
|
|
|
class CDEVMODEIDAT {
|
|
private:
|
|
PCDEVMODEIDAT pcdmiNext;
|
|
int iRepData1;
|
|
int iRepData2;
|
|
|
|
public:
|
|
CDEVMODEIDAT() : pcdmiNext(NULL), iRepData1(0), iRepData2(0) {};
|
|
CDEVMODEIDAT(int i1, int i2) : pcdmiNext(NULL), iRepData1(i1),
|
|
iRepData2(i2) {};
|
|
|
|
~CDEVMODEIDAT() { if (pcdmiNext != NULL) delete pcdmiNext; }
|
|
|
|
int Index(int i1, int i2);
|
|
BOOL GetData(int iOrd, int *pi1, int *pi2);
|
|
PCDEVMODEIDAT Insert(int i1, int i2);
|
|
};
|
|
|
|
int CDEVMODEIDAT::Index(int i1, int i2) {
|
|
|
|
PCDEVMODEIDAT pcdmi = this;
|
|
int i = 0;
|
|
|
|
while (pcdmi) {
|
|
|
|
if (pcdmi->iRepData1 == i1 && pcdmi->iRepData2 == i2) {
|
|
|
|
return i;
|
|
|
|
} else {
|
|
|
|
i += 1;
|
|
pcdmi = pcdmi->pcdmiNext;
|
|
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
BOOL CDEVMODEIDAT::GetData(int iOrd, int *pi1, int *pi2) {
|
|
if (iOrd == 0) {
|
|
*pi1 = this->iRepData1;
|
|
*pi2 = this->iRepData2;
|
|
return TRUE;
|
|
} else if (this->pcdmiNext != NULL)
|
|
return this->pcdmiNext->GetData(iOrd - 1, pi1, pi2);
|
|
else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
PCDEVMODEIDAT CDEVMODEIDAT::Insert(int i1, int i2) {
|
|
|
|
PCDEVMODEIDAT pcdmi = NULL;
|
|
PCDEVMODEIDAT pcdmiNext = this;
|
|
|
|
//
|
|
// Try to find the entry
|
|
//
|
|
|
|
while (1) {
|
|
|
|
if ( (pcdmiNext == NULL) ||
|
|
(pcdmiNext->iRepData1 > i1) ||
|
|
((pcdmiNext->iRepData1 == i1) && (pcdmiNext->iRepData2 > i2)) ) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
pcdmi = pcdmiNext;
|
|
pcdmiNext = pcdmiNext->pcdmiNext;
|
|
|
|
}
|
|
|
|
//
|
|
// If we did not find it, add it to the list.
|
|
//
|
|
|
|
if (pcdmi == NULL || pcdmi->iRepData1 != i1 || pcdmi->iRepData2 != i2) {
|
|
|
|
PCDEVMODEIDAT pcdmiNew = new CDEVMODEIDAT(i1, i2);
|
|
|
|
if (pcdmiNew == NULL)
|
|
return NULL;
|
|
|
|
if (pcdmi == NULL) {
|
|
pcdmiNew->pcdmiNext = this;
|
|
return pcdmiNew;
|
|
|
|
} else {
|
|
|
|
pcdmiNew->pcdmiNext = pcdmi->pcdmiNext;
|
|
pcdmi->pcdmiNext = pcdmiNew;
|
|
return this;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*****************************************************************\
|
|
*
|
|
* CDEVMODEINDEX class
|
|
*
|
|
\*****************************************************************/
|
|
typedef class CDEVMODEINDEX *PCDEVMODEINDEX;
|
|
|
|
class CDEVMODEINDEX {
|
|
private:
|
|
PCDEVMODEIDAT pcdmiHead;
|
|
|
|
public:
|
|
CDEVMODEINDEX() : pcdmiHead(NULL) {}
|
|
~CDEVMODEINDEX() { if (pcdmiHead) delete pcdmiHead; };
|
|
|
|
int AddIndex(int i1, int i2);
|
|
int MapRepresentationToOrdinal(int i1, int i2);
|
|
BOOL MapOrdinalToRepresentation(int iOrd, int *pi1, int *pi2);
|
|
};
|
|
|
|
int CDEVMODEINDEX::MapRepresentationToOrdinal(int i1, int i2) {
|
|
if (pcdmiHead == NULL)
|
|
return -1;
|
|
|
|
return pcdmiHead->Index(i1, i2);
|
|
}
|
|
|
|
BOOL CDEVMODEINDEX::MapOrdinalToRepresentation(int iOrd, int *pi1, int *pi2) {
|
|
if (pcdmiHead == NULL)
|
|
return FALSE;
|
|
|
|
return pcdmiHead->GetData(iOrd, pi1, pi2);
|
|
}
|
|
|
|
|
|
int CDEVMODEINDEX::AddIndex(int i1, int i2) {
|
|
PCDEVMODEIDAT pcdmi;
|
|
|
|
if (pcdmiHead == NULL) {
|
|
|
|
pcdmiHead = new CDEVMODEIDAT(i1, i2);
|
|
|
|
} else {
|
|
|
|
pcdmi = pcdmiHead->Insert(i1, i2);
|
|
|
|
if (pcdmi == NULL)
|
|
return 0;
|
|
|
|
if (pcdmi != pcdmiHead)
|
|
pcdmiHead = pcdmi;
|
|
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*****************************************************************\
|
|
*
|
|
* CDEVMODELST class
|
|
*
|
|
\*****************************************************************/
|
|
class CDEVMODELST {
|
|
private:
|
|
int cRes;
|
|
int cClr;
|
|
int cFreq;
|
|
|
|
//
|
|
// The cdmHead is the linked list of valid mode.
|
|
// The pcdmArray is a cube of pointers to the appropriate CDEVMODE
|
|
// structure.
|
|
// If the pointer is valid, it indicates there is such a mode; otherwise,
|
|
// if the pointer is NULL, there is no such mode.
|
|
//
|
|
|
|
CDEVMODE cdmHead;
|
|
PCDEVMODE *pcdmArray;
|
|
|
|
CDEVMODEINDEX cdmiRes;
|
|
CDEVMODEINDEX cdmiClr;
|
|
CDEVMODEINDEX cdmiFreq;
|
|
|
|
|
|
//
|
|
// No driver should return frequencies of 0 anymore. Use 1 for
|
|
// hardware default.
|
|
//
|
|
|
|
BOOL bBadData;
|
|
|
|
|
|
public:
|
|
CDEVMODELST() : cRes(0), cClr(0), cFreq(0), pcdmArray(NULL),
|
|
bBadData(FALSE) {};
|
|
|
|
~CDEVMODELST() {
|
|
delete pcdmArray;
|
|
}
|
|
|
|
BOOL BuildList(LPTSTR pszDevName, HWND hwnd);
|
|
|
|
void AddDevMode(LPDEVMODE lpdm);
|
|
|
|
PCDEVMODE LookUp(int iRes, int iClr, int iFreq)
|
|
{
|
|
if ((iFreq != -1) &&
|
|
(iRes != -1) &&
|
|
(iClr != -1))
|
|
{
|
|
return *(pcdmArray + (((iRes * cClr) + iClr) * cFreq) + iFreq);
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
BOOL FindClosestMode(int iRes, int *iClr, int *iFreq);
|
|
BOOL FindClosestMode(int *iRes, int iClr, int *iFreq);
|
|
BOOL FindClosestMode(int *iRes, int *iClr, int iFreq);
|
|
|
|
|
|
int ColorFromIndex(int iClr) {
|
|
int i1, i2;
|
|
|
|
cdmiClr.MapOrdinalToRepresentation(iClr, &i1, &i2);
|
|
|
|
return i1;
|
|
}
|
|
|
|
void ResXYFromIndex(int iRes, int *pcx, int *pcy) {
|
|
cdmiRes.MapOrdinalToRepresentation(iRes, pcx, pcy);
|
|
}
|
|
|
|
int FreqFromIndex(int iFreq) {
|
|
int i1, i2;
|
|
|
|
cdmiFreq.MapOrdinalToRepresentation(iFreq, &i1, &i2);
|
|
|
|
return i1;
|
|
}
|
|
|
|
int IndexFromColor(int cBitsPerPel) {
|
|
return cdmiClr.MapRepresentationToOrdinal(cBitsPerPel, 0);
|
|
}
|
|
|
|
int IndexFromResXY(int cx, int cy) {
|
|
return cdmiRes.MapRepresentationToOrdinal(cx, cy);
|
|
}
|
|
|
|
int IndexFromFreq(int cHz) {
|
|
return cdmiFreq.MapRepresentationToOrdinal(cHz, 0);
|
|
}
|
|
|
|
int GetResCount() {return cRes;}
|
|
int GetClrCount() {return cClr;}
|
|
int GetFreqCount() {return cFreq;}
|
|
|
|
BOOL IsDriverBadData() {return bBadData;}
|
|
VOID SetDriverBadData() {bBadData = TRUE;}
|
|
|
|
PCDEVMODE GetDevmodeList() {return ((PCDEVMODE)(&cdmHead));}
|
|
};
|
|
|
|
typedef CDEVMODELST *PCDEVMODELST;
|
|
|
|
//
|
|
// FindClosestMode methods
|
|
//
|
|
// DON'T PANIC!!!!
|
|
//
|
|
// C++ lets you over load functions. It figures out which one to call
|
|
// based on the parameters you pass it.
|
|
//
|
|
// These methods find the closest matching devmode in the matrix. You
|
|
// pass a pointer for the two parameters you are trying to find, and
|
|
// an int for the one you want to remain the same.
|
|
// (Rather PROLOGish, isn't it?)
|
|
//
|
|
BOOL CDEVMODELST::FindClosestMode(int iRes, int *piClr, int *piFreq) {
|
|
int iClr, iFreq;
|
|
|
|
/*
|
|
* Try lower colors until we find one that will work
|
|
*/
|
|
for (iClr = *piClr; iClr >= 0; iClr--) {
|
|
|
|
/* Try lower frequencies first, incase the monitor can't handle
|
|
* higher ones.
|
|
*/
|
|
for (iFreq = *piFreq; iFreq >= 0; iFreq--) {
|
|
if(LookUp(iRes, iClr, iFreq)) {
|
|
*piFreq = iFreq;
|
|
*piClr = iClr;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
/* Couldn't find lower freq, try higher */
|
|
for (iFreq = *piFreq; iFreq < this->cFreq; iFreq++) {
|
|
if(LookUp(iRes, iClr, iFreq)) {
|
|
*piFreq = iFreq;
|
|
*piClr = iClr;
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Couldn't find a lower clr mode, check for higher
|
|
*/
|
|
for (iClr = *piClr; iClr < this->cClr; iClr++) {
|
|
/* Try lower frequencies first, incase the monitor can't handle
|
|
* higher ones.
|
|
*/
|
|
for (iFreq = *piFreq; iFreq >= 0; iFreq--) {
|
|
if(LookUp(iRes, iClr, iFreq)) {
|
|
*piFreq = iFreq;
|
|
*piClr = iClr;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
/* Couldn't find lower freq, try higher */
|
|
for (iFreq = *piFreq; iFreq < this->cFreq; iFreq++) {
|
|
if (LookUp(iRes, iClr, iFreq)) {
|
|
*piFreq = iFreq;
|
|
*piClr = iClr;
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CDEVMODELST::FindClosestMode(int *piRes, int iClr, int *piFreq ) {
|
|
int iRes, iFreq;
|
|
|
|
/*
|
|
* Try lower resolutions until we find one that will work
|
|
*/
|
|
for(iRes = *piRes; iRes >= 0; iRes-- ) {
|
|
|
|
/* Try lower frequencies first, incase the monitor can't handle
|
|
* higher ones.
|
|
*/
|
|
for(iFreq = *piFreq; iFreq >= 0; iFreq-- ) {
|
|
if(LookUp(iRes, iClr, iFreq )) {
|
|
*piFreq = iFreq;
|
|
*piRes = iRes;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
/* Couldn't find lower freq, try higher */
|
|
for(iFreq = *piFreq; iFreq < this->cFreq; iFreq++ ) {
|
|
if(LookUp(iRes, iClr, iFreq )) {
|
|
*piFreq = iFreq;
|
|
*piRes = iRes;
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Couldn't find a lower res mode, check for higher
|
|
*/
|
|
for(iRes = *piRes; iRes < this->cRes; iRes++ ) {
|
|
/* Try lower frequencies first, incase the monitor can't handle
|
|
* higher ones.
|
|
*/
|
|
for(iFreq = *piFreq; iFreq >= 0; iFreq-- ) {
|
|
if(LookUp(iRes, iClr, iFreq )) {
|
|
*piFreq = iFreq;
|
|
*piRes = iRes;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
/* Couldn't find lower freq, try higher */
|
|
for(iFreq = *piFreq; iFreq < this->cFreq; iFreq++ ) {
|
|
if(LookUp(iRes, iClr, iFreq )) {
|
|
*piFreq = iFreq;
|
|
*piRes = iRes;
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CDEVMODELST::FindClosestMode(int *piRes, int *piClr, int iFreq ) {
|
|
int iRes, iClr;
|
|
|
|
/*
|
|
* Try lower resolutions until we find one that will work
|
|
*/
|
|
for(iRes = *piRes; iRes >= 0; iRes-- ) {
|
|
|
|
/* Try lower Colors first, incase the adaptor can't handle
|
|
* higher ones.
|
|
*/
|
|
for(iClr = *piClr; iClr >= 0; iClr-- ) {
|
|
if(LookUp(iRes, iClr, iFreq )) {
|
|
*piClr = iClr;
|
|
*piRes = iRes;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
/* Couldn't find lower color, try higher */
|
|
for(iClr = *piClr; iClr < this->cClr; iClr++ ) {
|
|
if(LookUp(iRes, iClr, iFreq )) {
|
|
*piClr = iClr;
|
|
*piRes = iRes;
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Couldn't find a lower res mode, check for higher
|
|
*/
|
|
for(iRes = *piRes; iRes < this->cRes; iRes++ ) {
|
|
/* Try lower colors first, incase the adaptor can't handle
|
|
* higher ones.
|
|
*/
|
|
for(iClr = *piClr; iClr >= 0; iClr-- ) {
|
|
if(LookUp(iRes, iClr, iFreq )) {
|
|
*piClr = iClr;
|
|
*piRes = iRes;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
/* Couldn't find lower color, try higher */
|
|
for(iClr = *piClr; iClr < this->cClr; iClr++ ) {
|
|
if(LookUp(iRes, iClr, iFreq )) {
|
|
*piClr = iClr;
|
|
*piRes = iRes;
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// BuildList
|
|
//
|
|
// Enumerates all the device modes and puts them into the list.
|
|
// This method must be called before other methods in DEVMODELST.
|
|
//
|
|
// (I suppose I should have made this the constructor for the DEVMODELST
|
|
// class, but I wanted it to return a value).
|
|
//
|
|
BOOL CDEVMODELST::BuildList(LPTSTR pszDevName, HWND hwnd ) {
|
|
|
|
DWORD size;
|
|
BOOL ret = TRUE;
|
|
BYTE devmode[sizeof(DEVMODE) + 0xFFFF];
|
|
LPDEVMODE pdevmode = (LPDEVMODE) devmode;
|
|
DWORD i;
|
|
CList list;
|
|
|
|
#if 0
|
|
|
|
KdPrint(("Display.cpl: Root of linked list of modes = %08lx\n", &cdmHead));
|
|
|
|
#endif
|
|
|
|
//
|
|
// Lets generate a list with all the possible modes. Then we'll
|
|
// remove 16 color modes for which we have an exact 256 color
|
|
// duplicate.
|
|
//
|
|
|
|
pdevmode->dmSize = sizeof(DEVMODE);
|
|
pdevmode->dmDriverExtra = 0xFFFF;
|
|
|
|
i = 0;
|
|
|
|
while (EnumDisplaySettings(pszDevName, i++, pdevmode))
|
|
{
|
|
list.Insert(pdevmode);
|
|
pdevmode->dmDriverExtra = 0xFFFF;
|
|
}
|
|
|
|
list.Process();
|
|
|
|
while (pdevmode = list.Pop())
|
|
{
|
|
AddDevMode(pdevmode);
|
|
}
|
|
|
|
//
|
|
// If the cube is empty, return failiure.
|
|
//
|
|
|
|
if ((size = cRes * cClr * cFreq) == 0)
|
|
{
|
|
KdPrint(("Display.cpl: error doing enummodes %08lx\n", ret));
|
|
return FALSE;
|
|
}
|
|
|
|
pcdmArray = new PCDEVMODE[size];
|
|
|
|
if (pcdmArray == NULL) {
|
|
|
|
return FALSE;
|
|
|
|
} else {
|
|
|
|
PCDEVMODE pcdm, *pArray;
|
|
LPDEVMODE lpdm;
|
|
int iRes, iClr, iFreq;
|
|
|
|
ZeroMemory(pcdmArray, sizeof(PCDEVMODE) * size);
|
|
|
|
for (pcdm = cdmHead.NextDevMode();
|
|
pcdm != NULL;
|
|
pcdm = pcdm->NextDevMode()) {
|
|
|
|
lpdm = pcdm->GetData();
|
|
|
|
iRes = cdmiRes.MapRepresentationToOrdinal(lpdm->dmPelsWidth,
|
|
lpdm->dmPelsHeight);
|
|
iClr = cdmiClr.MapRepresentationToOrdinal(lpdm->dmBitsPerPel, 0);
|
|
iFreq = cdmiFreq.MapRepresentationToOrdinal(lpdm->dmDisplayFrequency, 0);
|
|
|
|
//
|
|
// Save the pointer in the right index in the array.
|
|
// NOTE:
|
|
// If we have a pretested mode, it will show up first in the list
|
|
// of modes - so we must make sure we do not overwrite that entry
|
|
// with a duplicate further on in the list.
|
|
//
|
|
|
|
pArray = pcdmArray + (((iRes * cClr) + iClr) * cFreq) + iFreq;
|
|
|
|
if (!*pArray) {
|
|
*pArray = pcdm;
|
|
}
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// AddDevMode method
|
|
//
|
|
// This method builds the index lists for the matrix. There is one
|
|
// index list for each axes of the three dimemsional matrix of device
|
|
// modes.
|
|
//
|
|
// The entry is also automatically added to the linked list of modes if
|
|
// it is not alreay present in the list.
|
|
//
|
|
|
|
void CDEVMODELST::AddDevMode(LPDEVMODE lpdm) {
|
|
|
|
//
|
|
// !!!
|
|
// Make sure all the fields of the DEVMODE are correctly filled in
|
|
//
|
|
|
|
//
|
|
// Warn about:
|
|
// - Drivers that return refresh rate of 0.
|
|
// - Drivers that have an invalid set of DisplayFlags.
|
|
// - Drivers that do not mark their devmode appropriately.
|
|
//
|
|
|
|
if ((lpdm->dmDisplayFrequency == 0) ||
|
|
(lpdm->dmDisplayFlags & ~DMDISPLAYFLAGS_VALID) ||
|
|
(lpdm->dmFields & ~(DM_BITSPERPEL |
|
|
DM_PELSWIDTH |
|
|
DM_PELSHEIGHT |
|
|
DM_DISPLAYFLAGS |
|
|
DM_DISPLAYFREQUENCY)))
|
|
{
|
|
SetDriverBadData();
|
|
}
|
|
|
|
//
|
|
// Set the height for the test of the 1152 mode
|
|
//
|
|
|
|
if (lpdm->dmPelsWidth == 1152) {
|
|
|
|
Set1152Mode(lpdm->dmPelsHeight);
|
|
}
|
|
|
|
//
|
|
// The mode was not in the list, so add it.
|
|
//
|
|
|
|
cdmHead.AddElement(lpdm);
|
|
|
|
cRes += cdmiRes.AddIndex(lpdm->dmPelsWidth, lpdm->dmPelsHeight);
|
|
cClr += cdmiClr.AddIndex(lpdm->dmBitsPerPel, 0);
|
|
cFreq += cdmiFreq.AddIndex(lpdm->dmDisplayFrequency, 0);
|
|
|
|
}
|
|
|
|
/*****************************************************************\
|
|
*
|
|
* CDISPLAYOBJ class
|
|
*
|
|
\*****************************************************************/
|
|
class CDISPLAYOBJ {
|
|
|
|
protected:
|
|
RECT rcPos;
|
|
HWND hwndParent;
|
|
|
|
public:
|
|
void Redraw() { InvalidateRect(this->hwndParent, &(this->rcPos), FALSE); }
|
|
void SetPosition(HWND hwnd, LPRECT lprc )
|
|
{ hwndParent = hwnd; rcPos = *lprc; }
|
|
virtual void Paint(HDC hdc, LPRECT lprc = NULL) = 0;
|
|
};
|
|
|
|
/*****************************************************************\
|
|
*
|
|
* CMONITOR class
|
|
*
|
|
\*****************************************************************/
|
|
|
|
extern HBITMAP FAR LoadMonitorBitmap( BOOL bFillDesktop );
|
|
|
|
class CMONITOR : public CDISPLAYOBJ {
|
|
private:
|
|
HBITMAP hbmMonitor;
|
|
HBITMAP hbmScrSample;
|
|
int iOrgXRes;
|
|
int iOrgYRes;
|
|
int iCurXRes;
|
|
int iCurYRes;
|
|
BOOL fInit;
|
|
|
|
public:
|
|
CMONITOR();
|
|
~CMONITOR();
|
|
void SetScreenSize(int HRes, int VRes);
|
|
void Paint(HDC hdc, LPRECT lprc = NULL);
|
|
void SysColorChange( void );
|
|
};
|
|
|
|
|
|
CMONITOR::CMONITOR() : fInit(TRUE), iOrgXRes(800), iOrgYRes(600), iCurXRes(800), iCurYRes(600) {
|
|
HDC hdc;
|
|
|
|
this->hbmScrSample = LoadMonitorBitmap( TRUE ); // let them do the desktop
|
|
|
|
// get a base copy of the bitmap for when the "internals" change
|
|
this->hbmMonitor = LoadMonitorBitmap( FALSE ); // we'll do the desktop
|
|
|
|
//hdc = GetWindowDC(GetDesktopWindow());
|
|
//this->iOrgXRes = GetDeviceCaps(hdc, HORZRES);
|
|
//this->iOrgYRes = GetDeviceCaps(hdc, VERTRES);
|
|
//ReleaseDC(GetDesktopWindow(), hdc);
|
|
|
|
}
|
|
|
|
|
|
CMONITOR::~CMONITOR() {
|
|
SendDlgItemMessage(this->hwndParent, IDC_SCREENSAMPLE, STM_SETIMAGE, IMAGE_BITMAP, NULL);
|
|
|
|
if (this->hbmScrSample)
|
|
{
|
|
DeleteObject(this->hbmScrSample);
|
|
this->hbmScrSample = NULL;
|
|
}
|
|
if (this->hbmMonitor)
|
|
{
|
|
DeleteObject(this->hbmMonitor);
|
|
this->hbmMonitor = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
void CMONITOR::SetScreenSize(int HRes, int VRes)
|
|
{
|
|
HBITMAP hbmOld;
|
|
HBRUSH hbrOld;
|
|
HDC hdcMem2;
|
|
|
|
// stretching the taskbar could get messy, we'll only do the desktop
|
|
int mon_dy = MON_DY - MON_TRAY;
|
|
|
|
// init to identical extents
|
|
SIZE dSrc = { MON_DX, mon_dy };
|
|
SIZE dDst = { MON_DX, mon_dy };
|
|
|
|
// set up a work area to play in
|
|
if (!this->hbmMonitor || !this->hbmScrSample)
|
|
return;
|
|
hdcMem2 = CreateCompatibleDC(g_hdcMem);
|
|
if (!hdcMem2)
|
|
return;
|
|
SelectObject(hdcMem2, this->hbmScrSample);
|
|
hbmOld = (HBITMAP)SelectObject(g_hdcMem, this->hbmMonitor);
|
|
|
|
// see if we need to shrink either aspect of the image
|
|
if (HRes > this->iOrgXRes || VRes > this->iOrgYRes)
|
|
{
|
|
// make sure the uncovered area will be seamless with the desktop
|
|
RECT rc = { MON_X, MON_Y, MON_X + MON_DX, MON_Y + mon_dy };
|
|
HBRUSH hbr =
|
|
CreateSolidBrush( GetPixel( g_hdcMem, MON_X + 1, MON_Y + 1 ) );
|
|
|
|
FillRect(hdcMem2, &rc, hbr);
|
|
DeleteObject( hbr );
|
|
}
|
|
|
|
// stretch the image to reflect the new resolution
|
|
if( HRes > this->iOrgXRes )
|
|
dDst.cx = MulDiv( MON_DX, this->iOrgXRes, HRes );
|
|
else if( HRes < this->iOrgXRes )
|
|
dSrc.cx = MulDiv( MON_DX, HRes, this->iOrgXRes );
|
|
|
|
if( VRes > this->iOrgYRes )
|
|
dDst.cy = MulDiv( mon_dy, this->iOrgYRes, VRes );
|
|
else if( VRes < this->iOrgYRes )
|
|
dSrc.cy = MulDiv( mon_dy, VRes, this->iOrgYRes );
|
|
|
|
SetStretchBltMode( hdcMem2, COLORONCOLOR );
|
|
StretchBlt( hdcMem2, MON_X, MON_Y, dDst.cx, dDst.cy,
|
|
g_hdcMem, MON_X, MON_Y, dSrc.cx, dSrc.cy, SRCCOPY );
|
|
|
|
// now fill the new image's desktop with the possibly-dithered brush
|
|
// the top right corner seems least likely to be hit by the stretch...
|
|
hbrOld = (HBRUSH)SelectObject( hdcMem2, GetSysColorBrush( COLOR_DESKTOP ) );
|
|
ExtFloodFill(hdcMem2, MON_X + MON_DX - 2, MON_Y+1,
|
|
GetPixel(hdcMem2, MON_X + MON_DX - 2, MON_Y+1), FLOODFILLSURFACE);
|
|
|
|
// clean up after ourselves
|
|
SelectObject( hdcMem2, hbrOld );
|
|
SelectObject( hdcMem2, g_hbmDefault );
|
|
DeleteObject( hdcMem2 );
|
|
SelectObject( g_hdcMem, hbmOld );
|
|
|
|
this->iCurXRes = HRes;
|
|
this->iCurYRes = VRes;
|
|
}
|
|
|
|
void CMONITOR::Paint(HDC hdc, LPRECT lprc) {
|
|
if (this->fInit) {
|
|
this->fInit = FALSE;
|
|
SendDlgItemMessage(this->hwndParent, IDC_SCREENSAMPLE, STM_SETIMAGE, IMAGE_BITMAP, (DWORD)this->hbmScrSample);
|
|
}
|
|
|
|
InvalidateRect(GetDlgItem(this->hwndParent, IDC_SCREENSAMPLE), NULL, FALSE);
|
|
}
|
|
|
|
void CMONITOR::SysColorChange( void ) {
|
|
if( this->hbmMonitor )
|
|
DeleteObject( this->hbmMonitor );
|
|
|
|
if( this->hbmScrSample )
|
|
DeleteObject( this->hbmScrSample );
|
|
|
|
this->hbmScrSample = LoadMonitorBitmap( TRUE ); // let them do the desktop
|
|
|
|
// get a base copy of the bitmap for when the "internals" change
|
|
this->hbmMonitor = LoadMonitorBitmap( FALSE ); // we'll do the desktop
|
|
|
|
this->SetScreenSize( this->iCurXRes, this->iCurYRes );
|
|
|
|
SendDlgItemMessage(this->hwndParent, IDC_SCREENSAMPLE, STM_SETIMAGE, IMAGE_BITMAP, (DWORD)this->hbmScrSample);
|
|
}
|
|
|
|
|
|
/*****************************************************************\
|
|
*
|
|
* CCOLORBAR class
|
|
*
|
|
\*****************************************************************/
|
|
|
|
class CCOLORBAR : public CDISPLAYOBJ {
|
|
private:
|
|
HBITMAP ahbmColorBar[IDB_COLORMAX - IDB_COLORMIN + 1];
|
|
int iClrIndex; /* 0 = 2 clr, 1 = 16 clr, 3 = 256 clr */
|
|
SIZE size;
|
|
|
|
|
|
public:
|
|
CCOLORBAR();
|
|
~CCOLORBAR();
|
|
void SetColorIndex(int iClr) {this->iClrIndex = iClr; this->Redraw();}
|
|
void Paint(HDC hdc, LPRECT lprc = NULL);
|
|
};
|
|
|
|
CCOLORBAR::CCOLORBAR() : iClrIndex(0) {
|
|
int i;
|
|
BITMAP bmp;
|
|
HBITMAP hbm;
|
|
|
|
this->size.cx = this->size.cy = 0;
|
|
|
|
for(i = 0; i <= IDB_COLORMAX - IDB_COLORMIN; i++) {
|
|
hbm = LoadBitmap(ghmod, MAKEINTRESOURCE(i + IDB_COLORMIN));
|
|
|
|
if (GetObject(hbm, sizeof(bmp), &bmp)) {
|
|
this->size.cx = bmp.bmWidth;
|
|
this->size.cy = bmp.bmHeight;
|
|
}
|
|
|
|
ahbmColorBar[i] = hbm;
|
|
}
|
|
}
|
|
|
|
CCOLORBAR::~CCOLORBAR() {
|
|
int i;
|
|
|
|
for (i = IDB_COLORMIN; i <= IDB_COLORMAX; i++) {
|
|
DeleteObject(ahbmColorBar[i]);
|
|
}
|
|
}
|
|
|
|
void CCOLORBAR::Paint(HDC hdc, LPRECT lprc) {
|
|
HDC hdcMem;
|
|
HBITMAP hbmOld;
|
|
RECT rcTmp;
|
|
|
|
if ((lprc != NULL && !IntersectRect(&rcTmp, lprc, &(this->rcPos))) ||
|
|
(this->size.cx == 0) ||
|
|
(this->size.cy == 0)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
hdcMem = CreateCompatibleDC(hdc);
|
|
|
|
if (hdcMem != NULL) {
|
|
|
|
hbmOld = (HBITMAP)SelectObject(hdcMem, this->ahbmColorBar[iClrIndex]);
|
|
|
|
StretchBlt(hdc,
|
|
this->rcPos.left,
|
|
this->rcPos.top,
|
|
this->rcPos.right - this->rcPos.left,
|
|
this->rcPos.bottom - this->rcPos.top,
|
|
hdcMem,
|
|
0,
|
|
0,
|
|
this->size.cx,
|
|
this->size.cy,
|
|
SRCCOPY);
|
|
|
|
SelectObject(hdcMem, hbmOld);
|
|
|
|
DeleteDC(hdcMem);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************\
|
|
*
|
|
* CFILEVER class
|
|
*
|
|
* Class to access the filever info in a driver
|
|
*
|
|
\*****************************************************************/
|
|
class CFILEVER {
|
|
private:
|
|
LPBYTE lpbVerInfo;
|
|
TCHAR szVersionKey[MAX_PATH];
|
|
|
|
LPTSTR GetVerInfo(LPTSTR szKey);
|
|
|
|
public:
|
|
CFILEVER(LPTSTR szFile);
|
|
~CFILEVER();
|
|
|
|
|
|
LPTSTR GetFileVer() { return this->GetVerInfo(SZ_FILEVER); }
|
|
LPTSTR GetCompanyName() { return this->GetVerInfo(SZ_COMPNAME); }
|
|
};
|
|
|
|
CFILEVER::CFILEVER(LPTSTR szFile): lpbVerInfo(NULL) {
|
|
|
|
DWORD cb;
|
|
DWORD dwHandle;
|
|
|
|
cb = GetFileVersionInfoSize(szFile, &dwHandle);
|
|
|
|
if (cb != 0) {
|
|
|
|
lpbVerInfo = (LPBYTE)LocalAlloc(LPTR, cb);
|
|
|
|
if (lpbVerInfo != NULL) {
|
|
|
|
GetFileVersionInfo(szFile, dwHandle, cb, lpbVerInfo);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
CFILEVER::~CFILEVER() {
|
|
|
|
if (lpbVerInfo != NULL)
|
|
LocalFree(lpbVerInfo);
|
|
|
|
}
|
|
|
|
LPTSTR CFILEVER::GetVerInfo(LPTSTR pszKey) {
|
|
|
|
LPTSTR lpValue;
|
|
UINT cb = 0;
|
|
|
|
//
|
|
// Try to get info in the local language
|
|
//
|
|
|
|
wsprintf(szVersionKey, TEXT("\\StringFileInfo\\%04X04B0\\%ws"),
|
|
LANGIDFROMLCID(GetUserDefaultLCID()), pszKey);
|
|
|
|
if (lpbVerInfo)
|
|
{
|
|
VerQueryValue(lpbVerInfo, szVersionKey, (LPVOID*)&lpValue, &cb);
|
|
|
|
if (cb == 0)
|
|
{
|
|
//
|
|
// No local language, try US English
|
|
//
|
|
|
|
wsprintf(szVersionKey, TEXT("\\StringFileInfo\\040904B0\\%ws"), pszKey);
|
|
|
|
VerQueryValue(lpbVerInfo, szVersionKey, (LPVOID*)&lpValue, &cb);
|
|
}
|
|
}
|
|
|
|
if (cb == 0)
|
|
{
|
|
//
|
|
// We have no file information.
|
|
//
|
|
|
|
LoadString(ghmod, IDS_NO_VERSION_INFO, szVersionKey, sizeof(szVersionKey));
|
|
lpValue = szVersionKey;
|
|
}
|
|
|
|
return lpValue;
|
|
}
|
|
|
|
|
|
/*****************************************************************\
|
|
*
|
|
* CREGVIDOBJ class
|
|
*
|
|
* Class to access the video part of the registry
|
|
*
|
|
\*****************************************************************/
|
|
class CREGVIDOBJ {
|
|
private:
|
|
HKEY hkVideoRegR;
|
|
HKEY hkVideoRegW;
|
|
HKEY hkServiceReg;
|
|
LPTSTR pszDrvName;
|
|
LPTSTR pszKeyName;
|
|
BOOL bdisablable;
|
|
|
|
public:
|
|
CREGVIDOBJ(LPTSTR pszDisplay);
|
|
~CREGVIDOBJ();
|
|
|
|
LPTSTR CloneDescription(void);
|
|
LPTSTR CloneDisplayFileNames(BOOL bPreprocess);
|
|
|
|
//
|
|
// Returns a pointer to the mini port name. THIS IS NOT A CLONE!
|
|
// THE CALLER MUST COPY IT IF IT NEEDS TO KEEP IT AROUND!
|
|
//
|
|
// DO NOT FREE THE POINTER RETURNED FROM THIS CALL!
|
|
//
|
|
|
|
LPTSTR GetMiniPort(void) { return this->pszDrvName; }
|
|
LPTSTR GetKeyName(void) { return this->pszKeyName; }
|
|
|
|
VOID GetHardwareInformation(PHARDWARE_INFO pInfo);
|
|
|
|
BOOL EnableDriver(BOOL Enable);
|
|
BOOL SetErrorControlNormal(void);
|
|
|
|
};
|
|
|
|
//
|
|
// CREGVIDOBJ constructor
|
|
//
|
|
CREGVIDOBJ::CREGVIDOBJ(LPTSTR pszDisplay):
|
|
hkServiceReg(NULL), hkVideoRegR(NULL), hkVideoRegW(NULL), pszDrvName(NULL),
|
|
pszKeyName(NULL), bdisablable(FALSE) {
|
|
|
|
TCHAR szName[MAX_PATH];
|
|
TCHAR szPath[MAX_PATH];
|
|
TCHAR szGroup[MAX_PATH];
|
|
LPTSTR pszPath;
|
|
HKEY hkeyMap;
|
|
int i;
|
|
DWORD cb;
|
|
|
|
LPTSTR pszName = NULL;
|
|
|
|
//
|
|
// map the driver's symbolic link into an NT name
|
|
//
|
|
|
|
pszDisplay = SubStrEnd(SZ_BACKBACKDOT, pszDisplay);
|
|
|
|
if (QueryDosDevice(pszDisplay, szName, MAX_PATH) == 0) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// get the video part of the device map
|
|
//
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
SZ_VIDEOMAP,
|
|
0,
|
|
KEY_READ,
|
|
&hkeyMap) != ERROR_SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// parse the device map and open the registry.
|
|
//
|
|
|
|
//Reg functions deal with bytes, not chars
|
|
cb = sizeof(szPath);
|
|
|
|
i = RegQueryValueEx(hkeyMap,
|
|
szName,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)szPath,
|
|
&cb);
|
|
|
|
RegCloseKey(hkeyMap);
|
|
|
|
if (i != ERROR_SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// At this point, szPath has something like:
|
|
// \REGISTRY\Machine\System\ControlSet001\Services\Jazzg300\Device0
|
|
//
|
|
// To use the Win32 registry calls, we have to strip off the \REGISTRY
|
|
// and convert \Machine to HKEY_LOCAL_MACHINE
|
|
//
|
|
|
|
hkeyMap = HKEY_LOCAL_MACHINE;
|
|
pszPath = SubStrEnd(SZ_REGISTRYMACHINE, szPath);
|
|
|
|
//
|
|
// try to open the registry key.
|
|
// Get Read access and Write access seperately so we can query stuff
|
|
// when an ordinary user is logged on.
|
|
//
|
|
|
|
if (RegOpenKeyEx(hkeyMap,
|
|
pszPath,
|
|
0,
|
|
KEY_READ,
|
|
&hkVideoRegR) != ERROR_SUCCESS) {
|
|
|
|
hkVideoRegR = 0;
|
|
|
|
}
|
|
|
|
if (RegOpenKeyEx(hkeyMap,
|
|
pszPath,
|
|
0,
|
|
KEY_WRITE,
|
|
&hkVideoRegW) != ERROR_SUCCESS) {
|
|
|
|
hkVideoRegW = 0;
|
|
|
|
}
|
|
|
|
//
|
|
// Save the mini port driver name
|
|
//
|
|
|
|
{
|
|
LPTSTR pszEnd;
|
|
HKEY hkeyDriver;
|
|
|
|
pszEnd = pszPath + lstrlen(pszPath);
|
|
|
|
//
|
|
// Remove the \DeviceX at the end of the path
|
|
//
|
|
|
|
while (pszEnd != pszPath && *pszEnd != TEXT('\\')) {
|
|
|
|
pszEnd--;
|
|
}
|
|
|
|
*pszEnd = UNICODE_NULL;
|
|
|
|
//
|
|
// First check if their is a binary name in there that we should use.
|
|
//
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
pszPath,
|
|
0,
|
|
KEY_READ,
|
|
&hkeyDriver) == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// parse the device map and open the registry.
|
|
//
|
|
|
|
cb = sizeof(szName);
|
|
|
|
if (RegQueryValueEx(hkeyDriver,
|
|
L"ImagePath",
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)szName,
|
|
&cb) == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// The is a binary.
|
|
// extract the name, which will be of the form ...\driver.sys
|
|
//
|
|
|
|
{
|
|
|
|
LPTSTR pszDriver, pszDriverEnd;
|
|
|
|
pszDriver = szName;
|
|
pszDriverEnd = pszDriver + lstrlen(pszDriver);
|
|
|
|
while(pszDriverEnd != pszDriver &&
|
|
*pszDriverEnd != TEXT('.')) {
|
|
pszDriverEnd--;
|
|
}
|
|
|
|
*pszDriverEnd = UNICODE_NULL;
|
|
|
|
while(pszDriverEnd != pszDriver &&
|
|
*pszDriverEnd != TEXT('\\')) {
|
|
pszDriverEnd--;
|
|
}
|
|
|
|
pszDriverEnd++;
|
|
|
|
//
|
|
// If pszDriver and pszDriverEnd are different, we now
|
|
// have the driver name.
|
|
//
|
|
|
|
if (pszDriverEnd > pszDriver) {
|
|
|
|
pszName = pszDriverEnd;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// while we have this key open, determine if the driver is in
|
|
// the Video group (to know if we can disable it automatically.
|
|
//
|
|
|
|
cb = sizeof(szName);
|
|
|
|
if (RegQueryValueEx(hkeyDriver,
|
|
L"Group",
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)szGroup,
|
|
&cb) == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Compare the string , case insensitive, to the "Video" group.
|
|
//
|
|
|
|
bdisablable = !(BOOL)(lstrcmpi(szGroup, L"Video"));
|
|
|
|
}
|
|
|
|
RegCloseKey(hkeyDriver);
|
|
}
|
|
|
|
while(pszEnd > pszPath && *pszEnd != TEXT('\\')) {
|
|
pszEnd--;
|
|
}
|
|
pszEnd++;
|
|
|
|
//
|
|
// Save the key name
|
|
//
|
|
|
|
this->pszKeyName = (LPTSTR)LocalAlloc(LMEM_ZEROINIT,
|
|
(lstrlen(pszEnd) + 1) * sizeof(TCHAR));
|
|
|
|
if (this->pszKeyName != NULL) {
|
|
|
|
CopyMemory(this->pszKeyName, pszEnd, lstrlen(pszEnd) * sizeof(TCHAR));
|
|
|
|
}
|
|
|
|
//
|
|
// something failed trying to get the binary name.
|
|
// just get the device name
|
|
//
|
|
|
|
if (!pszName) {
|
|
|
|
pszDrvName = pszKeyName;
|
|
|
|
} else {
|
|
|
|
this->pszDrvName = (LPTSTR)LocalAlloc(LMEM_ZEROINIT,
|
|
(lstrlen(pszName) + 1) * sizeof(TCHAR));
|
|
|
|
if (this->pszDrvName != NULL) {
|
|
|
|
CopyMemory(this->pszDrvName, pszName, lstrlen(pszName) * sizeof(TCHAR));
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Finally, Get a "write" handle to the service Key so we can disable the
|
|
// driver at a later time.
|
|
//
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
pszPath,
|
|
0,
|
|
KEY_READ | KEY_WRITE,
|
|
&hkServiceReg) != ERROR_SUCCESS) {
|
|
|
|
this->hkServiceReg = NULL;
|
|
bdisablable = FALSE;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
//
|
|
// CREGVIDOBJ destructor
|
|
//
|
|
// (gets called whenever a CREGVIDOBJ is destroyed or goes out of scope)
|
|
//
|
|
|
|
CREGVIDOBJ::~CREGVIDOBJ() {
|
|
|
|
//
|
|
// Close the registry
|
|
//
|
|
|
|
if (hkVideoRegW) {
|
|
RegCloseKey(hkVideoRegW);
|
|
}
|
|
|
|
if (hkVideoRegR) {
|
|
RegCloseKey(hkVideoRegR);
|
|
}
|
|
|
|
if (hkServiceReg) {
|
|
RegCloseKey(hkServiceReg);
|
|
}
|
|
|
|
//
|
|
// Free the strings
|
|
//
|
|
|
|
if (pszDrvName) {
|
|
LocalFree(pszDrvName);
|
|
}
|
|
}
|
|
|
|
//
|
|
// CloneDescription
|
|
//
|
|
// Gets the descriptive name of the driver out of the registry.
|
|
// (eg. "Stealth Pro" instead of "S3"). If there is no
|
|
// DeviceDescription value in the registry, then it returns
|
|
// the generic driver name (like 'S3' or 'ATI')
|
|
//
|
|
// NOTE: The caller must LocalFree the returned pointer when they
|
|
// are done with it. (Which is why it is called Clone instead of Get)
|
|
//
|
|
|
|
LPTSTR CREGVIDOBJ::CloneDescription(void) {
|
|
|
|
DWORD cb, dwType;
|
|
LPTSTR psz = NULL;
|
|
LONG lRet;
|
|
|
|
//
|
|
// query the size of the string
|
|
//
|
|
|
|
cb = 0;
|
|
lRet = RegQueryValueEx(hkVideoRegR,
|
|
SZ_DEVICEDESCRIPTION,
|
|
NULL,
|
|
&dwType,
|
|
NULL,
|
|
&cb);
|
|
|
|
//
|
|
// check to see if there is a string, and the string is more than just
|
|
// a UNICODE_NULL (detection will put an empty string there).
|
|
//
|
|
|
|
if ( (lRet == ERROR_SUCCESS || lRet == ERROR_MORE_DATA) &&
|
|
(cb > 2) ) {
|
|
|
|
//
|
|
// alloc a string buffer
|
|
//
|
|
|
|
psz = (LPTSTR)LocalAlloc(LPTR, cb);
|
|
|
|
if (psz) {
|
|
|
|
//
|
|
// get the string
|
|
//
|
|
|
|
if (RegQueryValueEx(hkVideoRegR,
|
|
SZ_DEVICEDESCRIPTION,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)psz,
|
|
&cb) != ERROR_SUCCESS) {
|
|
|
|
LocalFree(psz);
|
|
psz = NULL;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!psz) {
|
|
|
|
//
|
|
// we can't read the registry, just us the generic name
|
|
//
|
|
|
|
psz = FmtSprint(ID_DSP_TXT_COMPATABLE_DEV, this->pszDrvName);
|
|
|
|
}
|
|
|
|
ASSERT(psz != NULL);
|
|
|
|
return psz;
|
|
}
|
|
|
|
//
|
|
// Method to get the hardware information fields.
|
|
//
|
|
|
|
VOID CREGVIDOBJ::GetHardwareInformation(
|
|
PHARDWARE_INFO pInfo)
|
|
{
|
|
|
|
DWORD cb, dwType;
|
|
LPTSTR psz;
|
|
DWORD i;
|
|
LONG lRet;
|
|
TCHAR pszTmp[MAX_PATH];
|
|
|
|
LPTSTR pKeyNames[5] = {
|
|
L"HardwareInformation.MemorySize",
|
|
L"HardwareInformation.ChipType",
|
|
L"HardwareInformation.DacType",
|
|
L"HardwareInformation.AdapterString",
|
|
L"HardwareInformation.BiosString"
|
|
};
|
|
|
|
ZeroMemory(pInfo, sizeof(HARDWARE_INFO));
|
|
|
|
//
|
|
// Query each entry one after the other.
|
|
//
|
|
|
|
for (i = 0; i < 5; i++) {
|
|
|
|
//
|
|
// query the size of the string
|
|
//
|
|
|
|
cb = 0;
|
|
lRet = RegQueryValueEx(hkVideoRegR,
|
|
pKeyNames[i],
|
|
NULL,
|
|
&dwType,
|
|
NULL,
|
|
&cb);
|
|
|
|
//
|
|
// check to see if there is a string, and the string is more than just
|
|
// a UNICODE_NULL (detection will put an empty string there).
|
|
//
|
|
|
|
psz = NULL;
|
|
|
|
if (lRet == ERROR_SUCCESS || lRet == ERROR_MORE_DATA) {
|
|
|
|
if (i == 0) {
|
|
|
|
ULONG mem;
|
|
|
|
if (RegQueryValueEx(hkVideoRegR,
|
|
pKeyNames[i],
|
|
NULL,
|
|
&dwType,
|
|
(PUCHAR) (&mem),
|
|
&cb) == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// If we queried the memory size, we actually have
|
|
// a DWORD. Transform the DWORD to a string
|
|
//
|
|
|
|
// Divide down to Ks
|
|
mem = mem >> 10;
|
|
|
|
// if a MB multiple, divide again.
|
|
|
|
if ((mem & 0x3FF) != 0) {
|
|
|
|
psz = FmtSprint( MSG_SETTING_KB, mem );
|
|
|
|
} else {
|
|
|
|
psz = FmtSprint( MSG_SETTING_MB, mem >> 10 );
|
|
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// alloc a string buffer
|
|
//
|
|
|
|
psz = (LPTSTR)LocalAlloc(LPTR, cb);
|
|
|
|
if (psz) {
|
|
|
|
//
|
|
// get the string
|
|
//
|
|
|
|
if (RegQueryValueEx(hkVideoRegR,
|
|
pKeyNames[i],
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)psz,
|
|
&cb) != ERROR_SUCCESS) {
|
|
|
|
LocalFree(psz);
|
|
psz = NULL;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (psz == NULL) {
|
|
|
|
//
|
|
// Put in the default string
|
|
//
|
|
|
|
LoadString(ghmod,
|
|
IDS_UNAVAILABLE,
|
|
pszTmp,
|
|
sizeof(pszTmp));
|
|
|
|
cb = lstrlen(pszTmp) * sizeof(TCHAR);
|
|
|
|
psz = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, cb + sizeof(TCHAR));
|
|
|
|
if (psz) {
|
|
|
|
CopyMemory(psz, pszTmp, cb);
|
|
|
|
}
|
|
}
|
|
|
|
*(((LPTSTR *)pInfo) + i) = psz;
|
|
}
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
BOOL CREGVIDOBJ::EnableDriver(BOOL Enable) {
|
|
|
|
DWORD dw;
|
|
|
|
//
|
|
// just return TRUE if it is not a driver we want to disable
|
|
// i.e. it is not in the group "Video"
|
|
//
|
|
|
|
if (!bdisablable) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
//
|
|
// actually try to disable other drivers
|
|
//
|
|
|
|
if (Enable)
|
|
{
|
|
dw = SERVICE_SYSTEM_START;
|
|
}
|
|
else
|
|
{
|
|
dw = SERVICE_DISABLED;
|
|
}
|
|
|
|
|
|
if (hkServiceReg) {
|
|
|
|
return ((RegSetValueEx(this->hkServiceReg,
|
|
L"Start",
|
|
NULL,
|
|
REG_DWORD,
|
|
(LPBYTE) &dw,
|
|
sizeof(DWORD))) == ERROR_SUCCESS);
|
|
|
|
} else {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Sets the error control to whteve the driver wants - ERROR_NORMAL
|
|
// it what we will probably set it to.
|
|
//
|
|
|
|
BOOL CREGVIDOBJ::SetErrorControlNormal(void) {
|
|
|
|
DWORD dw = SERVICE_ERROR_NORMAL;
|
|
|
|
//
|
|
// just return TRUE if it is not a driver we want to report errors for
|
|
// i.e. it is not in the group "Video"
|
|
//
|
|
|
|
if (!bdisablable) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// change the ErrorControl value in the registry.
|
|
//
|
|
|
|
if (hkServiceReg) {
|
|
|
|
return ((RegSetValueEx(this->hkServiceReg,
|
|
L"ErrorControl",
|
|
NULL,
|
|
REG_DWORD,
|
|
(LPBYTE) &dw,
|
|
sizeof(DWORD))) == ERROR_SUCCESS);
|
|
|
|
} else {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// returns the display drivers
|
|
//
|
|
|
|
LPTSTR CREGVIDOBJ::CloneDisplayFileNames(BOOL bPreprocess) {
|
|
DWORD cb, dwType;
|
|
LPTSTR psz, pszName, tmppsz;
|
|
LONG lRet;
|
|
DWORD cNumStrings;
|
|
|
|
//
|
|
// query the size of the string
|
|
//
|
|
|
|
cb = 0;
|
|
|
|
lRet = RegQueryValueEx(hkVideoRegR,
|
|
SZ_INSTALLEDDRIVERS,
|
|
NULL,
|
|
&dwType,
|
|
NULL,
|
|
&cb);
|
|
|
|
if (lRet != ERROR_SUCCESS && lRet != ERROR_MORE_DATA) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
//
|
|
// alloc a string buffer
|
|
//
|
|
|
|
psz = (LPTSTR)LocalAlloc(LPTR, cb);
|
|
|
|
if (psz) {
|
|
|
|
//
|
|
// get the string
|
|
//
|
|
|
|
if (RegQueryValueEx(hkVideoRegR,
|
|
SZ_INSTALLEDDRIVERS,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)psz,
|
|
&cb) != ERROR_SUCCESS) {
|
|
|
|
LocalFree(psz);
|
|
return NULL;
|
|
|
|
}
|
|
|
|
//
|
|
// If the caller want a preprocessed list, we will add the commas,
|
|
// remove the NULLs, etc.
|
|
//
|
|
|
|
if (bPreprocess) {
|
|
|
|
//
|
|
// if it is a multi_sz, count the number of sub strings.
|
|
//
|
|
|
|
if (dwType == REG_MULTI_SZ) {
|
|
|
|
tmppsz = psz;
|
|
cNumStrings = 0;
|
|
|
|
while(*tmppsz) {
|
|
|
|
while(*tmppsz++);
|
|
cNumStrings++;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
cNumStrings = 1;
|
|
|
|
}
|
|
|
|
//
|
|
// the buffer must contain enought space for :
|
|
// the miniport name,
|
|
// the .sys extension,
|
|
// all the display driver names,
|
|
// the .dll extension for each of them.
|
|
// and place for ", " between each name
|
|
// we forget about NULL, so our buffer is a bit bigger.
|
|
//
|
|
|
|
cb = lstrlen(this->GetMiniPort()) +
|
|
cb +
|
|
lstrlen(SZ_DOTSYS) +
|
|
cNumStrings * (lstrlen(SZ_DOTDLL) + lstrlen(SZ_FILE_SEPARATOR));
|
|
|
|
|
|
pszName = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, cb * sizeof(TCHAR));
|
|
|
|
if (pszName != NULL) {
|
|
|
|
lstrcpy(pszName, this->GetMiniPort());
|
|
lstrcat(pszName, SZ_DOTSYS);
|
|
|
|
tmppsz = psz;
|
|
|
|
while (cNumStrings--) {
|
|
|
|
lstrcat(pszName, SZ_FILE_SEPARATOR);
|
|
lstrcat(pszName, tmppsz);
|
|
lstrcat(pszName, SZ_DOTDLL);
|
|
|
|
while (*tmppsz++);
|
|
}
|
|
}
|
|
|
|
LocalFree(psz);
|
|
psz = pszName;
|
|
}
|
|
}
|
|
|
|
//
|
|
// return it to the caller
|
|
//
|
|
|
|
return psz;
|
|
|
|
}
|
|
|
|
/*****************************************************************\
|
|
*
|
|
* CREGCLEANUP class
|
|
*
|
|
\*****************************************************************/
|
|
|
|
class CREGCLEANUP {
|
|
|
|
private:
|
|
|
|
PMARK_FILE pkKeyUsedRoot;
|
|
PMARK_FILE pfMiniUsedRoot;
|
|
PMARK_FILE pfDispUsedRoot;
|
|
|
|
PMARK_KEY pkMarkRoot;
|
|
|
|
VOID DeleteDriver(LPTSTR DriverName, BOOL Mini, HSPFILELOG hfileLog);
|
|
|
|
public:
|
|
CREGCLEANUP(void);
|
|
~CREGCLEANUP();
|
|
|
|
VOID vClean(BOOL bCleanEverything);
|
|
VOID ListDriver(LPTSTR deviceName);
|
|
|
|
};
|
|
|
|
typedef CREGCLEANUP *PCREGCLEANUP;
|
|
|
|
//
|
|
// cleanup regsitry
|
|
//
|
|
|
|
//
|
|
// CREGCLEANUP destructor
|
|
//
|
|
CREGCLEANUP::~CREGCLEANUP() {
|
|
|
|
//
|
|
// Delete the linked list we built
|
|
//
|
|
|
|
|
|
}
|
|
|
|
//
|
|
// CREGCLEANUP constructor
|
|
//
|
|
|
|
CREGCLEANUP::CREGCLEANUP(void) {
|
|
|
|
//
|
|
// We should only be performing cleanup if we did NOT postpone the
|
|
// configuration until later.
|
|
//
|
|
|
|
ASSERT(gUnattenedConfigureAtLogon == 0);
|
|
|
|
}
|
|
|
|
//
|
|
// vClean - main function
|
|
//
|
|
VOID CREGCLEANUP::vClean(BOOL bCleanEverything) {
|
|
|
|
HKEY hkServices;
|
|
DWORD i;
|
|
WCHAR pszKeyName[MAX_PATH];
|
|
DWORD cbNameLength;
|
|
FILETIME filetime;
|
|
ULONG ulStat;
|
|
HKEY hkDriver;
|
|
DWORD type;
|
|
WCHAR pGroup[MAX_PATH];
|
|
DWORD cbGroup;
|
|
WCHAR pImage[MAX_PATH];
|
|
DWORD cbImage;
|
|
ULONG bDeleteKey;
|
|
ULONG bDeleteDriver;
|
|
LPTSTR pszDriverName;
|
|
HKEY hkDevice0;
|
|
|
|
HSPFILELOG hfileLog = NULL;
|
|
|
|
pkKeyUsedRoot = NULL;
|
|
pfMiniUsedRoot = NULL;
|
|
pfDispUsedRoot = NULL;
|
|
|
|
pkMarkRoot = NULL;
|
|
|
|
#if 0
|
|
KdPrint(("Display.cpl: Cleaning up the registry\n"));
|
|
#endif
|
|
|
|
//
|
|
// Clean up any errors that may have been reported by the system (invalid
|
|
// display resolution) while the applet is running.
|
|
//
|
|
// This will solve the boot up case when a new driver is installed because
|
|
// a ChangeDisplaySettings call is made *after* the display applet has been
|
|
// started to reconfigure the mode, which cause the invalid display key to
|
|
// be put in the registry.
|
|
//
|
|
|
|
RegDeleteKey(HKEY_LOCAL_MACHINE,
|
|
SZ_INVALID_DISPLAY);
|
|
|
|
|
|
//
|
|
// Only clean we in a setup mode
|
|
//
|
|
|
|
if ( (gbExecMode == EXEC_SETUP) ||
|
|
(gbExecMode == EXEC_DETECT) ) {
|
|
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// If we are to clean everything, then ignore any loaded driver (dont
|
|
// enumerate them). That way we will only stay with VGA
|
|
//
|
|
|
|
if (bCleanEverything) {
|
|
|
|
#ifndef _X86_
|
|
ASSERT(FALSE);
|
|
#endif
|
|
|
|
#if 0
|
|
KdPrint(("Display.cpl: Cleaning everything in the registry\n"));
|
|
#endif
|
|
|
|
} else {
|
|
|
|
//
|
|
// Get our loaded drivers. There will never be more than three ...
|
|
//
|
|
|
|
DWORD iDevNum;
|
|
|
|
#if 0
|
|
KdPrint(("Display.cpl: Cleaning unused information in the registry\n"));
|
|
#endif
|
|
|
|
for (iDevNum = 1; ; iDevNum++) {
|
|
|
|
DISPLAY_DEVICE displayDevice;
|
|
|
|
displayDevice.cb = sizeof(DISPLAY_DEVICE);
|
|
|
|
if (EnumDisplayDevices(NULL, iDevNum, &displayDevice)) {
|
|
|
|
ListDriver(displayDevice.DeviceName);
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// We first open the registry, and get a pointer to the services node.
|
|
//
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
L"System\\CurrentControlSet\\Services",
|
|
0,
|
|
KEY_READ,
|
|
&hkServices) != ERROR_SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
hfileLog = SetupInitializeFileLog(NULL, SPFILELOG_SYSTEMLOG);
|
|
|
|
//
|
|
// Enumerate all the drivers in this list, and find the one that are
|
|
// in the video group
|
|
//
|
|
|
|
for (i=0; ; i++) {
|
|
|
|
pszDriverName = NULL;
|
|
cbNameLength = MAX_PATH;
|
|
|
|
ulStat = RegEnumKeyEx(hkServices,
|
|
i,
|
|
pszKeyName,
|
|
&cbNameLength,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&filetime);
|
|
|
|
if (ulStat == ERROR_NO_MORE_ITEMS) {
|
|
break;
|
|
}
|
|
|
|
if (ulStat != ERROR_SUCCESS) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// We now have a key name.
|
|
// Get the group name
|
|
//
|
|
|
|
ulStat = RegOpenKeyEx(hkServices,
|
|
pszKeyName,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hkDriver);
|
|
|
|
if (ulStat != ERROR_SUCCESS) {
|
|
continue;
|
|
}
|
|
|
|
cbGroup = MAX_PATH;
|
|
|
|
ulStat = RegQueryValueEx(hkDriver,
|
|
TEXT("GROUP"),
|
|
NULL,
|
|
&type,
|
|
(LPBYTE) &pGroup,
|
|
&cbGroup);
|
|
|
|
if ( (ulStat != ERROR_SUCCESS) ||
|
|
(lstrcmpi(pGroup, L"Video")) ) {
|
|
|
|
RegCloseKey(hkDriver);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// This driver is in the video group.
|
|
// check to see if the name is one of our loaded drivers.
|
|
// assume it will be deleted and check against the driver names
|
|
// to see if it should not.
|
|
//
|
|
|
|
PMARK_FILE pkUsed = pkKeyUsedRoot;
|
|
bDeleteKey = 1;
|
|
|
|
while (pkUsed) {
|
|
|
|
if (pkUsed->File) {
|
|
bDeleteKey &= lstrcmpi(pszKeyName, pkUsed->File);
|
|
}
|
|
|
|
pkUsed = pkUsed->Next;
|
|
}
|
|
|
|
if (bDeleteKey) {
|
|
|
|
//
|
|
// We need to get the list of the display drivers and miniport
|
|
// dirvers used by this
|
|
// adapter and see if they are used by anyone else.
|
|
//
|
|
|
|
//
|
|
// Now determine if the miniport driver must be deleted
|
|
// Get the binary name if possible. Otherwise just use the
|
|
// key name as the miniport name.
|
|
//
|
|
|
|
cbImage = MAX_PATH;
|
|
|
|
ulStat = RegQueryValueEx(hkDriver,
|
|
TEXT("ImagePath"),
|
|
NULL,
|
|
&type,
|
|
(LPBYTE) &pImage,
|
|
&cbImage);
|
|
|
|
if (ulStat == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// The is a binary.
|
|
// extract the name, which will be of the form ...\driver.sys
|
|
//
|
|
|
|
LPTSTR pszDriver, pszDriverEnd;
|
|
|
|
pszDriver = pImage;
|
|
pszDriverEnd = pImage + lstrlen(pImage);
|
|
|
|
while(pszDriverEnd != pszDriver &&
|
|
*pszDriverEnd != TEXT('.')) {
|
|
pszDriverEnd--;
|
|
}
|
|
|
|
*pszDriverEnd = UNICODE_NULL;
|
|
|
|
while(pszDriverEnd != pszDriver &&
|
|
*pszDriverEnd != TEXT('\\')) {
|
|
pszDriverEnd--;
|
|
}
|
|
|
|
pszDriverEnd++;
|
|
|
|
//
|
|
// If pszDriver and pszDriverEnd are different, we now
|
|
// have the driver name.
|
|
//
|
|
|
|
if (pszDriverEnd > pszDriver) {
|
|
|
|
pszDriverName = pszDriverEnd;
|
|
|
|
}
|
|
}
|
|
|
|
if (pszDriverName == NULL) {
|
|
|
|
pszDriverName = pszKeyName;
|
|
|
|
}
|
|
|
|
//
|
|
// We now have an image name. Check to see if the image can be
|
|
// deleted;
|
|
//
|
|
|
|
PMARK_FILE pkMini = pfMiniUsedRoot;
|
|
bDeleteDriver = 1;
|
|
|
|
while (pkMini) {
|
|
|
|
if (pkMini->File) {
|
|
bDeleteDriver &= lstrcmpi(pszDriverName, pkMini->File);
|
|
}
|
|
|
|
pkMini = pkMini->Next;
|
|
}
|
|
|
|
if (bDeleteDriver) {
|
|
|
|
DeleteDriver(pszDriverName, TRUE, hfileLog);
|
|
|
|
}
|
|
|
|
//
|
|
// Now determine if the display drivers must be deleted
|
|
//
|
|
|
|
ulStat = RegOpenKeyEx(hkDriver,
|
|
TEXT("Device0"),
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hkDevice0);
|
|
|
|
if (ulStat == ERROR_SUCCESS) {
|
|
|
|
cbImage = MAX_PATH;
|
|
|
|
ulStat = RegQueryValueEx(hkDevice0,
|
|
TEXT("InstalledDisplayDrivers"),
|
|
NULL,
|
|
&type,
|
|
(LPBYTE) &pImage,
|
|
&cbImage);
|
|
|
|
if (ulStat == ERROR_SUCCESS) {
|
|
|
|
pszDriverName = pImage;
|
|
|
|
while (*pszDriverName) {
|
|
|
|
PMARK_FILE pkDisp = pfDispUsedRoot;
|
|
bDeleteDriver = 1;
|
|
|
|
while (pkDisp) {
|
|
|
|
if (pkDisp->File) {
|
|
|
|
bDeleteDriver &= lstrcmpi(pszDriverName, pkDisp->File);
|
|
}
|
|
|
|
pkDisp = pkDisp->Next;
|
|
}
|
|
|
|
if (bDeleteDriver) {
|
|
|
|
DeleteDriver(pszDriverName, FALSE, hfileLog);
|
|
|
|
}
|
|
|
|
while(*pszDriverName++);
|
|
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hkDevice0);
|
|
}
|
|
|
|
//
|
|
// Now save the key for later deletion
|
|
//
|
|
|
|
PMARK_KEY pkMark;
|
|
|
|
pkMark = (PMARK_KEY)
|
|
LocalAlloc (LMEM_ZEROINIT, sizeof(MARK_KEY));
|
|
#if 0
|
|
KdPrint(("Display.cpl: Deleting key %ws\n", pszKeyName));
|
|
#endif
|
|
if (pkMark) {
|
|
|
|
if (pkMarkRoot) {
|
|
|
|
pkMark->Next = pkMarkRoot;
|
|
|
|
}
|
|
|
|
pkMarkRoot = pkMark;
|
|
pkMarkRoot->hKey = hkDriver;
|
|
|
|
} else {
|
|
|
|
RegCloseKey(hkDriver);
|
|
}
|
|
|
|
} else {
|
|
|
|
RegCloseKey(hkDriver);
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// disble the list of all keys to be deleted.
|
|
//
|
|
|
|
while (pkMarkRoot)
|
|
{
|
|
PMARK_KEY pktemp = pkMarkRoot;
|
|
DWORD dw = SERVICE_DISABLED;
|
|
|
|
RegSetValueEx(pkMarkRoot->hKey,
|
|
L"Start",
|
|
NULL,
|
|
REG_DWORD,
|
|
(LPBYTE) &dw,
|
|
sizeof(DWORD));
|
|
|
|
RegCloseKey(pkMarkRoot->hKey);
|
|
|
|
pkMarkRoot = pkMarkRoot->Next;
|
|
LocalFree(pktemp);
|
|
}
|
|
|
|
RegCloseKey(hkServices);
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
VOID CREGCLEANUP::DeleteDriver(LPTSTR DriverName, BOOL Mini, HSPFILELOG hfileLog) {
|
|
|
|
WCHAR pszFilePath[MAX_PATH];
|
|
WCHAR pszSystemPath[MAX_PATH];
|
|
DWORD cb = MAX_PATH;
|
|
|
|
cb = GetSystemDirectory(pszSystemPath, cb);
|
|
|
|
if (cb) {
|
|
|
|
if (lstrcmpi(L"vga", DriverName) &&
|
|
lstrcmpi(L"vga256", DriverName) &&
|
|
lstrcmpi(L"vga64k", DriverName) &&
|
|
lstrcmpi(L"framebuf", DriverName) ) {
|
|
|
|
//
|
|
// build up the name
|
|
//
|
|
|
|
swprintf(pszFilePath,
|
|
L"%ws%ws%ws%ws",
|
|
pszSystemPath,
|
|
Mini ? L"\\Drivers\\" : L"\\",
|
|
DriverName,
|
|
Mini ? SZ_DOTSYS : SZ_DOTDLL);
|
|
#if 0
|
|
KdPrint(("Display.cpl: Deleting driver %ws\n", pszFilePath));
|
|
#endif
|
|
//
|
|
// Make sure we delete the file from the filelog
|
|
//
|
|
|
|
if (hfileLog)
|
|
{
|
|
//
|
|
// Setup wants a name that start with no drive letter in front
|
|
// that is - \winnt ...
|
|
//
|
|
|
|
SetupRemoveFileLogEntry(hfileLog, NULL, pszFilePath + 2);
|
|
}
|
|
|
|
DeleteFile(pszFilePath);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// function that builds up the list up keys, miniport drivers and
|
|
// display drivers that are used in the system.
|
|
//
|
|
|
|
VOID CREGCLEANUP::ListDriver(LPTSTR deviceName) {
|
|
|
|
CREGVIDOBJ crv(deviceName);
|
|
|
|
LPTSTR pszKey = crv.GetKeyName();
|
|
LPTSTR pszMini = crv.GetMiniPort();
|
|
LPTSTR pszDisp = crv.CloneDisplayFileNames(FALSE);
|
|
|
|
if (!pszKey) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Add to the list of used keys
|
|
//
|
|
|
|
PMARK_FILE pfUsed;
|
|
|
|
pfUsed = (PMARK_FILE) LocalAlloc (LMEM_ZEROINIT, sizeof(MARK_FILE));
|
|
|
|
if (pfUsed) {
|
|
|
|
if (pkKeyUsedRoot) {
|
|
|
|
pfUsed->Next = pkKeyUsedRoot;
|
|
|
|
}
|
|
|
|
pkKeyUsedRoot = pfUsed;
|
|
pkKeyUsedRoot->File = CloneString(pszKey);
|
|
|
|
}
|
|
|
|
//
|
|
// Add the miniport to the list of used miniports
|
|
//
|
|
|
|
if (pszMini) {
|
|
|
|
PMARK_FILE pfMini;
|
|
|
|
pfMini = (PMARK_FILE)
|
|
LocalAlloc (LMEM_ZEROINIT, sizeof(MARK_FILE));
|
|
|
|
if (pfMini) {
|
|
|
|
if (pfMiniUsedRoot) {
|
|
|
|
pfMini->Next = pfMiniUsedRoot;
|
|
|
|
}
|
|
|
|
pfMiniUsedRoot = pfMini;
|
|
pfMiniUsedRoot->File = CloneString(pszMini);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add the miniport to the list of used miniports
|
|
//
|
|
|
|
if (pszDisp) {
|
|
|
|
LPTSTR pszTmp = pszDisp;
|
|
|
|
while (*pszTmp) {
|
|
|
|
PMARK_FILE pfDisp;
|
|
|
|
pfDisp = (PMARK_FILE)
|
|
LocalAlloc (LMEM_ZEROINIT, sizeof(MARK_FILE));
|
|
|
|
if (pfDisp) {
|
|
|
|
if (pfDispUsedRoot) {
|
|
|
|
pfDisp->Next = pfDispUsedRoot;
|
|
|
|
}
|
|
|
|
pfDispUsedRoot = pfDisp;
|
|
pfDispUsedRoot->File = CloneString(pszTmp);
|
|
}
|
|
|
|
//
|
|
// Go to the next string in the list
|
|
//
|
|
|
|
while(*pszTmp++);
|
|
|
|
}
|
|
|
|
LocalFree(pszDisp);
|
|
}
|
|
|
|
//
|
|
// Finally mark the driver as ERROR_NORMAL now.
|
|
//
|
|
|
|
crv.SetErrorControlNormal();
|
|
|
|
}
|
|
|
|
/*****************************************************************\
|
|
*
|
|
* CDIALOG class
|
|
*
|
|
\*****************************************************************/
|
|
|
|
class CDIALOG {
|
|
|
|
protected:
|
|
HWND hwnd;
|
|
HWND hwndParent;
|
|
HINSTANCE hmodModule;
|
|
LPARAM lParam;
|
|
int iDlgResID;
|
|
void SetHWnd(HWND hwndNew) { this->hwnd = hwndNew; }
|
|
void SetHWndParent(HWND hwndNew) { this->hwndParent = hwndNew; }
|
|
friend BOOL CALLBACK DisplayDlgProc(HWND hwnd, UINT msg, WPARAM wParam,
|
|
LPARAM lParam);
|
|
|
|
friend DLGPROC NewDisplayDialogBox(HINSTANCE hmod, LPARAM *lplParam);
|
|
|
|
|
|
public:
|
|
int Dialog(HINSTANCE hmod, HWND hwndParentCaller, LPARAM lInitParam = 0);
|
|
|
|
HWND GetHWnd(void ) { return this->hwnd; }
|
|
HWND GetHWndParent(void ) { return this->hwndParent; }
|
|
HINSTANCE GetHMod(void ) { return this->hmodModule; }
|
|
|
|
|
|
LONG SendCtlMsg(int idCtl, UINT msg, WPARAM wParam, LPARAM lParam ) {
|
|
return SendDlgItemMessage(this->hwnd, idCtl, msg, wParam, lParam);
|
|
}
|
|
|
|
BOOL SetCtlInt(int idCtl, UINT uiValue, BOOL fSigned = TRUE) {
|
|
return SetDlgItemInt(this->hwnd, idCtl, uiValue, fSigned);
|
|
}
|
|
|
|
BOOL Disable(void ) { return EnableWindow(this->hwnd, FALSE); }
|
|
BOOL Enable(void ) { return EnableWindow(this->hwnd, TRUE); }
|
|
|
|
virtual BOOL WndProc(UINT msg, WPARAM wParam, LPARAM lParam);
|
|
virtual BOOL InitDlg(HWND hwndFocus) { return TRUE; } //BUGBUG - possible dead code!
|
|
virtual BOOL DoCommand(int idControl, HWND hwndControl, int iNoteCode ) = 0;
|
|
virtual BOOL DoNotify(int idControl, NMHDR *lpnmh, UINT iNoteCode ) { return FALSE; }
|
|
virtual BOOL HScroll(int idCtrl, int iCode, int iPos) { return FALSE; }
|
|
virtual BOOL Paint(void) { return FALSE; }
|
|
virtual BOOL OnDestroy(void) { return FALSE; }
|
|
virtual BOOL TimerTick(int id) { return FALSE; }
|
|
virtual BOOL InitMessage() { return FALSE; }
|
|
virtual BOOL SysColorChange(void) { return FALSE; }
|
|
virtual BOOL DoHelp( LPHELPINFO lphi );
|
|
virtual BOOL DoContextMenu( HWND hwnd, WORD xPos, WORD yPos );
|
|
|
|
};
|
|
|
|
typedef CDIALOG *PCDIALOG;
|
|
|
|
//
|
|
// Dialog method
|
|
//
|
|
// Creates the dialog box (shows it on the screen)
|
|
//
|
|
|
|
CDIALOG::Dialog(HINSTANCE hmod, HWND hwndCallerParent, LPARAM lInitParam) {
|
|
|
|
this->hwndParent = hwndCallerParent;
|
|
this->hmodModule = hmod;
|
|
this->lParam = lInitParam;
|
|
|
|
return DialogBoxParam(hmod, MAKEINTRESOURCE(this->iDlgResID),
|
|
this->hwndParent, (DLGPROC)::DisplayDlgProc, (LONG)this);
|
|
}
|
|
|
|
#if RESIZE_PROBLEM
|
|
LRESULT WINAPI MyProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (uMsg == WM_WINDOWPOSCHANGING)
|
|
{
|
|
RECT r;
|
|
ULONG currHeight, newHeight;
|
|
LPWINDOWPOS lpWinPos = (LPWINDOWPOS)lParam;
|
|
|
|
GetWindowRect(hwnd, &r);
|
|
|
|
currHeight = r.bottom - r.top;
|
|
newHeight = lpWinPos->cy;
|
|
|
|
if ( (!(lpWinPos->flags & SWP_NOSIZE)) &&
|
|
(currHeight != newHeight) &&
|
|
(newHeight < 350))
|
|
{
|
|
#if DBG
|
|
CHAR buffer[256];
|
|
|
|
sprintf(buffer, "!! IMPORTANT !!\n\n"
|
|
"We are trying to track down a bug in the system "
|
|
"where occasionally this display applet has its size "
|
|
"changed on the fly. We think that is about to happen "
|
|
"on your machine! Please contact ErickS, or AndreVa.\n\n"
|
|
"The current height is: %d\n"
|
|
"The new height is: %d",
|
|
currHeight,
|
|
newHeight);
|
|
|
|
MessageBoxA(hwnd, buffer, "NOTE: Please contact ErickS!",
|
|
MB_ICONSTOP | MB_OK);
|
|
|
|
#else
|
|
|
|
//
|
|
// Work around the problem by setting the SWP_NOSIZE
|
|
// flag. Now our window size won't change.
|
|
//
|
|
|
|
((LPWINDOWPOS)lParam)->flags |= SWP_NOSIZE;
|
|
#endif
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
else
|
|
{
|
|
return gOldProc(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// WndProc dialog
|
|
//
|
|
// cracks the messages and dispatches them to the virtual message methods
|
|
//
|
|
BOOL CDIALOG::WndProc(UINT msg, WPARAM wParam, LPARAM lParam) {
|
|
switch(msg) {
|
|
|
|
case WM_INITDIALOG:
|
|
|
|
#if RESIZE_PROBLEM
|
|
//
|
|
// Lets try to subclass our parent window at this time. Make
|
|
// sure we only do this once!!
|
|
//
|
|
|
|
if (gOldProc == NULL)
|
|
{
|
|
gOldProc = (WNDPROC) GetWindowLong(this->hwndParent, GWL_WNDPROC);
|
|
SetWindowLong(this->hwndParent, GWL_WNDPROC, (LONG)MyProc);
|
|
}
|
|
#endif
|
|
|
|
return this->InitDlg((HWND)wParam);
|
|
|
|
case WM_COMMAND:
|
|
return this->DoCommand((int)LOWORD(wParam), (HWND)lParam,
|
|
(int)HIWORD(wParam));
|
|
|
|
case WM_NOTIFY:
|
|
return this->DoNotify((int)wParam, (NMHDR *)lParam, ((NMHDR *)lParam)->code );
|
|
|
|
case WM_HSCROLL:
|
|
return this->HScroll(GetDlgCtrlID((HWND)lParam), LOWORD(wParam),
|
|
HIWORD(wParam));
|
|
|
|
case WM_PAINT:
|
|
return this->Paint();
|
|
|
|
case WM_TIMER:
|
|
return this->TimerTick((int)wParam);
|
|
|
|
case WM_DESTROY:
|
|
|
|
#if RESIZE_PROBLEM
|
|
//
|
|
// We should restore our parents original WndProc before returning...
|
|
//
|
|
|
|
if (gOldProc)
|
|
{
|
|
SetWindowLong(this->hwndParent, GWL_WNDPROC, (LONG)gOldProc);
|
|
gOldProc = NULL;
|
|
}
|
|
#endif
|
|
|
|
return this->OnDestroy();
|
|
|
|
case MSG_DSP_SETUP_MESSAGE:
|
|
return this->InitMessage();
|
|
|
|
case WM_SYSCOLORCHANGE:
|
|
case WM_DISPLAYCHANGE:
|
|
return this->SysColorChange();
|
|
|
|
case WM_HELP:
|
|
return this->DoHelp( (LPHELPINFO) lParam );
|
|
|
|
case WM_CONTEXTMENU:
|
|
return this->DoContextMenu( (HWND)wParam, LOWORD(lParam), HIWORD(lParam) );
|
|
|
|
default:
|
|
|
|
// if (msg == wHelpMessage) {
|
|
//
|
|
// return this->DoCommand(ID_DEFAULT_HELP, (HWND) NULL, 0);
|
|
//
|
|
// }
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
BOOL CDIALOG::DoHelp( LPHELPINFO lphi ) {
|
|
|
|
WinHelp((HWND) lphi->hItemHandle, NULL, HELP_WM_HELP, (DWORD) g_aiSetHelpIds);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CDIALOG::DoContextMenu( HWND hwnd, WORD xPos, WORD yPos ) {
|
|
|
|
WinHelp((HWND)hwnd, NULL, HELP_CONTEXTMENU, (DWORD) g_aiSetHelpIds);
|
|
return TRUE;
|
|
}
|
|
|
|
/*****************************************************************\
|
|
*
|
|
* CDLGSTARTUP class
|
|
*
|
|
* Dialog presented at startup.
|
|
*
|
|
* derived from CDIALOG
|
|
*
|
|
\*****************************************************************/
|
|
|
|
class CDLGSTARTUP : public CDIALOG {
|
|
protected:
|
|
|
|
LPTSTR pszDetectDevice;
|
|
|
|
public:
|
|
CDLGSTARTUP(LPTSTR pszDisplay);
|
|
~CDLGSTARTUP();
|
|
|
|
virtual BOOL InitDlg(HWND hwndFocus);
|
|
virtual BOOL DoCommand(int idControl, HWND hwndControl, int iNoteCode);
|
|
};
|
|
|
|
|
|
CDLGSTARTUP::CDLGSTARTUP(LPTSTR pszDisplay) {
|
|
|
|
CREGVIDOBJ rvoVideo(pszDisplay);
|
|
|
|
pszDetectDevice = FmtSprint(ID_DSP_TXT_COMPATABLE_DEV,
|
|
rvoVideo.GetMiniPort());
|
|
|
|
this->iDlgResID = DLG_SET_STARTUP;
|
|
|
|
}
|
|
|
|
CDLGSTARTUP::~CDLGSTARTUP() {
|
|
|
|
if (pszDetectDevice) {
|
|
|
|
LocalFree(pszDetectDevice);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BOOL CDLGSTARTUP::InitDlg(HWND hwndFocus) {
|
|
|
|
|
|
this->SendCtlMsg(ID_STARTUP_DETECT,
|
|
WM_SETTEXT,
|
|
(WPARAM) 0,
|
|
(LPARAM) pszDetectDevice);
|
|
|
|
return CDIALOG::InitDlg(hwndFocus);
|
|
|
|
}
|
|
|
|
BOOL CDLGSTARTUP::DoCommand(int idControl, HWND hwndControl, int iNoteCode ) {
|
|
|
|
switch(idControl ) {
|
|
|
|
case IDOK:
|
|
|
|
EndDialog(this->hwnd, 1);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*****************************************************************\
|
|
*
|
|
* CDLGCHGADAPTOR class
|
|
*
|
|
* derived from CDIALOG
|
|
*
|
|
\*****************************************************************/
|
|
|
|
class CDLGCHGADAPTOR : public CDIALOG {
|
|
protected:
|
|
int iRet;
|
|
|
|
public:
|
|
CDLGCHGADAPTOR();
|
|
|
|
virtual BOOL InitDlg(HWND hwndFocus);
|
|
virtual BOOL DoCommand(int idControl, HWND hwndControl, int iNoteCode);
|
|
};
|
|
|
|
CDLGCHGADAPTOR::CDLGCHGADAPTOR() : iRet(RET_NO_CHANGE) {
|
|
this->iDlgResID = DLG_SET_CHANGE_VID;
|
|
}
|
|
|
|
BOOL CDLGCHGADAPTOR::InitDlg(HWND hwndFocus) {
|
|
|
|
CREGVIDOBJ crvo(*(LPTSTR *)(this->lParam));
|
|
LPTSTR psz;
|
|
TCHAR szPath[MAX_PATH];
|
|
HDC hdc;
|
|
ULONG DrivVer;
|
|
HARDWARE_INFO hardwareInfo;
|
|
DWORD i;
|
|
|
|
//
|
|
// Get the installed driver names and put them in the dialog
|
|
//
|
|
|
|
psz = crvo.CloneDisplayFileNames(TRUE);
|
|
|
|
if (psz) {
|
|
|
|
this->SendCtlMsg(ID_ADP_CURFILES, WM_SETTEXT, 0, (LPARAM)psz);
|
|
LocalFree(psz);
|
|
|
|
}
|
|
|
|
//
|
|
// display the adaptor type
|
|
//
|
|
|
|
psz = crvo.CloneDescription();
|
|
|
|
if (psz) {
|
|
|
|
this->SendCtlMsg(ID_ADP_ADAPTOR, WM_SETTEXT, 0, (LPARAM)psz);
|
|
LocalFree(psz);
|
|
|
|
}
|
|
|
|
//
|
|
// Get the miniport driver path
|
|
//
|
|
|
|
wsprintf(szPath, TEXT("drivers\\%s.sys"), crvo.GetMiniPort());
|
|
|
|
//
|
|
// Open the file version resource for the driver
|
|
//
|
|
|
|
CFILEVER cfv(szPath);
|
|
|
|
//
|
|
// Get the company name and put it in the dialog
|
|
//
|
|
|
|
this->SendCtlMsg(ID_ADP_MANUFACT, WM_SETTEXT, 0,
|
|
(LPARAM)cfv.GetCompanyName());
|
|
|
|
//
|
|
// Get the version number from the miniport, and append "," and the
|
|
// display driver version number.
|
|
//
|
|
|
|
hdc = GetDC(this->hwnd);
|
|
DrivVer = GetDeviceCaps(hdc, DRIVERVERSION);
|
|
ReleaseDC(this->hwnd, hdc);
|
|
|
|
wsprintf(szPath, TEXT("%s, %d.%d.%d"), cfv.GetFileVer(),
|
|
(DrivVer >> 12) & 0xF, (DrivVer >> 8) & 0xF, DrivVer & 0xFF);
|
|
|
|
this->SendCtlMsg(ID_ADP_VERSION, WM_SETTEXT, 0, (LPARAM)szPath);
|
|
|
|
|
|
//
|
|
// Now put in the hardware information.
|
|
//
|
|
|
|
crvo.GetHardwareInformation(&hardwareInfo);
|
|
|
|
this->SendCtlMsg(ID_ADP_CHIP, WM_SETTEXT, 0, (LPARAM)hardwareInfo.ChipType);
|
|
this->SendCtlMsg(ID_ADP_DAC, WM_SETTEXT, 0, (LPARAM)hardwareInfo.DACType);
|
|
this->SendCtlMsg(ID_ADP_MEM, WM_SETTEXT, 0, (LPARAM)hardwareInfo.MemSize);
|
|
this->SendCtlMsg(ID_ADP_ADP_STRING, WM_SETTEXT, 0, (LPARAM)hardwareInfo.AdapString);
|
|
this->SendCtlMsg(ID_ADP_BIOS_INFO, WM_SETTEXT, 0, (LPARAM)hardwareInfo.BiosString);
|
|
|
|
for (i=0; i < 5; i++) {
|
|
|
|
if ( *(((LPTSTR *) (&hardwareInfo)) + i) != NULL) {
|
|
|
|
LocalFree(*(((LPTSTR *) (&hardwareInfo)) + i));
|
|
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CDLGCHGADAPTOR::DoCommand(int idControl, HWND hwndControl, int iNoteCode ) {
|
|
|
|
DWORD err;
|
|
BOOL bKeepEnabled = FALSE;
|
|
|
|
switch(idControl ) {
|
|
|
|
case IDCANCEL:
|
|
EndDialog(this->hwnd, iRet);
|
|
break;
|
|
|
|
case ID_ADP_DETECT:
|
|
case ID_ADP_CHGADP: {
|
|
|
|
LPTSTR lpsz;
|
|
|
|
if ( (gbExecMode == EXEC_SETUP) ||
|
|
(gbExecMode == EXEC_DETECT) ) {
|
|
|
|
//
|
|
// Can not change a driver during setup.
|
|
// run the control panel later on.
|
|
//
|
|
|
|
FmtMessageBox(this->hwnd,
|
|
MB_ICONINFORMATION,
|
|
FALSE,
|
|
ID_DSP_TXT_INSTALL_DRIVER,
|
|
ID_DSP_TXT_DRIVER_IN_SETUP_MODE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (IsUserAnAdmin() == FALSE)
|
|
{
|
|
FmtMessageBox(this->hwnd,
|
|
MB_ICONEXCLAMATION,
|
|
FALSE,
|
|
ID_DSP_TXT_INSTALL_DRIVER,
|
|
ID_DSP_TXT_ADMIN_CHANGE);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Let's get the current driver description, if it is available,
|
|
// so we can pass it as the default driver to select in setup.
|
|
//
|
|
|
|
CREGVIDOBJ crvo(*(LPTSTR *)(this->lParam));
|
|
|
|
crvo.EnableDriver(FALSE);
|
|
|
|
err = InstallNewDriver(hwnd,
|
|
crvo.CloneDescription(),
|
|
(idControl == ID_ADP_DETECT),
|
|
&bKeepEnabled);
|
|
|
|
|
|
if ((err != NO_ERROR) ||
|
|
(bKeepEnabled))
|
|
{
|
|
//
|
|
// Re-enable the driver if the installation failed.
|
|
//
|
|
|
|
crvo.EnableDriver(TRUE);
|
|
}
|
|
|
|
if (err == NO_ERROR)
|
|
{
|
|
//
|
|
// Remember the driver has been changed.
|
|
//
|
|
|
|
iRet = RET_CHANGED;
|
|
|
|
//
|
|
// Reset the buttons in the UI
|
|
//
|
|
|
|
lpsz = FmtSprint(ID_DSP_TXT_CLOSE);
|
|
this->SendCtlMsg(IDCANCEL, WM_SETTEXT, 0, (LPARAM)lpsz);
|
|
LocalFree(lpsz);
|
|
|
|
this->InitDlg(NULL);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*****************************************************************\
|
|
*
|
|
* CDLGMODELIST class
|
|
*
|
|
* derived from CDIALOG
|
|
*
|
|
\*****************************************************************/
|
|
|
|
class CDLGMODELIST : public CDIALOG {
|
|
|
|
public:
|
|
CDLGMODELIST();
|
|
|
|
void AddMode(LPDEVMODE lpdm);
|
|
|
|
virtual BOOL InitDlg(HWND hwndFocus);
|
|
virtual BOOL DoCommand(int idControl, HWND hwndControl, int iNoteCode);
|
|
VOID CDLGMODELIST::RecurseList(PCDEVMODE pcdevCurrent);
|
|
};
|
|
|
|
typedef CDLGMODELIST *PCDLGMODELIST;
|
|
|
|
CDLGMODELIST::CDLGMODELIST() {
|
|
this->iDlgResID = DLG_SET_MODE_LIST;
|
|
}
|
|
|
|
BOOL CDLGMODELIST::InitDlg(HWND hwndFocus) {
|
|
|
|
PCDEVMODE pcModeList = (*(PCDEVMODELST *)(this->lParam))->GetDevmodeList();
|
|
|
|
//
|
|
// The first entry in the list is NULL, so ignore it.
|
|
//
|
|
|
|
RecurseList(pcModeList->NextDevMode());
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID CDLGMODELIST::RecurseList(PCDEVMODE pcdevCurrent) {
|
|
|
|
LPTSTR lpsz;
|
|
int i;
|
|
DWORD id;
|
|
LPDEVMODE lpdm = pcdevCurrent->GetData();
|
|
|
|
//
|
|
// Recursive call till we hit the end of the list.
|
|
//
|
|
|
|
if ((pcdevCurrent->NextDevMode()) != NULL) {
|
|
|
|
RecurseList(pcdevCurrent->NextDevMode());
|
|
|
|
}
|
|
|
|
//
|
|
// Add it to the list
|
|
//
|
|
|
|
if (lpdm->dmDisplayFrequency == 1) {
|
|
|
|
if (lpdm->dmBitsPerPel < 32) {
|
|
|
|
id = ID_DSP_TXT_COLOR_MODE_DEF_REF;
|
|
|
|
} else {
|
|
|
|
id = ID_DSP_TXT_TRUE_COLOR_MODE_DEF_REF;
|
|
|
|
}
|
|
|
|
} else if (lpdm->dmDisplayFrequency < 50) {
|
|
|
|
if (lpdm->dmBitsPerPel < 32) {
|
|
|
|
id = ID_DSP_TXT_COLOR_MODE_INT_REF;
|
|
|
|
} else {
|
|
|
|
id = ID_DSP_TXT_TRUE_COLOR_MODE_INT_REF;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (lpdm->dmBitsPerPel < 32) {
|
|
|
|
id = ID_DSP_TXT_COLOR_MODE;
|
|
|
|
} else {
|
|
|
|
id = ID_DSP_TXT_TRUE_COLOR_MODE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lpsz = FmtSprint(id,
|
|
lpdm->dmPelsWidth,
|
|
lpdm->dmPelsHeight,
|
|
1 << lpdm->dmBitsPerPel,
|
|
lpdm->dmDisplayFrequency);
|
|
|
|
#if DBG
|
|
{
|
|
WCHAR pszMode[1024];
|
|
|
|
swprintf(pszMode, L"%ws%ws", lpsz,
|
|
pcdevCurrent->bModeTested() ? L" - Tested" : L"");
|
|
|
|
i = this->SendCtlMsg(ID_MODE_LIST, LB_ADDSTRING, 0, (LPARAM)pszMode);
|
|
}
|
|
#else
|
|
|
|
i = this->SendCtlMsg(ID_MODE_LIST, LB_ADDSTRING, 0, (LPARAM)lpsz);
|
|
|
|
#endif
|
|
|
|
LocalFree(lpsz);
|
|
|
|
//
|
|
// Save the devmode pointer in the data field of the list so we can
|
|
// retrieve it when the user selects the entry.
|
|
//
|
|
|
|
this->SendCtlMsg(ID_MODE_LIST, LB_SETITEMDATA, i, (LPARAM)lpdm);
|
|
|
|
return;
|
|
}
|
|
|
|
BOOL CDLGMODELIST::DoCommand(int idControl, HWND hwndControl, int iNoteCode ) {
|
|
|
|
int iSel;
|
|
LPDEVMODE lpdm;
|
|
|
|
switch(idControl ) {
|
|
|
|
case ID_MODE_LIST:
|
|
|
|
if (iNoteCode != LBN_DBLCLK) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If we do get a double click, then fall through as an OK
|
|
//
|
|
|
|
case IDOK:
|
|
|
|
//
|
|
// get the selected driver id.
|
|
//
|
|
|
|
iSel = this->SendCtlMsg(ID_MODE_LIST, LB_GETCURSEL, 0, 0);
|
|
|
|
if (iSel == LB_ERR ||
|
|
(lpdm = (LPDEVMODE) (this->SendCtlMsg(ID_MODE_LIST,
|
|
LB_GETITEMDATA,
|
|
iSel,
|
|
0))) == NULL) {
|
|
|
|
lpdm = NULL;
|
|
|
|
}
|
|
|
|
EndDialog(this->hwnd, (int)lpdm);
|
|
|
|
break;
|
|
|
|
case IDCANCEL:
|
|
EndDialog(this->hwnd, 0);
|
|
break;
|
|
|
|
default:
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*****************************************************************\
|
|
*
|
|
* CDISPLAYDLG class
|
|
*
|
|
* derived from CDIALOG
|
|
*
|
|
\*****************************************************************/
|
|
|
|
class CDISPLAYDLG : public CDIALOG {
|
|
protected:
|
|
CMONITOR monitor;
|
|
CCOLORBAR clrbar;
|
|
|
|
LPTSTR pszDisplay;
|
|
PCDEVMODELST pcdmlModes;
|
|
|
|
int iOrgResolution;
|
|
int iOrgColor;
|
|
int iOrgFrequency;
|
|
|
|
int iResolution;
|
|
int iColor;
|
|
int iFrequency;
|
|
|
|
int cResolutions;
|
|
|
|
//
|
|
// current log pixels of the screen.
|
|
// does not change !
|
|
|
|
int cLogPix;
|
|
|
|
//
|
|
// Determines if the current adapter is the adapter that was booted with.
|
|
//
|
|
|
|
BOOL fActiveDsp;
|
|
|
|
BOOL bBadDriver;
|
|
|
|
//
|
|
// When a new driver is installed, we don't want to save the parameters
|
|
// to the registry.
|
|
//
|
|
|
|
BOOL bNewDriver;
|
|
|
|
public:
|
|
CDISPLAYDLG();
|
|
~CDISPLAYDLG();
|
|
|
|
VOID vPreExecMode();
|
|
VOID vPostExecMode();
|
|
|
|
BOOL SaveParamsToReg();
|
|
|
|
void SetCurColor(int iClr);
|
|
void SetCurFrequency(int iFreq);
|
|
void SetCurResolution(int iRes);
|
|
|
|
void ForceSmallFont( BOOL fDoit );
|
|
|
|
BOOL InitEverything();
|
|
BOOL InitFontList(void);
|
|
|
|
BOOL bDoClean(void);
|
|
|
|
|
|
virtual BOOL InitDlg(HWND hwndFocus);
|
|
virtual BOOL DoCommand(int idControl, HWND hwndControl, int iNoteCode);
|
|
virtual BOOL DoNotify(int idControl, NMHDR *lpnmh, UINT iNoteCode );
|
|
virtual BOOL HScroll(int idCtrl, int iCode, int iPos);
|
|
virtual BOOL Paint(void);
|
|
virtual BOOL InitMessage();
|
|
virtual BOOL SysColorChange( void );
|
|
|
|
};
|
|
|
|
typedef CDISPLAYDLG *PDISPLAYDLG;
|
|
|
|
//
|
|
// Constructor for CDISPLAYDLG
|
|
//
|
|
// (gets called when ever a CDISPLAYDLG object is created)
|
|
//
|
|
|
|
CDISPLAYDLG::CDISPLAYDLG() : cResolutions(0), pszDisplay(NULL),
|
|
bBadDriver(FALSE), bNewDriver(FALSE) {
|
|
|
|
this->iDlgResID = DLG_SET_DISPLAY;
|
|
|
|
HKEY hkFont;
|
|
DWORD cb;
|
|
|
|
pcdmlModes = new CDEVMODELST;
|
|
|
|
//
|
|
// For font size just always use the one of the current screen.
|
|
// Whether or not we are testing the current screen.
|
|
//
|
|
|
|
cLogPix = 96;
|
|
|
|
//
|
|
// If the size does not match what is in the registry, then install
|
|
// the new one
|
|
//
|
|
|
|
if ((RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
SZ_FONTDPI_PROF,
|
|
0,
|
|
KEY_READ,
|
|
&hkFont) == ERROR_SUCCESS) ||
|
|
(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
SZ_FONTDPI,
|
|
0,
|
|
KEY_READ,
|
|
&hkFont) == ERROR_SUCCESS)) {
|
|
|
|
cb = sizeof(DWORD);
|
|
|
|
if (RegQueryValueEx(hkFont,
|
|
SZ_LOGPIXELS,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE) &cLogPix,
|
|
&cb) != ERROR_SUCCESS) {
|
|
|
|
cLogPix = 96;
|
|
|
|
}
|
|
|
|
RegCloseKey(hkFont);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Destructor
|
|
//
|
|
CDISPLAYDLG::~CDISPLAYDLG() {
|
|
if (pszDisplay != NULL)
|
|
LocalFree(pszDisplay);
|
|
|
|
if (pcdmlModes != NULL) {
|
|
|
|
delete pcdmlModes;
|
|
pcdmlModes = NULL;
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// InitDlg method
|
|
//
|
|
|
|
BOOL CDISPLAYDLG::InitDlg(HWND hwndFocus) {
|
|
|
|
int cb;
|
|
RECT rc;
|
|
HDC hdc;
|
|
int cxRes, cyRes;
|
|
int passes;
|
|
|
|
//
|
|
// Determine in what mode we are running the applet before getting
|
|
// information
|
|
//
|
|
|
|
vPreExecMode();
|
|
|
|
//
|
|
// Tell Monitor picture where it should paint itself
|
|
//
|
|
|
|
GetWindowRect(GetDlgItem(this->hwnd, ID_DSP_REPRESENT), &rc);
|
|
ScreenToClient(this->hwnd, (LPPOINT)&(rc.left));
|
|
ScreenToClient(this->hwnd, (LPPOINT)&(rc.right));
|
|
|
|
this->monitor.SetPosition(this->hwnd, &rc);
|
|
|
|
//
|
|
// Tell Color bar where it should paint itself
|
|
//
|
|
|
|
GetWindowRect(GetDlgItem(this->hwnd, ID_DSP_COLORBAR), &rc);
|
|
ScreenToClient(this->hwnd, (LPPOINT)&(rc.left));
|
|
ScreenToClient(this->hwnd, (LPPOINT)&(rc.right));
|
|
|
|
this->clrbar.SetPosition(this->hwnd, &rc);
|
|
|
|
//
|
|
// Now tell the entire window where to paint itself (centered).
|
|
//
|
|
|
|
GetWindowRect(this->hwnd, &rc);
|
|
hdc = GetDC(this->hwnd);
|
|
cxRes = GetDeviceCaps(hdc, HORZRES);
|
|
cyRes = GetDeviceCaps(hdc, VERTRES);
|
|
|
|
|
|
cxRes = (cxRes - (rc.right - rc.left)) / 2;
|
|
cyRes = (cyRes - (rc.bottom - rc.top)) / 2;
|
|
|
|
SetWindowPos(this->hwnd,
|
|
0,
|
|
cxRes < 1 ? 1 : cxRes,
|
|
cyRes < 1 ? 1 : cyRes,
|
|
0,
|
|
0,
|
|
SWP_NOSIZE | SWP_NOZORDER);
|
|
|
|
//
|
|
// If we are in setupmode, and someone wants a driver automatically
|
|
// installed, install it before we enum the drivers and configure them.
|
|
//
|
|
|
|
if (gUnattenedInstall)
|
|
{
|
|
UNICODE_STRING UnicodeString;
|
|
TCHAR ServiceName[MAX_PATH];
|
|
NTSTATUS Status;
|
|
BOOLEAN PrivEnabled;
|
|
LPTSTR lpUnattenedPszOptionEnd = gUnattenedPszOption;
|
|
LPTSTR lpUnattenedPszInfEnd = gUnattenedPszInf;
|
|
LPTSTR lpUnattenedPszOption = gUnattenedPszOption;
|
|
LPTSTR lpUnattenedPszInf = gUnattenedPszInf;
|
|
|
|
//
|
|
// Transform the string to a MULTI_SZ
|
|
//
|
|
|
|
do
|
|
{
|
|
if (*lpUnattenedPszOptionEnd == TEXT(','))
|
|
{
|
|
*lpUnattenedPszOptionEnd = 0;
|
|
lpUnattenedPszOptionEnd++;
|
|
}
|
|
} while (*lpUnattenedPszOptionEnd++);
|
|
|
|
lpUnattenedPszOptionEnd = 0;
|
|
|
|
do
|
|
{
|
|
if (*lpUnattenedPszInfEnd == TEXT(','))
|
|
{
|
|
*lpUnattenedPszInfEnd = 0;
|
|
lpUnattenedPszInfEnd++;
|
|
}
|
|
} while (*lpUnattenedPszInfEnd++);
|
|
|
|
//
|
|
// Install all the specified drivers in a loop.
|
|
// If an error occurs (except in LoadDriver), just go straight to
|
|
// the cleanup so the machine boots in VGA.
|
|
//
|
|
|
|
while (*lpUnattenedPszOption && *lpUnattenedPszInf)
|
|
{
|
|
if (PreInstallDriver(this->hwnd,
|
|
lpUnattenedPszOption,
|
|
lpUnattenedPszInf,
|
|
ServiceName) != NO_ERROR)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Let's try to load the driver on the fly
|
|
//
|
|
|
|
Status = RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE,
|
|
TRUE,
|
|
FALSE,
|
|
&PrivEnabled);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
RtlInitUnicodeString(&UnicodeString,
|
|
ServiceName);
|
|
|
|
//
|
|
// Don't check the return value since it is OK to fail the
|
|
// driver if the hardware is not present.
|
|
// The driver will get cleaned up properly upon exit from the
|
|
// applet
|
|
//
|
|
|
|
Status = NtLoadDriver(&UnicodeString);
|
|
|
|
RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE,
|
|
PrivEnabled,
|
|
FALSE,
|
|
&PrivEnabled);
|
|
|
|
//
|
|
// If we loaded the driver successfully, then try to
|
|
// reenumerate the device list and find the driver in there.
|
|
// Otherwise ask the user if this driver should really be
|
|
// kept around.
|
|
//
|
|
}
|
|
|
|
//
|
|
// These are MULTI_SZ strings, except they can have initial spaces
|
|
//
|
|
|
|
while (*lpUnattenedPszOption++ != 0);
|
|
while (*lpUnattenedPszOption == TEXT(' '))
|
|
{
|
|
lpUnattenedPszOption++;
|
|
}
|
|
|
|
while (*lpUnattenedPszInf++ != 0);
|
|
while (*lpUnattenedPszInf == TEXT(' '))
|
|
{
|
|
lpUnattenedPszInf++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Force the screen to repeint in case the detection messed up
|
|
// the contents of the screen.
|
|
//
|
|
|
|
ChangeDisplaySettings(NULL, CDS_RESET);
|
|
}
|
|
|
|
//
|
|
// Get the current primary device and all it's information
|
|
//
|
|
// Which driver do we want to display by default ?
|
|
//
|
|
// 1) The primary - unless VGA
|
|
// 2) A non-primary, to avoid VGA.
|
|
// 3) Anything
|
|
//
|
|
|
|
for (passes = 1; (passes <= 3) && (this->pszDisplay == NULL); passes++)
|
|
{
|
|
int iDevNum = 1;
|
|
DISPLAY_DEVICE displayDevice;
|
|
|
|
displayDevice.cb = sizeof(DISPLAY_DEVICE);
|
|
|
|
while (EnumDisplayDevices(NULL, iDevNum++, &displayDevice))
|
|
{
|
|
fActiveDsp = displayDevice.StateFlags &
|
|
DISPLAY_DEVICE_PRIMARY_DEVICE;
|
|
|
|
if (passes == 1)
|
|
{
|
|
//
|
|
// Search for the primary.
|
|
//
|
|
|
|
if (fActiveDsp)
|
|
{
|
|
CREGVIDOBJ crv(displayDevice.DeviceName);
|
|
|
|
LPTSTR pszMini = crv.GetMiniPort();
|
|
|
|
//
|
|
// If VGA is active, then go to pass 2.
|
|
// Otherwise, let's try to use this device
|
|
//
|
|
|
|
if (pszMini && (!lstrcmpi(TEXT("vga"), pszMini)))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
|
|
}
|
|
else if (passes == 2)
|
|
{
|
|
//
|
|
// Search for a non-primary, and try that for initialization.
|
|
//
|
|
|
|
if (fActiveDsp)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If we make it to pass 3, then we want to try any device
|
|
//
|
|
}
|
|
|
|
|
|
//
|
|
// Save the name of this device for later use.
|
|
//
|
|
|
|
this->pszDisplay = CloneString(displayDevice.DeviceName);
|
|
|
|
//
|
|
// Try to initialize the applet.
|
|
// If for some reason this fails, then we return and
|
|
// try the next device (just like the system init code does).
|
|
//
|
|
// In this case we want to make the sure the "old driver" pop-up
|
|
// shows up.
|
|
//
|
|
|
|
if (this->InitEverything() == TRUE)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We failed. Try the next video device.
|
|
//
|
|
|
|
bBadDriver = TRUE;
|
|
|
|
LocalFree(this->pszDisplay);
|
|
this->pszDisplay = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the active display did not work, give it a last try with the active
|
|
// device
|
|
//
|
|
|
|
if (this->pszDisplay == NULL)
|
|
{
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
//
|
|
// Determine if any errors showed up during enumerations and initialization
|
|
//
|
|
|
|
vPostExecMode();
|
|
|
|
//
|
|
// Now tell the user what we found out during initialization
|
|
// Errors, or what we found during detection
|
|
//
|
|
|
|
PostMessage(this->hwnd, MSG_DSP_SETUP_MESSAGE, 0, 0);
|
|
|
|
//
|
|
// Since this could have taken a very long time, just make us visible
|
|
// if another app (like progman) came up.
|
|
//
|
|
|
|
ShowWindow(this->hwnd, SW_SHOW);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// InitEveryting
|
|
//
|
|
// Inits all the controls in the list box and bulids the devmode matrix
|
|
//
|
|
|
|
BOOL CDISPLAYDLG::InitEverything() {
|
|
|
|
int i;
|
|
DEVMODE defaultdm;
|
|
PCDEVMODE pcdev;
|
|
int iResOk, iClrOk, iFreqOk;
|
|
|
|
//
|
|
// Clear out old values
|
|
//
|
|
|
|
if (pcdmlModes != NULL) {
|
|
|
|
delete pcdmlModes;
|
|
pcdmlModes = NULL;
|
|
|
|
}
|
|
|
|
this->SendCtlMsg(ID_DSP_COLORBOX, CB_RESETCONTENT, 0, 0);
|
|
this->SendCtlMsg(ID_DSP_FREQ, CB_RESETCONTENT, 0, 0);
|
|
this->SendCtlMsg(ID_DSP_FONTSIZE, CB_RESETCONTENT, 0, 0);
|
|
|
|
//
|
|
// Clear cached values for selected modes.
|
|
// These are reset at the end of the routine before exiting.
|
|
//
|
|
|
|
this->iColor = -1;
|
|
this->iFrequency = -1;
|
|
this->iResolution = -1;
|
|
|
|
//
|
|
// Clear initial mode value.
|
|
// Setting all these values to -1 means the user has to save on OK.
|
|
//
|
|
|
|
this->iOrgResolution = -1;
|
|
this->iOrgColor = -1;
|
|
this->iOrgFrequency = -1;
|
|
|
|
//
|
|
// new matrix storage
|
|
//
|
|
|
|
pcdmlModes = new CDEVMODELST;
|
|
|
|
#if 0
|
|
|
|
HDC hdc;
|
|
|
|
//
|
|
// This code will determine exactly what bit depth the video mode
|
|
// is set at.
|
|
//
|
|
|
|
hdc = GetDC(this->hwnd);
|
|
|
|
cxRes = GetDeviceCaps(hdc, DESKTOPHORZRES);
|
|
cyRes = GetDeviceCaps(hdc, DESKTOPVERTRES);
|
|
cClr = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES);
|
|
chzRefresh = GetDeviceCaps(hdc, VREFRESH);
|
|
|
|
if (cClr == 16) {
|
|
|
|
BYTE ajBitmapInfo[sizeof(BITMAPINFO) + 3 * sizeof(DWORD)];
|
|
BITMAPINFO *pbmi;
|
|
HBITMAP hbm;
|
|
|
|
pbmi = (BITMAPINFO *) ajBitmapInfo;
|
|
|
|
//
|
|
// Some devices that are actually 15bpp have to return 16bpp
|
|
// for compatibility, but we need to know the precise bits
|
|
// per pixel so that we can distinguish between available 15bpp
|
|
// and 16bpp modes. As such, we call GDI to determine the
|
|
// RGB bit masks, and we count the bits in those.
|
|
//
|
|
// First, we need a compatible bitmap from which to query:
|
|
//
|
|
|
|
hbm = CreateCompatibleBitmap(hdc, 1, 1);
|
|
if (hbm != 0) {
|
|
|
|
//
|
|
// Now call GetDIBits to fill in our bitmap info header:
|
|
//
|
|
|
|
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
pbmi->bmiHeader.biBitCount = 0;
|
|
|
|
if (GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS)) {
|
|
|
|
if (pbmi->bmiHeader.biCompression == BI_BITFIELDS) {
|
|
|
|
//
|
|
// Now call GetDIBits to fill in the colour table.
|
|
//
|
|
|
|
if (GetDIBits(hdc, hbm, 0, pbmi->bmiHeader.biHeight, NULL,
|
|
pbmi, DIB_RGB_COLORS)) {
|
|
|
|
DWORD *adwMask;
|
|
DWORD dwMask;
|
|
|
|
adwMask = (DWORD *) &pbmi->bmiColors[0];
|
|
|
|
dwMask = adwMask[0] | adwMask[1] | adwMask[2];
|
|
|
|
//
|
|
// Okay, we can now count the number of bits in the
|
|
// masks to determine the true bits per pixel.
|
|
//
|
|
|
|
for (cClr = 0; dwMask != 0; dwMask >>= 1) {
|
|
|
|
if (dwMask & 1) {
|
|
|
|
cClr++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Let's be paranoid, since we're so close to shipping.
|
|
//
|
|
|
|
if ((cClr != 15) && (cClr != 16)) {
|
|
|
|
cClr = 16;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Default DIB format for non BI_BITFIELDS.
|
|
//
|
|
|
|
cClr = 15;
|
|
}
|
|
}
|
|
|
|
DeleteObject(hbm);
|
|
}
|
|
}
|
|
|
|
ReleaseDC(this->hwnd, hdc);
|
|
|
|
defaultdm.dmBitsPerPel = cClr;
|
|
defaultdm.dmPelsWidth = cxRes;
|
|
defaultdm.dmPelsHeight = cyRes;
|
|
defaultdm.dmDisplayFrequency = chzRefresh;
|
|
defaultdm.dmDisplayFlags = 0;
|
|
|
|
#endif
|
|
|
|
//
|
|
// Try to build the list of mode.
|
|
//
|
|
|
|
if (pcdmlModes->BuildList(this->pszDisplay, this->hwnd) == FALSE) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Tell the controls what their valid values are.
|
|
//
|
|
|
|
cResolutions = pcdmlModes->GetResCount();
|
|
this->SendCtlMsg(ID_DSP_AREA_SB, TBM_SETRANGE, TRUE, MAKELONG(0, cResolutions - 1));
|
|
|
|
for (i = 0; i < pcdmlModes->GetClrCount(); i++) {
|
|
|
|
int cBits;
|
|
LPTSTR lpszColor;
|
|
|
|
//
|
|
// convert bit count to number of colors and make it a string
|
|
//
|
|
|
|
cBits = pcdmlModes->ColorFromIndex(i);
|
|
|
|
if (cBits == 32) {
|
|
|
|
lpszColor = FmtSprint(ID_DSP_TXT_TRUECOLOR);
|
|
|
|
} else {
|
|
|
|
lpszColor = FmtSprint(ID_DSP_TXT_COLOR, (1 << cBits));
|
|
|
|
}
|
|
|
|
this->SendCtlMsg(ID_DSP_COLORBOX, CB_INSERTSTRING, i,
|
|
(LPARAM)lpszColor);
|
|
|
|
LocalFree(lpszColor);
|
|
}
|
|
|
|
for (i = 0; i < pcdmlModes->GetFreqCount(); i++) {
|
|
|
|
LPTSTR lpszFreq;
|
|
int cHz = pcdmlModes->FreqFromIndex(i);
|
|
|
|
//
|
|
// convert bit count to number of colors and make it a string.
|
|
//
|
|
|
|
if ((cHz == 0) ||
|
|
(cHz == 1) ) {
|
|
|
|
lpszFreq = FmtSprint(ID_DSP_TXT_DEFFREQ);
|
|
|
|
} else if (cHz < 50) {
|
|
|
|
lpszFreq = FmtSprint(ID_DSP_TXT_INTERLACED, cHz);
|
|
|
|
|
|
} else {
|
|
|
|
lpszFreq = FmtSprint(ID_DSP_TXT_FREQ, cHz);
|
|
}
|
|
|
|
this->SendCtlMsg(ID_DSP_FREQ, CB_INSERTSTRING, i,
|
|
(LPARAM)lpszFreq);
|
|
|
|
LocalFree(lpszFreq);
|
|
}
|
|
|
|
//
|
|
// These values
|
|
//
|
|
|
|
iResOk = 0;
|
|
iClrOk = 0;
|
|
iFreqOk = 0;
|
|
|
|
pcdev = NULL;
|
|
|
|
//
|
|
// If the device we are getting the modes for is the current device,
|
|
// then lets get the current system mode.
|
|
// We will want to mark that mode as pretested.
|
|
//
|
|
|
|
if (fActiveDsp) {
|
|
|
|
int iRes, iClr, iFreq;
|
|
|
|
RtlZeroMemory(&defaultdm, sizeof(DEVMODE));
|
|
defaultdm.dmSize = sizeof(DEVMODE);
|
|
|
|
if (EnumDisplaySettings(this->pszDisplay, (ULONG) -1, &defaultdm))
|
|
{
|
|
PCDEVMODE pcdev;
|
|
|
|
iRes = pcdmlModes->IndexFromResXY(defaultdm.dmPelsWidth,
|
|
defaultdm.dmPelsHeight);
|
|
iClr = pcdmlModes->IndexFromColor(defaultdm.dmBitsPerPel);
|
|
iFreq = pcdmlModes->IndexFromFreq(defaultdm.dmDisplayFrequency);
|
|
|
|
if (pcdev = pcdmlModes->LookUp(iRes, iClr, iFreq))
|
|
{
|
|
pcdev->vTestMode(TRUE);
|
|
iResOk = iRes;
|
|
iClrOk = iClr;
|
|
iFreqOk = iFreq;
|
|
|
|
//
|
|
// For the active display, set the original values to the current
|
|
// values. These might be invalid values, such as -1, in the
|
|
// case of setup or a bad_mode in the registry ...
|
|
//
|
|
|
|
iOrgResolution = iRes;
|
|
iOrgColor = iClr;
|
|
iOrgFrequency = iFreq;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Let's get the mode that is in the registry.
|
|
// We will use this mode to set the default settings of the controls.
|
|
//
|
|
|
|
RtlZeroMemory(&defaultdm, sizeof(DEVMODE));
|
|
defaultdm.dmSize = sizeof(DEVMODE);
|
|
|
|
if (EnumDisplaySettings(this->pszDisplay, (ULONG) -2, &defaultdm))
|
|
{
|
|
int iRes, iClr, iFreq;
|
|
|
|
iRes = pcdmlModes->IndexFromResXY(defaultdm.dmPelsWidth,
|
|
defaultdm.dmPelsHeight);
|
|
iClr = pcdmlModes->IndexFromColor(defaultdm.dmBitsPerPel);
|
|
iFreq = pcdmlModes->IndexFromFreq(defaultdm.dmDisplayFrequency);
|
|
|
|
if (pcdev = pcdmlModes->LookUp(iRes, iClr, iFreq))
|
|
{
|
|
//
|
|
// We found a mode in the registry. We will use this mode as
|
|
// the new default ofr the applet since someone could have
|
|
// changed the mode on the fly, and the current active mode
|
|
// would not be the "current state of the machine".
|
|
//
|
|
|
|
iResOk = iRes;
|
|
iClrOk = iClr;
|
|
iFreqOk = iFreq;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// BUGBUG - if the mode in the registry does not work, we should
|
|
// generate and error here (this needs to be done in conjunction
|
|
// with the code in USER.
|
|
//
|
|
|
|
}
|
|
}
|
|
|
|
|
|
if (pcdev == NULL)
|
|
{
|
|
//
|
|
// If the current mode is invalid, and there is no mode in the
|
|
// registry that we can read, then we are in some sort of setup mode.
|
|
// Try to use the setup values that are passed in by setup.
|
|
//
|
|
|
|
//
|
|
// Try to find the mode that matches the predefined parameters
|
|
// set during setup.
|
|
// If they are not valid, we will find the closest match.
|
|
//
|
|
// Try to find a 60 Hz Mode if no frequency is specified.
|
|
// Try to find a 256 color mode if no color depth is defined
|
|
//
|
|
|
|
if (gUnattenedVRefresh == 0) {
|
|
gUnattenedVRefresh = 60;
|
|
}
|
|
|
|
if (gUnattenedBitsPerPel == 0) {
|
|
gUnattenedBitsPerPel = 8;
|
|
}
|
|
|
|
// DbgPrint("VRefresh = %d BitsPerPel = %d XResolution = %d YResolution = %d \n",
|
|
// gUnattenedVRefresh, gUnattenedBitsPerPel,
|
|
// gUnattenedXResolution, gUnattenedYResolution);
|
|
|
|
iFreqOk = pcdmlModes->IndexFromFreq(gUnattenedVRefresh);
|
|
iClrOk = pcdmlModes->IndexFromColor(gUnattenedBitsPerPel);
|
|
iResOk = pcdmlModes->IndexFromResXY(gUnattenedXResolution,
|
|
gUnattenedYResolution);
|
|
|
|
if (iFreqOk == -1) {
|
|
iFreqOk = 0;
|
|
}
|
|
if (iResOk == -1) {
|
|
iResOk = 0;
|
|
}
|
|
if (iClrOk == -1) {
|
|
iClrOk = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set the fonts. This must be done before calling SetCurResolution
|
|
//
|
|
|
|
this->InitFontList();
|
|
|
|
//
|
|
// Call FindClosest mode to make sure we actually have a valid mode
|
|
// show up in the display applet.
|
|
//
|
|
|
|
pcdmlModes->FindClosestMode(iResOk, &iClrOk, &iFreqOk);
|
|
|
|
this->SetCurResolution(iResOk);
|
|
this->SetCurColor(iClrOk);
|
|
this->SetCurFrequency(iFreqOk);
|
|
|
|
// Recompute bitmaps incase syscolors have changed since when this dialog object was constructed
|
|
// and the dialog has been shown for this first time.
|
|
this->SysColorChange();
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
// Init Font sizes
|
|
//
|
|
// Read the supported fonts out of the inf file(s)
|
|
// Select was the user currently has.
|
|
//
|
|
|
|
BOOL CDISPLAYDLG::InitFontList() {
|
|
|
|
HINF InfFileHandle;
|
|
INFCONTEXT infoContext;
|
|
int i;
|
|
ULONG currentSel = (ULONG) -1;
|
|
|
|
//
|
|
// Get all font entries from both inf files
|
|
//
|
|
|
|
InfFileHandle = SetupOpenInfFile(TEXT("font.inf"),
|
|
NULL,
|
|
INF_STYLE_WIN4,
|
|
NULL);
|
|
|
|
if (InfFileHandle != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (SetupFindFirstLine(InfFileHandle,
|
|
TEXT("Font Sizes"),
|
|
NULL,
|
|
&infoContext))
|
|
{
|
|
while(TRUE)
|
|
{
|
|
int cPix = 0;
|
|
TCHAR awcDesc[LINE_LEN];
|
|
|
|
if (SetupGetStringField(&infoContext,
|
|
0,
|
|
awcDesc,
|
|
sizeof(awcDesc),
|
|
NULL) &&
|
|
SetupGetIntField(&infoContext,
|
|
1,
|
|
&cPix))
|
|
{
|
|
//
|
|
// Add it to the list box
|
|
//
|
|
|
|
i = this->SendCtlMsg(ID_DSP_FONTSIZE,
|
|
CB_ADDSTRING,
|
|
0,
|
|
(LPARAM) awcDesc);
|
|
|
|
this->SendCtlMsg(ID_DSP_FONTSIZE,
|
|
CB_SETITEMDATA,
|
|
i,
|
|
cPix);
|
|
|
|
if (cLogPix == cPix)
|
|
{
|
|
currentSel = i;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Try to get the next line.
|
|
//
|
|
|
|
if (!SetupFindNextLine(&infoContext,
|
|
&infoContext))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
SetupCloseInfFile(InfFileHandle);
|
|
}
|
|
|
|
//
|
|
// Put in the empty entry if necessary.
|
|
//
|
|
|
|
if (currentSel == (ULONG) -1)
|
|
{
|
|
LPTSTR lpszNoFonts;
|
|
|
|
//
|
|
// Put a line that says <No Fonts>
|
|
//
|
|
|
|
lpszNoFonts = FmtSprint(ID_DSP_NO_FONTS_AVAIL);
|
|
|
|
i = this->SendCtlMsg(ID_DSP_FONTSIZE, CB_ADDSTRING, 0,
|
|
(LPARAM) lpszNoFonts);
|
|
|
|
this->SendCtlMsg(ID_DSP_FONTSIZE, CB_SETITEMDATA, i, 0);
|
|
|
|
currentSel = i;
|
|
}
|
|
|
|
//
|
|
// Select the right entry.
|
|
//
|
|
|
|
this->SendCtlMsg(ID_DSP_FONTSIZE, CB_SETCURSEL, currentSel, 0);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// SaveParamsToReg
|
|
//
|
|
// Writes the new display parameters to the proper place in the
|
|
// registry.
|
|
//
|
|
|
|
BOOL CDISPLAYDLG::SaveParamsToReg() {
|
|
|
|
CREGVIDOBJ rvoVideo(this->pszDisplay);
|
|
|
|
int cOk = 0;
|
|
int cx, cy;
|
|
int chzFreq;
|
|
int cFontSize = 0;
|
|
|
|
int i;
|
|
|
|
//
|
|
// Save all of the new values out to the registry
|
|
//
|
|
|
|
//
|
|
// Resolution color bits and frequency
|
|
//
|
|
|
|
PCDEVMODE pcdev;
|
|
|
|
pcdev = pcdmlModes->LookUp(this->iResolution,
|
|
this->iColor,
|
|
this->iFrequency);
|
|
|
|
pcdmlModes->ResXYFromIndex(this->iResolution, &cx, &cy);
|
|
chzFreq = pcdmlModes->FreqFromIndex(this->iFrequency);
|
|
|
|
//
|
|
// If we are in DevModeNotify mode then send them the DEVMODE info
|
|
// and return
|
|
//
|
|
ASSERT(pcdev != NULL);
|
|
|
|
if (hwndDevModeNotify) {
|
|
COPYDATASTRUCT cds;
|
|
|
|
cds.dwData = CPL_INIT_DEVMODE_TAG;
|
|
cds.cbData = sizeof(DEVMODE);
|
|
cds.lpData = pcdev->GetData();
|
|
SendMessage(hwndDevModeNotify, WM_COPYDATA, CPL_INIT_DEVMODE_TAG, (LPARAM)&cds);
|
|
return TRUE;
|
|
}
|
|
|
|
if (ChangeDisplaySettingsEx(this->pszDisplay,
|
|
pcdev->GetData(),
|
|
NULL,
|
|
CDS_UPDATEREGISTRY | CDS_NORESET,
|
|
NULL) == DISP_CHANGE_NOTUPDATED)
|
|
{
|
|
FmtMessageBox(this->hwnd,
|
|
MB_ICONEXCLAMATION,
|
|
FALSE,
|
|
ID_DSP_TXT_CHANGE_SETTINGS,
|
|
ID_DSP_TXT_ADMIN_CHANGE);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Change font size if necessary
|
|
//
|
|
|
|
i = this->SendCtlMsg(ID_DSP_FONTSIZE, CB_GETCURSEL, 0, 0);
|
|
|
|
if (i != CB_ERR ) {
|
|
|
|
WCHAR awcDesc[10];
|
|
|
|
cFontSize = this->SendCtlMsg(ID_DSP_FONTSIZE, CB_GETITEMDATA, i, 0);
|
|
|
|
if ( (cFontSize != CB_ERR) &&
|
|
(cFontSize != 0) &&
|
|
(cFontSize != cLogPix)) {
|
|
|
|
//
|
|
// The user has changed the fonts.
|
|
// Lets make sure they want this.
|
|
//
|
|
|
|
if (FmtMessageBox(this->hwnd,
|
|
MB_YESNO | MB_DEFBUTTON2 | MB_ICONQUESTION,
|
|
FALSE,
|
|
ID_DSP_TXT_CHANGE_FONT,
|
|
ID_DSP_TXT_NEW_FONT)
|
|
== IDNO) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
//
|
|
// Call setup to change the font size.
|
|
//
|
|
|
|
wsprintf(awcDesc, TEXT("%d"), cFontSize);
|
|
|
|
if (SetupChangeFontSize(this->hwnd, awcDesc) == NO_ERROR)
|
|
{
|
|
//
|
|
// A font size change will require a system reboot.
|
|
//
|
|
|
|
PropSheet_RestartWindows(ghwndPropSheet);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Setup failed.
|
|
//
|
|
|
|
FmtMessageBox(this->hwnd,
|
|
MB_ICONSTOP | MB_OK,
|
|
FALSE,
|
|
ID_DSP_TXT_CHANGE_FONT,
|
|
ID_DSP_TXT_ADMIN_INSTALL);
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cFontSize == 0)
|
|
{
|
|
//
|
|
// If we could not read the inf, then ignore the font selection
|
|
// and don't force the reboot on account of that.
|
|
//
|
|
|
|
cFontSize = cLogPix;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// SetCurResolution method
|
|
//
|
|
// Sets the string in under the resolution slider, sets the thumb to the
|
|
// correct pos. and remembers the new resolution index.
|
|
//
|
|
//
|
|
void CDISPLAYDLG::SetCurResolution(int iRes ) {
|
|
int cx, cy;
|
|
LPTSTR lpszXbyY;
|
|
|
|
pcdmlModes->ResXYFromIndex(iRes, &cx, &cy);
|
|
|
|
monitor.SetScreenSize(cx, cy);
|
|
|
|
lpszXbyY = FmtSprint(ID_DSP_TXT_XBYY, cx, cy);
|
|
this->SendCtlMsg(ID_DSP_X_BY_Y, WM_SETTEXT, 0, (LPARAM)lpszXbyY);
|
|
LocalFree(lpszXbyY);
|
|
|
|
this->SendCtlMsg(ID_DSP_AREA_SB, TBM_SETPOS, TRUE, iRes);
|
|
|
|
this->iResolution = iRes;
|
|
|
|
//
|
|
// Force Small fonts at 640x480
|
|
//
|
|
if (cx < 800 || cy < 600) {
|
|
this->ForceSmallFont(TRUE);
|
|
} else {
|
|
this->ForceSmallFont(FALSE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// ForceSmallFont method
|
|
//
|
|
//
|
|
void CDISPLAYDLG::ForceSmallFont( BOOL fDoit ) {
|
|
int i, iSmall, dpiSmall, dpi;
|
|
static int iOld = CB_ERR;
|
|
|
|
if ( fDoit) {
|
|
//
|
|
// Force only small fonts
|
|
//
|
|
|
|
// Save the current setting so we can restore it later
|
|
if (iOld == CB_ERR)
|
|
iOld = this->SendCtlMsg(ID_DSP_FONTSIZE, CB_GETCURSEL, 0, 0);
|
|
|
|
//
|
|
// Set small font size in the listbox.
|
|
//
|
|
iSmall = CB_ERR;
|
|
dpiSmall = 9999;
|
|
for (i=0; i <=1; i++)
|
|
{
|
|
dpi = this->SendCtlMsg(ID_DSP_FONTSIZE, CB_GETITEMDATA, i, 0);
|
|
if (dpi == CB_ERR)
|
|
continue;
|
|
|
|
if (dpi < dpiSmall || iSmall < CB_ERR)
|
|
{
|
|
iSmall = i;
|
|
dpiSmall = dpi;
|
|
}
|
|
}
|
|
|
|
if (iSmall != -1)
|
|
this->SendCtlMsg(ID_DSP_FONTSIZE, CB_SETCURSEL, iSmall, 0);
|
|
|
|
EnableWindow(GetDlgItem(this->hwnd, ID_DSP_FONTSIZE), FALSE);
|
|
|
|
} else {
|
|
//
|
|
// Allow any font
|
|
//
|
|
|
|
EnableWindow(GetDlgItem(this->hwnd, ID_DSP_FONTSIZE), TRUE);
|
|
|
|
//
|
|
// Restore the old setting we remembered before (only restore
|
|
// if we are coming out of a Disabled case)
|
|
//
|
|
if (iOld != CB_ERR) {
|
|
this->SendCtlMsg(ID_DSP_FONTSIZE, CB_SETCURSEL, iOld, 0);
|
|
}
|
|
|
|
iOld = CB_ERR;
|
|
}
|
|
}
|
|
|
|
//
|
|
// SetCurFrequency method
|
|
//
|
|
// Updates the combo list, and remembers the new frequency index
|
|
//
|
|
void CDISPLAYDLG::SetCurFrequency(int iFreq ) {
|
|
|
|
this->SendCtlMsg(ID_DSP_FREQ, CB_SETCURSEL, iFreq, 0);
|
|
|
|
this->iFrequency = iFreq;
|
|
}
|
|
|
|
//
|
|
// SetCurColor method
|
|
//
|
|
// Updates the combo list, repaints the correct color bar, and
|
|
// remembers the new color index
|
|
//
|
|
void CDISPLAYDLG::SetCurColor(int iClr) {
|
|
int cBits;
|
|
|
|
this->SendCtlMsg(ID_DSP_COLORBOX, CB_SETCURSEL, iClr, 0);
|
|
|
|
cBits = pcdmlModes->ColorFromIndex(iClr);
|
|
if (cBits < C_CLR_BITS_VGA )
|
|
clrbar.SetColorIndex(ICLR_MONO);
|
|
else if (cBits < C_CLR_BITS_PALLET)
|
|
clrbar.SetColorIndex(ICLR_STANDARD);
|
|
else {
|
|
clrbar.SetColorIndex(ICLR_PALLET);
|
|
}
|
|
|
|
this->iColor = iClr;
|
|
}
|
|
|
|
|
|
//
|
|
// DoNotify method
|
|
//
|
|
BOOL CDISPLAYDLG::DoNotify(int idControl, NMHDR *lpnmh, UINT iNoteCode ) {
|
|
PCDEVMODE pcdev;
|
|
|
|
switch (iNoteCode) {
|
|
|
|
|
|
case PSN_APPLY:
|
|
|
|
if (bNewDriver)
|
|
{
|
|
//
|
|
// If a new driver is installed, we just want to tell the
|
|
// system to reboot.
|
|
//
|
|
// NOTE - this is only until we can get drivers to load on the fly.
|
|
//
|
|
|
|
PropSheet_RestartWindows(ghwndPropSheet);
|
|
SetWindowLong(this->hwnd, DWL_MSGRESULT, PSNRET_NOERROR);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Check to see if the user has tried the resolution before they
|
|
// leave.
|
|
//
|
|
|
|
pcdev = pcdmlModes->LookUp(this->iResolution,
|
|
this->iColor,
|
|
this->iFrequency);
|
|
|
|
if (!gUnattenedAutoConfirm) {
|
|
|
|
if (!(pcdev->bModeTested())) {
|
|
|
|
//
|
|
// Put up a pop asking the user if they really want to save
|
|
// this selection.
|
|
//
|
|
// Only support this feature in normal operation
|
|
//
|
|
|
|
if ( (gbExecMode == EXEC_SETUP) ||
|
|
(gbExecMode == EXEC_DETECT) ) {
|
|
|
|
FmtMessageBox(this->hwnd,
|
|
MB_ICONSTOP,
|
|
FALSE,
|
|
ID_DSP_TXT_SETTINGS,
|
|
ID_DSP_TXT_MODE_UNTESTED);
|
|
|
|
SetWindowLong(this->hwnd,
|
|
DWL_MSGRESULT,
|
|
PSNRET_INVALID_NOCHANGEPAGE);
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
if (FmtMessageBox(this->hwnd,
|
|
MB_OKCANCEL | MB_DEFBUTTON2 | MB_ICONSTOP,
|
|
FALSE,
|
|
ID_DSP_TXT_SETTINGS,
|
|
ID_DSP_TXT_MODE_UNTESTED_RESTART) == IDOK)
|
|
{
|
|
//
|
|
// The user pressed OK.
|
|
// Let's assume the mode works
|
|
//
|
|
|
|
pcdev->vTestMode(TRUE);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The user cancelled, so go back to the app.
|
|
//
|
|
|
|
SetWindowLong(this->hwnd,
|
|
DWL_MSGRESULT,
|
|
PSNRET_INVALID_NOCHANGEPAGE);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
//
|
|
// Clean up (will only happen in setup\detect modes)
|
|
// The user succesfully tested, so we want to keep the drivers.
|
|
//
|
|
|
|
CREGCLEANUP cregClean;
|
|
cregClean.vClean(FALSE);
|
|
|
|
}
|
|
|
|
//
|
|
// Save all values out to the registry.
|
|
//
|
|
|
|
if (!SaveParamsToReg()) {
|
|
SetWindowLong(this->hwnd, DWL_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Change the resolution on the fly, if we are not in setup.
|
|
//
|
|
|
|
if ( (gbExecMode == EXEC_NORMAL) ||
|
|
(gbExecMode == EXEC_INVALID_MODE) ||
|
|
(gbExecMode == EXEC_DETECT) ) {
|
|
|
|
//
|
|
// Try to change the resolution on the fly to the new settings
|
|
// we saved in the registry.
|
|
//
|
|
// If it fails, request a reboot.
|
|
//
|
|
|
|
if ((fActiveDsp == FALSE) ||
|
|
(ChangeDisplaySettings(NULL, NULL) != DISP_CHANGE_SUCCESSFUL))
|
|
{
|
|
PropSheet_RestartWindows(ghwndPropSheet);
|
|
}
|
|
}
|
|
|
|
SetWindowLong(this->hwnd, DWL_MSGRESULT, PSNRET_NOERROR);
|
|
|
|
break;
|
|
|
|
|
|
case PSN_QUERYCANCEL:
|
|
|
|
//
|
|
// Clean up *everything* (will only happen in setup\detect modes)
|
|
// We will boot in vga mode next time !
|
|
//
|
|
// HOWEVER, nothing will happen if the configure at logon value is set,
|
|
// which means we will do everything on the next boot.
|
|
//
|
|
// If we did run with the active display, we can not clean everything
|
|
// though (this must be a system with no VgaStart).
|
|
//
|
|
|
|
if (gUnattenedConfigureAtLogon == 0)
|
|
{
|
|
CREGCLEANUP cregClean;
|
|
cregClean.vClean(TRUE && (!fActiveDsp));
|
|
}
|
|
|
|
//
|
|
// If we break and return TRUE, that means we want to prevent CANCEL.
|
|
// What actually happens in the property sheet stuff is that we get
|
|
// called back with a PSN_RESET call which causes the property sheet
|
|
// to go away anyways.
|
|
//
|
|
// So let just return FALSE here for now.
|
|
// Later, when we have an APPLY call, then we may want to deal with
|
|
// this message differently.
|
|
//
|
|
|
|
return FALSE;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// DoCommand method
|
|
//
|
|
BOOL CDISPLAYDLG::DoCommand(int idControl, HWND hwndControl, int iNoteCode ) {
|
|
|
|
int iFreq, iRes, iClr;
|
|
PCDEVMODE pcdev;
|
|
|
|
switch (idControl) {
|
|
|
|
case ID_DSP_TEST: {
|
|
|
|
HANDLE hThread;
|
|
DWORD idThread;
|
|
DWORD bTest;
|
|
NEW_DESKTOP_PARAM desktopParam;
|
|
|
|
//
|
|
// Warn the user
|
|
//
|
|
|
|
if (FmtMessageBox(this->hwnd,
|
|
MB_OKCANCEL | MB_ICONINFORMATION,
|
|
FALSE,
|
|
ID_DSP_TXT_TEST_MODE,
|
|
ID_DSP_TXT_DID_TEST_WARNING)
|
|
== IDCANCEL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
|
|
//
|
|
// Disable this window so we can simulate a modal dialog in a different
|
|
// desktop.
|
|
//
|
|
|
|
this->Disable();
|
|
|
|
//
|
|
// Create the test thread. It will do the work of creating the desktop
|
|
//
|
|
|
|
pcdev = pcdmlModes->LookUp(this->iResolution,
|
|
this->iColor,
|
|
this->iFrequency);
|
|
|
|
ASSERT(pcdev != NULL);
|
|
|
|
desktopParam.lpdevmode = pcdev->GetData();
|
|
desktopParam.pwszDevice = this->pszDisplay;
|
|
|
|
hThread = CreateThread(NULL,
|
|
CB_THREAD_STACK,
|
|
ApplyNowThd,
|
|
(LPVOID) (&desktopParam),
|
|
SYNCHRONIZE | THREAD_QUERY_INFORMATION,
|
|
&idThread);
|
|
|
|
WaitForSingleObject(hThread, INFINITE);
|
|
|
|
GetExitCodeThread(hThread, &bTest);
|
|
|
|
//
|
|
// clean up un-needed non-paged pool space
|
|
//
|
|
|
|
CloseHandle(hThread);
|
|
|
|
//
|
|
// If the user saw what they expected, then we want to save the results
|
|
//
|
|
|
|
if ((bTest) &&
|
|
(FmtMessageBox(this->hwnd,
|
|
MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2,
|
|
FALSE,
|
|
ID_DSP_TXT_TEST_MODE,
|
|
ID_DSP_TXT_DID_TEST_RESULT)
|
|
== IDYES) ) {
|
|
|
|
//
|
|
// Mark this mode as tested.
|
|
//
|
|
|
|
pcdev->vTestMode(TRUE);
|
|
|
|
//
|
|
// In setup mode, don't save the results.
|
|
// They will be saved when the user exits the applet.
|
|
//
|
|
|
|
if (gbExecMode == EXEC_SETUP) {
|
|
|
|
FmtMessageBox(this->hwnd,
|
|
0,
|
|
FALSE,
|
|
ID_DSP_TXT_SETTINGS,
|
|
ID_DSP_TXT_SETUP_SAVE);
|
|
}
|
|
|
|
} else {
|
|
|
|
FmtMessageBox(this->hwnd,
|
|
MB_ICONEXCLAMATION | MB_OK,
|
|
FALSE,
|
|
ID_DSP_TXT_TEST_MODE,
|
|
ID_DSP_TXT_TEST_FAILED);
|
|
|
|
}
|
|
|
|
this->Enable();
|
|
SetForegroundWindow(this->hwnd);
|
|
|
|
break;
|
|
}
|
|
|
|
case ID_DSP_FONTSIZE:
|
|
|
|
switch(iNoteCode) {
|
|
|
|
case CBN_SELCHANGE:
|
|
|
|
//
|
|
// Can not change a font during setup.
|
|
// run the control panel later on.
|
|
//
|
|
|
|
if (gbExecMode == EXEC_SETUP) {
|
|
|
|
ULONG i;
|
|
|
|
FmtMessageBox(this->hwnd,
|
|
MB_ICONINFORMATION,
|
|
FALSE,
|
|
ID_DSP_TXT_CHANGE_FONT,
|
|
ID_DSP_TXT_FONT_IN_SETUP_MODE);
|
|
|
|
//
|
|
// Reset the value in the listbox.
|
|
// We only have two entries for now !
|
|
//
|
|
|
|
for (i=0; i <=1; i++)
|
|
{
|
|
if (this->SendCtlMsg(ID_DSP_FONTSIZE,
|
|
CB_GETITEMDATA, i, 0) == cLogPix)
|
|
{
|
|
this->SendCtlMsg(ID_DSP_FONTSIZE,
|
|
CB_SETCURSEL, i, 0);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Warn the USER font changes will not be seen until after
|
|
// reboot
|
|
//
|
|
|
|
FmtMessageBox(this->hwnd,
|
|
MB_ICONINFORMATION,
|
|
FALSE,
|
|
ID_DSP_TXT_CHANGE_FONT,
|
|
ID_DSP_TXT_FONT_LATER);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case ID_DSP_COLORBOX:
|
|
|
|
switch(iNoteCode ) {
|
|
|
|
case CBN_SELCHANGE:
|
|
|
|
iClr = this->SendCtlMsg(ID_DSP_COLORBOX, CB_GETCURSEL, 0, 0);
|
|
|
|
if (iClr != CB_ERR ) {
|
|
|
|
//
|
|
// Realize the new monitor mode
|
|
//
|
|
|
|
iFreq = this->iFrequency;
|
|
iRes = this->iResolution;
|
|
|
|
pcdmlModes->FindClosestMode(&iRes, iClr, &iFreq);
|
|
|
|
this->SetCurResolution(iRes);
|
|
this->SetCurFrequency(iFreq);
|
|
this->SetCurColor(iClr);
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case ID_DSP_FREQ:
|
|
|
|
switch(iNoteCode ) {
|
|
|
|
case CBN_SELCHANGE:
|
|
|
|
iFreq = this->SendCtlMsg(ID_DSP_FREQ, CB_GETCURSEL, 0, 0);
|
|
if (iFreq != CB_ERR ) {
|
|
int iClr, iRes;
|
|
|
|
//
|
|
// Realize the new monitor mode
|
|
//
|
|
|
|
iClr = this->iColor;
|
|
iRes = this->iResolution;
|
|
|
|
pcdmlModes->FindClosestMode(&iRes, &iClr, iFreq);
|
|
|
|
this->SetCurResolution(iRes);
|
|
this->SetCurFrequency(iFreq);
|
|
this->SetCurColor(iClr);
|
|
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case ID_DSP_CHANGE: {
|
|
|
|
CDLGCHGADAPTOR cdcaNewCard;
|
|
|
|
LPTSTR lpszNewDevice = this->pszDisplay;
|
|
int i;
|
|
|
|
i = cdcaNewCard.Dialog(this->hmodModule, this->hwnd,
|
|
(LPARAM)&lpszNewDevice);
|
|
|
|
if (i != RET_NO_CHANGE && lpszNewDevice != NULL) {
|
|
|
|
//
|
|
// A new device has been installed.
|
|
//
|
|
// NOTE Disable saving the information to the registry until we
|
|
// can actually load drivers on the fly.
|
|
//
|
|
|
|
bNewDriver = TRUE;
|
|
#if 0
|
|
//
|
|
// Re-enable this when we support mutiple devices again.
|
|
//
|
|
|
|
LPTSTR pszOldString;
|
|
|
|
//
|
|
// One should not be able to change the driver in one of these
|
|
// modes. This would cause our cleanup code to screw up since
|
|
// it would go and delete any new driver the user tried to
|
|
// install.
|
|
//
|
|
|
|
if ( (gbExecMode == EXEC_SETUP) ||
|
|
(gbExecMode == EXEC_DETECT) ) {
|
|
|
|
ASSERT(FALSE);
|
|
|
|
}
|
|
|
|
//
|
|
// Delete the old string
|
|
//
|
|
|
|
pszOldString = this->pszDisplay;
|
|
|
|
//
|
|
// now try to see if we can setup the modes for the new device.
|
|
//
|
|
|
|
//
|
|
// Build new lists
|
|
//
|
|
|
|
this->pszDisplay = CloneString(lpszNewDevice);
|
|
|
|
if (this->InitEverything()) {
|
|
|
|
//
|
|
// We have modes on the new device.
|
|
// Delete the old name
|
|
//
|
|
|
|
LocalFree(pszOldString);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Put a pop-up because we could not build a list for the
|
|
// applet.
|
|
//
|
|
|
|
|
|
//
|
|
// Could not get the modes.
|
|
// Restore to old device.
|
|
//
|
|
|
|
LocalFree(this->pszDisplay);
|
|
this->pszDisplay = pszOldString;
|
|
|
|
//
|
|
// Reset the table. This time is must work since it did last
|
|
// time.
|
|
//
|
|
|
|
InitEverything();
|
|
|
|
}
|
|
#endif
|
|
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
case ID_DSP_LIST_ALL:
|
|
{
|
|
|
|
CDLGMODELIST cmodelist;
|
|
LPDEVMODE lpdevmode;
|
|
|
|
lpdevmode = (LPDEVMODE) cmodelist.Dialog(this->hmodModule,
|
|
this->hwnd,
|
|
(LPARAM)&(pcdmlModes));
|
|
|
|
if (lpdevmode) {
|
|
|
|
//
|
|
// Realize the new monitor mode
|
|
//
|
|
|
|
iRes = pcdmlModes->IndexFromResXY(lpdevmode->dmPelsWidth,
|
|
lpdevmode->dmPelsHeight);
|
|
iFreq = pcdmlModes->IndexFromFreq(lpdevmode->dmDisplayFrequency);
|
|
iClr = pcdmlModes->IndexFromColor(lpdevmode->dmBitsPerPel);
|
|
|
|
this->SetCurResolution(iRes);
|
|
this->SetCurFrequency(iFreq);
|
|
this->SetCurColor(iClr);
|
|
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
//
|
|
// Enable the apply button only if we are not in setup.
|
|
//
|
|
|
|
if ( (gbExecMode == EXEC_NORMAL) ||
|
|
(gbExecMode == EXEC_INVALID_MODE) ||
|
|
(gbExecMode == EXEC_DETECT) ) {
|
|
|
|
//
|
|
// Set the apply button if something changed
|
|
//
|
|
|
|
if ((iOrgResolution != iResolution) ||
|
|
(iOrgColor != iColor) ||
|
|
(iOrgFrequency != iFrequency))
|
|
{
|
|
SendMessage(this->hwndParent, PSM_CHANGED, (WPARAM) this->hwnd, 0L);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// HScroll method
|
|
// In this dialog, the HScroll method is used to work the resolution slider.
|
|
//
|
|
BOOL CDISPLAYDLG::HScroll(int idCtrl, int iCode, int iPos) {
|
|
BOOL fRealize = TRUE;
|
|
int iRes;
|
|
|
|
iRes = this->iResolution;
|
|
|
|
switch(iCode ) {
|
|
case TB_LINEUP:
|
|
case TB_PAGEUP:
|
|
if (iRes != 0)
|
|
iRes--;
|
|
break;
|
|
|
|
case TB_LINEDOWN:
|
|
case TB_PAGEDOWN:
|
|
if (++(iRes) >= this->cResolutions)
|
|
iRes = this->cResolutions - 1;
|
|
break;
|
|
|
|
case TB_BOTTOM:
|
|
iRes = this->cResolutions - 1;
|
|
break;
|
|
|
|
case TB_TOP:
|
|
iRes = 0;
|
|
break;
|
|
|
|
case TB_THUMBTRACK:
|
|
fRealize = FALSE;
|
|
|
|
case TB_THUMBPOSITION:
|
|
iRes = iPos;
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
if (fRealize) {
|
|
|
|
int iFreq, iClr;
|
|
iFreq = this->iFrequency;
|
|
iClr = this->iColor;
|
|
|
|
pcdmlModes->FindClosestMode(iRes, &iClr, &iFreq);
|
|
|
|
this->SetCurFrequency(iFreq);
|
|
this->SetCurColor(iClr);
|
|
|
|
}
|
|
|
|
this->SetCurResolution(iRes);
|
|
|
|
//
|
|
// Enable the apply button only if we are not in setup.
|
|
//
|
|
|
|
if ( (gbExecMode == EXEC_NORMAL) ||
|
|
(gbExecMode == EXEC_INVALID_MODE) ||
|
|
(gbExecMode == EXEC_DETECT) ) {
|
|
|
|
//
|
|
// Set the apply button if something changed
|
|
//
|
|
|
|
if ((iOrgResolution != iResolution) ||
|
|
(iOrgColor != iColor) ||
|
|
(iOrgFrequency != iFrequency))
|
|
{
|
|
SendMessage(this->hwndParent, PSM_CHANGED, (WPARAM) this->hwnd, 0L);
|
|
}
|
|
}
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
idCtrl; //there is only one hscroll in this dlg box
|
|
}
|
|
|
|
BOOL CDISPLAYDLG::SysColorChange( void ) {
|
|
this->monitor.SysColorChange();
|
|
this->SendCtlMsg(ID_DSP_AREA_SB, WM_SYSCOLORCHANGE, 0, 0);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Called to put up initial messages that need to appear above the dialog
|
|
// box
|
|
//
|
|
|
|
BOOL CDISPLAYDLG::InitMessage(void) {
|
|
|
|
|
|
//
|
|
// If configure at logon is set, then we don't want to do anything
|
|
//
|
|
|
|
if (gUnattenedConfigureAtLogon)
|
|
{
|
|
PropSheet_PressButton(ghwndPropSheet, PSBTN_CANCEL);
|
|
}
|
|
else if (gUnattenedAutoConfirm)
|
|
{
|
|
PropSheet_PressButton(ghwndPropSheet, PSBTN_OK);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Put up a pop saying what kind of video card we detected.
|
|
//
|
|
|
|
if ( (gbExecMode == EXEC_SETUP) ||
|
|
(gbExecMode == EXEC_DETECT) ) {
|
|
|
|
|
|
CDLGSTARTUP startup(this->pszDisplay);
|
|
|
|
startup.Dialog(this->hmodModule, this->hwnd);
|
|
|
|
}
|
|
|
|
//
|
|
// bBadDriver will be set when we fail to build the list of modes,
|
|
// or something else failed during initialization.
|
|
//
|
|
// In almost every case, we should already know about this situation
|
|
// based on our boot code.
|
|
// However, if this is a new situation, just report a "bad driver"
|
|
//
|
|
|
|
if (bBadDriver)
|
|
{
|
|
ASSERT(gbExecMode == EXEC_INVALID_MODE);
|
|
|
|
gbExecMode = EXEC_INVALID_MODE;
|
|
gbInvalidMode = EXEC_INVALID_DISPLAY_DRIVER;
|
|
|
|
}
|
|
|
|
|
|
if (gbExecMode == EXEC_INVALID_MODE)
|
|
{
|
|
DWORD Mesg;
|
|
|
|
switch(gbInvalidMode) {
|
|
|
|
case EXEC_INVALID_NEW_DRIVER:
|
|
Mesg = MSG_INVALID_NEW_DRIVER;
|
|
break;
|
|
case EXEC_INVALID_DEFAULT_DISPLAY_MODE:
|
|
Mesg = MSG_INVALID_DEFAULT_DISPLAY_MODE;
|
|
break;
|
|
case EXEC_INVALID_DISPLAY_DRIVER:
|
|
Mesg = MSG_INVALID_DISPLAY_DRIVER;
|
|
break;
|
|
case EXEC_INVALID_OLD_DISPLAY_DRIVER:
|
|
Mesg = MSG_INVALID_OLD_DISPLAY_DRIVER;
|
|
break;
|
|
case EXEC_INVALID_16COLOR_DISPLAY_MODE:
|
|
Mesg = MSG_INVALID_16COLOR_DISPLAY_MODE;
|
|
break;
|
|
case EXEC_INVALID_DISPLAY_MODE:
|
|
Mesg = MSG_INVALID_DISPLAY_MODE;
|
|
break;
|
|
case EXEC_INVALID_CONFIGURATION:
|
|
default:
|
|
Mesg = MSG_INVALID_CONFIGURATION;
|
|
break;
|
|
}
|
|
|
|
FmtMessageBox(this->hwnd,
|
|
MB_ICONEXCLAMATION,
|
|
FALSE,
|
|
MSG_CONFIGURATION_PROBLEM,
|
|
Mesg);
|
|
|
|
//
|
|
// For a bad display driver or old display driver, let's send the
|
|
// user straight to the installation dialog.
|
|
//
|
|
|
|
if ((gbInvalidMode == EXEC_INVALID_OLD_DISPLAY_DRIVER) ||
|
|
(gbInvalidMode == EXEC_INVALID_DISPLAY_DRIVER))
|
|
{
|
|
CREGVIDOBJ rvoVideo(pszDisplay);
|
|
BOOL unused;
|
|
|
|
if (InstallNewDriver(this->hwnd,
|
|
rvoVideo.CloneDescription(),
|
|
FALSE,
|
|
&unused) == NO_ERROR)
|
|
{
|
|
//
|
|
// Set this flag so that we don't get a message about
|
|
// having an untested mode.
|
|
//
|
|
|
|
bNewDriver = TRUE;
|
|
|
|
//
|
|
// Let's leave the applet so the user sees the reboot
|
|
// popup.
|
|
//
|
|
|
|
PropSheet_PressButton(ghwndPropSheet, PSBTN_OK);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// deterines if the applet is in detect mode.
|
|
//
|
|
|
|
VOID CDISPLAYDLG::vPreExecMode() {
|
|
|
|
HKEY hkey;
|
|
DWORD cb;
|
|
DWORD data;
|
|
|
|
//
|
|
// This function sets up the execution mode of the applet.
|
|
// There are four vlid modes.
|
|
//
|
|
// EXEC_NORMAL - When the apple is launched from the control panel
|
|
//
|
|
// EXEC_INVALID_MODE is exactly the same as for NORMAL except we will
|
|
// not mark the current mode as tested so the user has
|
|
// to at least test a mode
|
|
//
|
|
// EXEC_DETECT - When the applet is launched normally, but a detect was
|
|
// done on the previous boot (the key in the registry is
|
|
// set)
|
|
//
|
|
// EXEC_SETUP - When we launch the applet in setup mode from setup (Both
|
|
// the registry key is set and the setup flag is passed in).
|
|
//
|
|
|
|
//
|
|
// These two keys should only be checked \ deleted if the machine has been
|
|
// rebooted and the detect \ new display has actually happened.
|
|
// So we will look for the RebootNecessary key (a volatile key) and if
|
|
// it is not present, then we can delete the key. Otherwise, the reboot
|
|
// has not happened, and we keep the key
|
|
//
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
SZ_REBOOT_NECESSARY,
|
|
0,
|
|
KEY_READ | KEY_WRITE,
|
|
&hkey) != ERROR_SUCCESS) {
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
SZ_DETECT_DISPLAY,
|
|
0,
|
|
KEY_READ | KEY_WRITE,
|
|
&hkey) == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// NOTE: This key is also set when EXEC_SETUP is being run.
|
|
//
|
|
|
|
if (gbExecMode == EXEC_NORMAL) {
|
|
|
|
gbExecMode = EXEC_DETECT;
|
|
|
|
} else {
|
|
|
|
//
|
|
// If we are in setup mode, we also check the extra values
|
|
// under DetectDisplay that control the unattended installation.
|
|
//
|
|
|
|
ASSERT(gbExecMode == EXEC_SETUP);
|
|
|
|
cb = 4;
|
|
if (RegQueryValueEx(hkey,
|
|
SZ_CONFIGURE_AT_LOGON,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE) &gUnattenedConfigureAtLogon,
|
|
&cb) == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// We delete only this value since the other values must remain
|
|
// until the next boot
|
|
//
|
|
|
|
RegDeleteValue(hkey,
|
|
SZ_CONFIGURE_AT_LOGON);
|
|
}
|
|
|
|
if (gUnattenedConfigureAtLogon == 0)
|
|
{
|
|
|
|
cb = 4;
|
|
RegQueryValueEx(hkey,
|
|
SZ_UNATTEND_INSTALL,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE) &gUnattenedInstall,
|
|
&cb);
|
|
|
|
cb = sizeof(gUnattenedPszInf);
|
|
RegQueryValueEx(hkey,
|
|
SZ_UNATTEND_INF,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE) gUnattenedPszInf,
|
|
&cb);
|
|
|
|
cb = sizeof(gUnattenedPszOption);
|
|
RegQueryValueEx(hkey,
|
|
SZ_UNATTEND_OPTION,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE) gUnattenedPszOption,
|
|
&cb);
|
|
|
|
cb = 4;
|
|
RegQueryValueEx(hkey,
|
|
SZ_UNATTEND_BPP,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE) &gUnattenedBitsPerPel,
|
|
&cb);
|
|
|
|
cb = 4;
|
|
RegQueryValueEx(hkey,
|
|
SZ_UNATTEND_X,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE) &gUnattenedXResolution,
|
|
&cb);
|
|
|
|
cb = 4;
|
|
RegQueryValueEx(hkey,
|
|
SZ_UNATTEND_Y,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE) &gUnattenedYResolution,
|
|
&cb);
|
|
|
|
cb = 4;
|
|
RegQueryValueEx(hkey,
|
|
SZ_UNATTEND_REF,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE) &gUnattenedVRefresh,
|
|
&cb);
|
|
|
|
cb = 4;
|
|
RegQueryValueEx(hkey,
|
|
SZ_UNATTEND_FLAGS,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE) &gUnattenedFlags,
|
|
&cb);
|
|
|
|
cb = 4;
|
|
RegQueryValueEx(hkey,
|
|
SZ_UNATTEND_CONFIRM,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE) &gUnattenedAutoConfirm,
|
|
&cb);
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
//
|
|
// Check for a new driver being installed
|
|
//
|
|
|
|
if ( (gbExecMode == EXEC_NORMAL) &&
|
|
(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
SZ_NEW_DISPLAY,
|
|
0,
|
|
KEY_READ | KEY_WRITE,
|
|
&hkey) == ERROR_SUCCESS) ) {
|
|
|
|
gbExecMode = EXEC_INVALID_MODE;
|
|
gbInvalidMode = EXEC_INVALID_NEW_DRIVER;
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
RegDeleteKey(HKEY_LOCAL_MACHINE,
|
|
SZ_DETECT_DISPLAY);
|
|
|
|
RegDeleteKey(HKEY_LOCAL_MACHINE,
|
|
SZ_NEW_DISPLAY);
|
|
}
|
|
{
|
|
LPTSTR psz;
|
|
LPTSTR pszInv;
|
|
|
|
switch(gbExecMode) {
|
|
|
|
case EXEC_NORMAL:
|
|
psz = L"Normal Execution mode";
|
|
break;
|
|
case EXEC_DETECT:
|
|
psz = L"Detection Execution mode";
|
|
break;
|
|
case EXEC_SETUP:
|
|
psz = L"Setup Execution mode";
|
|
break;
|
|
case EXEC_INVALID_MODE:
|
|
psz = L"Invalid Mode Execution mode";
|
|
|
|
switch(gbInvalidMode) {
|
|
|
|
case EXEC_INVALID_NEW_DRIVER:
|
|
pszInv = L"Invalid new driver";
|
|
break;
|
|
default:
|
|
psz = L"*** Invalid *** Invalid mode";
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
psz = L"*** Invalid *** Execution mode";
|
|
break;
|
|
}
|
|
|
|
KdPrint(("\n \nDisplay.cpl: The display applet is in : %ws\n", psz));
|
|
|
|
if (gbExecMode == EXEC_INVALID_MODE)
|
|
{
|
|
KdPrint(("\t\t sub invalid mode : %ws", pszInv));
|
|
}
|
|
KdPrint(("\n\n", psz));
|
|
}
|
|
}
|
|
|
|
|
|
VOID CDISPLAYDLG::vPostExecMode() {
|
|
|
|
HKEY hkey;
|
|
DWORD cb;
|
|
DWORD data;
|
|
|
|
//
|
|
// Check for various invalid configurations
|
|
//
|
|
|
|
if ( (gbExecMode == EXEC_NORMAL) &&
|
|
(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
SZ_INVALID_DISPLAY,
|
|
0,
|
|
KEY_READ | KEY_WRITE,
|
|
&hkey) == ERROR_SUCCESS) ) {
|
|
|
|
gbExecMode = EXEC_INVALID_MODE;
|
|
|
|
//
|
|
// Check for these fields in increasing order of "badness" or
|
|
// "detail" so that the *worst* error is the one remaining in the
|
|
// gbInvalidMode variable once all the checks are done.
|
|
//
|
|
|
|
cb = 4;
|
|
if (RegQueryValueEx(hkey,
|
|
TEXT("DefaultMode"),
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)(&data),
|
|
&cb) == ERROR_SUCCESS)
|
|
{
|
|
gbInvalidMode = EXEC_INVALID_DEFAULT_DISPLAY_MODE;
|
|
}
|
|
|
|
cb = 4;
|
|
if (RegQueryValueEx(hkey,
|
|
TEXT("BadMode"),
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)(&data),
|
|
&cb) == ERROR_SUCCESS)
|
|
{
|
|
gbInvalidMode = EXEC_INVALID_DISPLAY_MODE;
|
|
}
|
|
|
|
cb = 4;
|
|
if (RegQueryValueEx(hkey,
|
|
TEXT("16ColorMode"),
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)(&data),
|
|
&cb) == ERROR_SUCCESS)
|
|
{
|
|
gbInvalidMode = EXEC_INVALID_16COLOR_DISPLAY_MODE;
|
|
}
|
|
|
|
|
|
cb = 4;
|
|
if (RegQueryValueEx(hkey,
|
|
TEXT("InvalidConfiguration"),
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)(&data),
|
|
&cb) == ERROR_SUCCESS)
|
|
{
|
|
gbInvalidMode = EXEC_INVALID_CONFIGURATION;
|
|
}
|
|
|
|
cb = 4;
|
|
if (RegQueryValueEx(hkey,
|
|
TEXT("MissingDisplayDriver"),
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)(&data),
|
|
&cb) == ERROR_SUCCESS)
|
|
{
|
|
gbInvalidMode = EXEC_INVALID_DISPLAY_DRIVER;
|
|
}
|
|
|
|
//
|
|
// This last case will be set in addition to the previous one in the
|
|
// case where the driver was an old driver linking to winsvr.dll
|
|
// and we can not load it.
|
|
//
|
|
|
|
cb = 4;
|
|
if (RegQueryValueEx(hkey,
|
|
TEXT("OldDisplayDriver"),
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)(&data),
|
|
&cb) == ERROR_SUCCESS)
|
|
{
|
|
gbInvalidMode = EXEC_INVALID_OLD_DISPLAY_DRIVER;
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
|
|
}
|
|
|
|
//
|
|
// Delete all of these bad configuration keys since we only want the
|
|
// user to see the message once.
|
|
//
|
|
|
|
RegDeleteKey(HKEY_LOCAL_MACHINE,
|
|
SZ_INVALID_DISPLAY);
|
|
|
|
{
|
|
LPTSTR psz;
|
|
LPTSTR pszInv;
|
|
|
|
if (gbExecMode == EXEC_INVALID_MODE)
|
|
{
|
|
switch (gbInvalidMode)
|
|
{
|
|
case EXEC_INVALID_DEFAULT_DISPLAY_MODE:
|
|
pszInv = L"Default mode being used";
|
|
break;
|
|
case EXEC_INVALID_DISPLAY_DRIVER:
|
|
pszInv = L"Invalid Display Driver";
|
|
break;
|
|
case EXEC_INVALID_OLD_DISPLAY_DRIVER:
|
|
pszInv = L"Old Display Driver";
|
|
break;
|
|
case EXEC_INVALID_16COLOR_DISPLAY_MODE:
|
|
pszInv = L"16 color mode not supported";
|
|
break;
|
|
case EXEC_INVALID_DISPLAY_MODE:
|
|
pszInv = L"Invalid display mode";
|
|
break;
|
|
case EXEC_INVALID_CONFIGURATION:
|
|
pszInv = L"Invalid configuration";
|
|
break;
|
|
default:
|
|
psz = L"*** Invalid *** Invalid mode";
|
|
break;
|
|
}
|
|
|
|
KdPrint(("\t\t sub invlid mode : %ws", pszInv));
|
|
KdPrint(("\n\n", psz));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Paint method
|
|
// Paints the dialog box. In this case, it shows the Monitor picture
|
|
// and the color bar.
|
|
//
|
|
|
|
BOOL CDISPLAYDLG::Paint(void) {
|
|
PAINTSTRUCT ps;
|
|
HDC hdc;
|
|
|
|
hdc = BeginPaint(this->hwnd, &ps);
|
|
|
|
this->monitor.Paint(hdc, &(ps.rcPaint));
|
|
this->clrbar.Paint(hdc, &(ps.rcPaint));
|
|
|
|
EndPaint(this->hwnd, &ps);
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* NewDisplayDialogBox
|
|
*
|
|
* Returns a DlgProc for our C++ display dialog
|
|
*
|
|
* History:
|
|
* 10-May-1995 JonPa Created it
|
|
\***************************************************************************/
|
|
DLGPROC NewDisplayDialogBox(HINSTANCE hmod, LPARAM *lplParam) {
|
|
CDISPLAYDLG *pddDialog;
|
|
|
|
pddDialog = new CDISPLAYDLG;
|
|
|
|
pddDialog->hwndParent = NULL;
|
|
pddDialog->hmodModule = hmod;
|
|
pddDialog->lParam = 0;
|
|
|
|
*lplParam = (LPARAM)pddDialog;
|
|
|
|
return DisplayPageProc;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* DeleteDisplayDialogBox
|
|
*
|
|
* Deletes the C++ objects associated with a display dialog box
|
|
*
|
|
* History:
|
|
* 10-May-1995 JonPa Created it
|
|
\***************************************************************************/
|
|
void DeleteDisplayDialogBox( LPARAM lParam ) {
|
|
CDISPLAYDLG *pddDialog;
|
|
|
|
pddDialog = (CDISPLAYDLG *)lParam;
|
|
|
|
delete pddDialog;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* DisplayPageProc
|
|
*
|
|
* Dialog Proc callable from PropertyPage code.
|
|
*
|
|
* History:
|
|
* 10-May-1995 JonPa Created it
|
|
\***************************************************************************/
|
|
BOOL CALLBACK DisplayPageProc(
|
|
HWND hwnd,
|
|
UINT msg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
if (msg == WM_INITDIALOG)
|
|
{
|
|
ghwndPropSheet = GetParent(hwnd);
|
|
|
|
return DisplayDlgProc(hwnd, msg, wParam, ((PROPSHEETPAGE *)lParam)->lParam );
|
|
}
|
|
else
|
|
return DisplayDlgProc(hwnd, msg, wParam, lParam );
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************\
|
|
* DisplayDlgProc
|
|
*
|
|
*
|
|
* History:
|
|
* 23-Sep-1993 JonPa Created it
|
|
\***************************************************************************/
|
|
|
|
BOOL CALLBACK DisplayDlgProc(
|
|
HWND hwnd,
|
|
UINT msg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
PCDIALOG pdlg;
|
|
|
|
if (msg == WM_INITDIALOG) {
|
|
/*
|
|
* Set up Object/Window relationship
|
|
*/
|
|
SetWindowLong(hwnd, DWL_USER, lParam);
|
|
pdlg = (PCDIALOG) lParam;
|
|
pdlg->SetHWnd(hwnd);
|
|
pdlg->SetHWndParent(GetParent(hwnd));
|
|
}
|
|
|
|
pdlg = (PCDIALOG)GetWindowLong(hwnd, DWL_USER);
|
|
|
|
|
|
|
|
if (pdlg != NULL) {
|
|
/*
|
|
* Dispatch to the Dialog Object's WndProc method
|
|
*/
|
|
return pdlg->WndProc(msg, wParam, lParam);
|
|
|
|
} else {
|
|
|
|
#if 0
|
|
/*
|
|
* We have not setup the Object/Dialog relationship yet,
|
|
* just let DefDlgProc handle this message, (unless it is
|
|
* a help request).
|
|
*/
|
|
if (msg == wHelpMessage) {
|
|
DspHelp(hwnd);
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* FUNCTION: FmtMessageBox(HWND hwnd, int dwTitleID, UINT fuStyle,
|
|
* BOOL fSound, DWORD dwTextID, ...);
|
|
*
|
|
* PURPOSE: Formats messages with FormatMessage and then displays them
|
|
* in a message box
|
|
*
|
|
* PARAMETERS:
|
|
* hwnd - parent window for message box
|
|
* fuStyle - MessageBox style
|
|
* fSound - if TRUE, MessageBeep will be called with fuStyle
|
|
* dwTitleID - Message ID for optional title, "Error" will
|
|
* be displayed if dwTitleID == -1
|
|
* dwTextID - Message ID for the message box text
|
|
* ... - optional args to be embedded in dwTextID
|
|
* see FormatMessage for more details
|
|
* History:
|
|
* 22-Apr-1993 JonPa Created it.
|
|
\***************************************************************************/
|
|
int
|
|
FmtMessageBox(
|
|
HWND hwnd,
|
|
UINT fuStyle,
|
|
BOOL fSound,
|
|
DWORD dwTitleID,
|
|
DWORD dwTextID, ... )
|
|
{
|
|
|
|
LPTSTR pszMsg;
|
|
LPTSTR pszTitle;
|
|
int idRet;
|
|
|
|
va_list marker;
|
|
|
|
va_start(marker, dwTextID);
|
|
|
|
if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_FROM_HMODULE |
|
|
FORMAT_MESSAGE_MAX_WIDTH_MASK,
|
|
ghmod,
|
|
dwTextID,
|
|
0,
|
|
(LPTSTR)&pszMsg,
|
|
1,
|
|
&marker)) {
|
|
|
|
pszMsg = gpszError;
|
|
|
|
}
|
|
|
|
va_end(marker);
|
|
|
|
GetLastError();
|
|
|
|
pszTitle = NULL;
|
|
|
|
if (dwTitleID != -1) {
|
|
|
|
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_FROM_HMODULE |
|
|
FORMAT_MESSAGE_MAX_WIDTH_MASK |
|
|
FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
|
ghmod,
|
|
dwTitleID,
|
|
0,
|
|
(LPTSTR)&pszTitle,
|
|
1,
|
|
NULL);
|
|
//(va_list *)&pszTitleStr);
|
|
|
|
}
|
|
|
|
//
|
|
// Turn on the beep if requested
|
|
//
|
|
|
|
if (fSound) {
|
|
MessageBeep(fuStyle & (MB_ICONASTERISK | MB_ICONEXCLAMATION |
|
|
MB_ICONHAND | MB_ICONQUESTION | MB_OK));
|
|
}
|
|
|
|
idRet = MessageBox(hwnd, pszMsg, pszTitle, fuStyle);
|
|
|
|
if (pszTitle != NULL)
|
|
LocalFree(pszTitle);
|
|
|
|
if (pszMsg != gpszError)
|
|
LocalFree(pszMsg);
|
|
|
|
return idRet;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* FUNCTION: FmtSprint(DWORD id, ...);
|
|
*
|
|
* PURPOSE: sprintf but it gets the pattern string from the message rc,
|
|
* and allocates the buffer for the end result.
|
|
*
|
|
* History:
|
|
* 03-May-1993 JonPa Created it.
|
|
\***************************************************************************/
|
|
LPTSTR FmtSprint(DWORD id, ... ) {
|
|
LPTSTR pszMsg;
|
|
va_list marker;
|
|
|
|
va_start(marker, id);
|
|
|
|
if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_FROM_HMODULE |
|
|
FORMAT_MESSAGE_MAX_WIDTH_MASK,
|
|
ghmod,
|
|
id,
|
|
0,
|
|
(LPTSTR)&pszMsg,
|
|
1,
|
|
&marker)) {
|
|
|
|
|
|
GetLastError();
|
|
pszMsg = TEXT("...");
|
|
}
|
|
va_end(marker);
|
|
|
|
return pszMsg;
|
|
}
|
|
|
|
/****************************************************************************\
|
|
*
|
|
* LPTSTR SubStrEnd(LPTSTR pszTarget, LPTSTR pszScan )
|
|
*
|
|
* If pszScan starts with pszTarget, then the function returns the first
|
|
* char of pszScan that follows the pszTarget; other wise it returns pszScan.
|
|
*
|
|
* eg: SubStrEnd("abc", "abcdefg" ) ==> "defg"
|
|
* SubStrEnd("abc", "abZQRT" ) ==> "abZQRT"
|
|
*
|
|
* History:
|
|
* 09-Dec-1993 JonPa Wrote it.
|
|
\****************************************************************************/
|
|
LPTSTR SubStrEnd(LPTSTR pszTarget, LPTSTR pszScan ) {
|
|
int i;
|
|
|
|
for (i = 0; pszScan[i] != TEXT('\0') && pszTarget[i] != TEXT('\0') &&
|
|
CharUpper(CHARTOPSZ(pszScan[i])) ==
|
|
CharUpper(CHARTOPSZ(pszTarget[i])); i++);
|
|
|
|
if (pszTarget[i] == TEXT('\0')) {
|
|
|
|
// we found the substring
|
|
return pszScan + i;
|
|
}
|
|
|
|
return pszScan;
|
|
}
|
|
|
|
/****************************************************************************\
|
|
*
|
|
* CloneString
|
|
*
|
|
* Makes a copy of a string. By copy, I mean it actually allocs memeory
|
|
* and copies the chars across.
|
|
*
|
|
* NOTE: the caller must LocalFree the string when they are done with it.
|
|
*
|
|
* Returns a pointer to a LocalAlloced buffer that has a copy of the
|
|
* string in it. If an error occurs, it retuns NULl.
|
|
*
|
|
* 16-Dec-1993 JonPa Wrote it.
|
|
\****************************************************************************/
|
|
LPTSTR CloneString(LPTSTR psz ) {
|
|
int cb;
|
|
LPTSTR psz2;
|
|
|
|
if (psz == NULL)
|
|
return NULL;
|
|
|
|
cb = (lstrlen(psz) + 1) * sizeof(TCHAR);
|
|
|
|
psz2 = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, cb);
|
|
if (psz2 != NULL)
|
|
CopyMemory(psz2, psz, cb);
|
|
|
|
return psz2;
|
|
}
|
|
|
|
|
|
/****************************************************************************\
|
|
*
|
|
* 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 WINAPI 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 = CreateDesktop(TEXT("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;
|
|
}
|