Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1643 lines
53 KiB

/******************************************************************************
Source File: Device Profile Management .CPP
Change History:
Implements the class which provides the various device profile management UI
Copyright (c) 1996 by Microsoft Corporation
A Pretty Penny Enterprises, Inc. Production
11-27-96 [email protected] coded it
******************************************************************************/
#include "ICMUI.H"
//
// This function is obtained from the April 1998 Knowledge Base
// Its purpose is to determine if the current user is an
// Administrator and therefore priveledged to change profile
// settings.
//
// BOOL IsAdmin(void)
//
// returns TRUE if user is an admin
// FALSE if user is not an admin
//
#if defined(_WIN95_)
//
// Always administrator on Windows 9x platform.
//
BOOL IsAdmin(void) {
return (TRUE);
}
#else
BOOL IsAdmin(void)
{
BOOL fReturn = FALSE;
PSID psidAdmin;
SID_IDENTIFIER_AUTHORITY SystemSidAuthority= SECURITY_NT_AUTHORITY;
if ( AllocateAndInitializeSid ( &SystemSidAuthority, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0, &psidAdmin) )
{
if(!CheckTokenMembership( NULL, psidAdmin, &fReturn )) {
//
// explicitly disallow Admin Access if CheckTokenMembership fails.
//
fReturn = FALSE;
}
FreeSid ( psidAdmin);
}
return ( fReturn );
}
#endif // _WIN95_
/******************************************************************************
List Managment functions
The method used here is simlar to that used in the profile Managment sheets
for managing device associations.
We (not royal, I mean the OS and I) manage two "to-do" lists and use these
to show the user the anticipated result of these lists being applied. The
first list is a list of existing associations that are to be broken. The
second is one of new associations to be made. This is coupled with a list
of the current associations.
The "Removals" list is the indices of existing associations which will be
borken. The "Adds" list is a list of new profiles to be associated. The
"Profiles" list is the list of existing associations.
Adding and removing profiles could mean removing an item from one of the work
lists (undoing a previous selection), or adding one. Each time such a change
is made, the profile list box is emptied and refilled. This lets us avoid
mapping removals and additions more directly.
When changes are commited, either with Apply or OK, we make or break
associations as specified, then empty all of the lists, and rebuild the list
of current associations.
We use the ITEMDATA of the UI list box to handle the associations. This lets
the list remain sorted.
All of the list management functions can be overriden, if needed.
******************************************************************************/
void CDeviceProfileManagement::InitList() {
// Make sure the lists are empty.
m_cuaRemovals.Empty();
m_cpaAdds.Empty();
// Determine the associations for the target device.
ENUMTYPE et = {sizeof et, ENUM_TYPE_VERSION, ET_DEVICENAME, m_csDevice};
CProfile::Enumerate(et, m_cpaProfile);
}
// Fill the UI list of profiles
void CDeviceProfileManagement::FillList(DWORD dwFlags) {
// Before reset list box, get current selection to restore later.
CString csSelect;
csSelect.Empty();
LRESULT idSelect = LB_ERR;
if ( !(dwFlags & DEVLIST_NOSELECT)) {
// Get current selected position.
idSelect = SendMessage(m_hwndList, LB_GETCURSEL, 0, 0);
// Get text length where currently selected, than allocate buffer for that.
DWORD dwLen = (DWORD) SendMessage(m_hwndList, LB_GETTEXTLEN, idSelect, 0);
TCHAR *pszSelect = new TCHAR[dwLen + 1];
// Get text itself.
if (pszSelect != NULL) {
if (SendMessage(m_hwndList, LB_GETTEXT, idSelect, (LPARAM) pszSelect) != LB_ERR) {
csSelect = pszSelect;
}
delete [] pszSelect;
}
}
// reset list box
SendMessage(m_hwndList, LB_RESETCONTENT, 0, 0);
// Fill the profile list box from the list of profiles
for (unsigned u = 0; u < m_cpaProfile.Count(); u++) {
// Don't list profiles tentatively disassociated...
for (unsigned uOut = 0; uOut < m_cuaRemovals.Count(); uOut++)
if (m_cuaRemovals[uOut] == u)
break;
if (uOut < m_cuaRemovals.Count())
continue; // Don't add this to list, it's been zapped!
LRESULT id = SendMessage(m_hwndList, LB_ADDSTRING, 0,
(LPARAM) (LPCTSTR) m_cpaProfile[u] -> GetName());
SendMessage(m_hwndList, LB_SETITEMDATA, id, u);
}
// Add the profiles that have been tentatively added...
for (u = 0; u < m_cpaAdds.Count(); u ++) {
LRESULT id = SendMessage(m_hwndList, LB_ADDSTRING, 0,
(LPARAM) (LPCTSTR) m_cpaAdds[u] -> GetName());
SendMessage(m_hwndList, LB_SETITEMDATA, id, u + m_cpaProfile.Count());
}
// If we have any profiles, select the first one
// Otherwise, disable the "Remove" button, as there's nothing to remove
unsigned itemCount = (m_cpaProfile.Count() + m_cpaAdds.Count() - m_cuaRemovals.Count());
if (itemCount) {
// The Remove button must remain disabled
// unless the user is Administrator.
// This code is specific to the Monitor Profile
// Property sheet.
if (!m_bReadOnly) {
EnableWindow(GetDlgItem(m_hwnd, RemoveButton), TRUE);
}
if ( !(dwFlags & DEVLIST_NOSELECT)) {
// Find out the string selected previously.
idSelect = LB_ERR;
if (!csSelect.IsEmpty()) {
idSelect = SendMessage(m_hwndList, LB_FINDSTRINGEXACT,
(WPARAM) -1, (LPARAM) (LPCTSTR) csSelect);
}
// if could not find, just select first item.
if (idSelect == LB_ERR) {
idSelect = 0;
}
// Select it.
SendMessage(m_hwndList, LB_SETCURSEL, idSelect, 0);
}
} else {
HWND hwndRemove = GetDlgItem(m_hwnd, RemoveButton);
// If focus is on Remove, move it to Add button.
if (GetFocus() == hwndRemove) {
HWND hwndAdd = GetDlgItem(m_hwnd, AddButton);
SetFocus(hwndAdd);
SendMessage(hwndRemove, BM_SETSTYLE, BS_PUSHBUTTON, MAKELPARAM(TRUE, 0));
SendMessage(hwndAdd, BM_SETSTYLE, BS_DEFPUSHBUTTON, MAKELPARAM(TRUE, 0));
}
EnableWindow(hwndRemove, FALSE);
}
// Apply button needs to remain disabled unless the
// user has permision to make changes - ie. user
// is Administrator.
if ((dwFlags & DEVLIST_CHANGED) && !(m_bReadOnly)) {
EnableApplyButton();
SettingChanged(TRUE);
}
}
void CDeviceProfileManagement::GetDeviceTypeString(DWORD dwType,CString& csDeviceName) {
DWORD id;
switch (dwType) {
case CLASS_MONITOR :
id = ClassMonitorString;
break;
case CLASS_PRINTER :
id = ClassPrinterString;
break;
case CLASS_SCANNER :
id = ClassScannerString;
break;
case CLASS_LINK :
id = ClassLinkString;
break;
case CLASS_ABSTRACT :
id = ClassAbstractString;
break;
case CLASS_NAMED :
id = ClassNamedString;
break;
case CLASS_COLORSPACE :
default :
id = ClassColorSpaceString;
break;
}
// Load string.
csDeviceName.Load(id);
}
// Constructor
CDeviceProfileManagement::CDeviceProfileManagement(LPCTSTR lpstrDevice,
HINSTANCE hiWhere,
int idPage, DWORD dwType) {
m_csDevice = lpstrDevice;
m_dwType = dwType;
m_psp.hInstance = hiWhere;
m_psp.pszTemplate = MAKEINTRESOURCE(idPage);
// Setting m_bReadOnly to false enables functionality
m_bReadOnly = FALSE; // default setting is false
#if defined(_WIN95_)
//
// There is no way to detect printer supports CMYK or not on Win 9x.
m_bCMYK = TRUE;
#else
// we need to check the device capabilities
// and determine if we're trying to associate
// a cmyk printer profile to a printer that
// doesn't support it.
m_bCMYK = FALSE; // default setting - don't support cmyk
// if the device is a printer
if (m_dwType == CLASS_PRINTER) {
HDC hdcThis = CGlobals::GetPrinterHDC(m_csDevice);
// if the printer supports CMYK
if (hdcThis) {
if (GetDeviceCaps(hdcThis, COLORMGMTCAPS) & CM_CMYK_COLOR) {
m_bCMYK = TRUE;
}
DeleteDC(hdcThis);
}
}
#endif // defined(_WIN95_)
}
// UI initialization
BOOL CDeviceProfileManagement::OnInit() {
InitList();
m_hwndList = GetDlgItem(m_hwnd, ProfileListControl);
// Fill the profile list box
FillList(DEVLIST_ONINIT);
// Disable apply button as default.
DisableApplyButton();
// Nothing changed, yet.
SettingChanged(FALSE);
return TRUE;
}
// Command processing
BOOL CDeviceProfileManagement::OnCommand(WORD wNotifyCode, WORD wid,
HWND hwndCtl) {
switch (wNotifyCode) {
case BN_CLICKED:
switch (wid) {
case AddButton: {
unsigned i = 0, u = 0;
// Time to do the old OpenFile dialog stuff...
CAddProfileDialog capd(m_hwnd, m_psp.hInstance);
// See if a profile was selected
while(i < capd.ProfileCount()) {
// Check profile validity and device type
CProfile cpTemp(capd.ProfileName(i));
// CLASS_COLORSPACE and CLASS_MONITOR can be associated to
// any device. Other (CLASS_SCANNER, CLASS_PRINTER) only
// can be associated to much device.
if ( !cpTemp.IsValid() // Wrong profile type or invalid?
|| ( cpTemp.GetType() != m_dwType
&& cpTemp.GetType() != CLASS_COLORSPACE
#if 1 // ALLOW_MONITOR_PROFILE_TO_ANY_DEVICE
&& cpTemp.GetType() != CLASS_MONITOR
#endif
)
) {
// Throw up a message box to inform the user of this
if (cpTemp.IsValid())
{
CString csDeviceType; GetDeviceTypeString(m_dwType,csDeviceType);
CString csProfileType; GetDeviceTypeString(cpTemp.GetType(),csProfileType);
CGlobals::ReportEx(MismatchDeviceType, m_hwnd, FALSE,
MB_OK|MB_ICONEXCLAMATION, 3,
(LPTSTR)capd.ProfileNameAndExtension(i),
(LPTSTR)csProfileType,
(LPTSTR)csDeviceType);
}
else
{
CGlobals::ReportEx(InstFailedWithName, m_hwnd, FALSE,
MB_OK|MB_ICONEXCLAMATION, 1,
(LPTSTR)capd.ProfileNameAndExtension(i));
}
goto SkipToNext;
}
// See if the profile has already been listed for addition
for (u = 0; u < m_cpaAdds.Count(); u++) {
if (!lstrcmpi(m_cpaAdds[u] -> GetName(), cpTemp.GetName())) {
goto SkipToNext; // This profile is already added
}
}
// If this profile is on the existing list, either ignore
// or zap it from the removal list, as the case may be
for (u = 0; u < m_cpaProfile.Count(); u++) {
if (!lstrcmpi(m_cpaProfile[u] -> GetName(),
cpTemp.GetName())) {
// Is this one on the removal list?
for (unsigned uOut = 0;
uOut < m_cuaRemovals.Count();
uOut++) {
if (m_cuaRemovals[uOut] == u) {
// Was to be removed- undo that...
m_cuaRemovals.Remove(uOut);
FillList(DEVLIST_CHANGED);
break;
}
}
goto SkipToNext;
} // End of name in existing list
}
// We need to check the device capabilities
// and determine if we're trying to associate
// a cmyk printer profile to a printer that
// doesn't support it.
if ((!m_bCMYK) && (cpTemp.GetColorSpace() == SPACE_CMYK)) {
CGlobals::ReportEx(UnsupportedProfile, m_hwnd, FALSE,
MB_OK|MB_ICONEXCLAMATION, 2,
(LPTSTR)m_csDevice,
(LPTSTR)capd.ProfileNameAndExtension(i));
goto SkipToNext;
}
// Add this profile to the list, item (max orig + index)
m_cpaAdds.Add(capd.ProfileName(i));
// Change has been made, update the list
FillList(DEVLIST_CHANGED);
SkipToNext:
i++;
}
return TRUE;
}
case RemoveButton: {
// Remove the selected profile
LRESULT id = SendMessage(m_hwndList, LB_GETCURSEL, 0, 0);
unsigned u = (unsigned) SendMessage(m_hwndList,
LB_GETITEMDATA, id, 0);
// If this is a tentative add, just drop it, otherwise
// note that it's been removed...
if (u >= m_cpaProfile.Count())
m_cpaAdds.Remove(u - m_cpaProfile.Count());
else
m_cuaRemovals.Add(u);
// That's it- just update the display, now...
FillList(DEVLIST_CHANGED);
// explicitly set the position of the current selection
// after the list has been recomputed.
int listsize = m_cpaProfile.Count()+m_cpaAdds.Count()-m_cuaRemovals.Count();
if (id >= listsize) id = listsize-1;
if (id < 0) id = 0;
SendMessage(m_hwndList, LB_SETCURSEL, id, 0);
return TRUE;
}
}
break;
case LBN_SELCHANGE: {
LRESULT id = SendMessage(m_hwndList, LB_GETCURSEL, 0, 0);
if (id == -1) {
EnableWindow(GetDlgItem(m_hwnd, RemoveButton), FALSE);
} else {
// The Remove button must remain disabled on a monitor
// profile property page if the user isn't the
// Administrator, otherwise enable remove button.
EnableWindow(GetDlgItem(m_hwnd, RemoveButton), !m_bReadOnly);
}
return TRUE;
}
}
return FALSE;
}
// Property Sheet notification processing
BOOL CDeviceProfileManagement::OnNotify(int idCtrl, LPNMHDR pnmh) {
switch (pnmh -> code) {
case PSN_APPLY:
DisableApplyButton();
if (SettingChanged()) {
// Apply the changes the user has made...
SettingChanged(FALSE);
while (m_cpaAdds.Count()) {
if (!m_cpaAdds[0] -> IsInstalled()) {
m_cpaAdds[0] -> Install();
}
m_cpaAdds[0] -> Associate(m_csDevice);
m_cpaAdds.Remove(0);
}
// Now do the removals (actually just dissociations)
while (m_cuaRemovals.Count()) {
m_cpaProfile[m_cuaRemovals[0]] -> Dissociate(m_csDevice);
m_cuaRemovals.Remove(0);
}
InitList();
FillList();
SetWindowLongPtr(m_hwnd, DWLP_MSGRESULT, PSNRET_NOERROR);
}
return TRUE;
}
return FALSE;
}
// This hook procedure both forces the use of the old-style common dialog
// and changes the OK button to an Add button. The actual button text is
// a string resource, and hence localizable.
UINT_PTR APIENTRY CAddProfileDialog::OpenFileHookProc(HWND hDlg, UINT uMessage,
WPARAM wp, LPARAM lp) {
switch (uMessage) {
case WM_INITDIALOG: {
CString csAddButton;
OPENFILENAME *pofn = (OPENFILENAME *) lp;
csAddButton.Load(AddButtonText);
SetDlgItemText(GetParent(hDlg), IDOK, csAddButton);
return TRUE;
}
}
return FALSE;
}
// Once again, a constructor that actually does most of the work!
TCHAR gacColorDir[MAX_PATH] = _TEXT("\0");
TCHAR gacFilter[MAX_PATH] = _TEXT("\0");
CAddProfileDialog::CAddProfileDialog(HWND hwndOwner, HINSTANCE hi) {
TCHAR tempBuffer[MAX_PATH*10];
// Empty the profile list.
csa_Files.Empty();
// Prepare file filter (if not yet).
if (gacFilter[0] == NULL) {
ULONG offset; /* 32bits is enough even for sundown */
CString csIccFilter; CString csAllFilter;
// If the filter is not built yet, build it here.
csIccFilter.Load(IccProfileFilterString);
csAllFilter.Load(AllProfileFilterString);
offset = 0;
lstrcpy(gacFilter+offset, csIccFilter);
offset += lstrlen(csIccFilter)+1;
lstrcpy(gacFilter+offset, TEXT("*.icm;*.icc"));
offset += lstrlen(TEXT("*.icm;*.icc"))+1;
lstrcpy(gacFilter+offset, csAllFilter);
offset += lstrlen(csAllFilter)+1;
lstrcpy(gacFilter+offset, TEXT("*.*"));
offset += lstrlen(TEXT("*.*"))+1;
*(gacFilter+offset) = TEXT('\0');
}
if (gacColorDir[0] == _TEXT('\0')) {
DWORD dwcbDir = MAX_PATH;
GetColorDirectory(NULL, gacColorDir, &dwcbDir);
}
// Time to do the old OpenFile dialog stuff...
CString csTitle; csTitle.Load(AddProfileAssociation);
// Set initial filename as null.
memset(tempBuffer, 0, sizeof tempBuffer);
OPENFILENAME ofn = {
sizeof ofn, hwndOwner, hi,
gacFilter,
NULL, 0, 1,
tempBuffer, sizeof tempBuffer / sizeof tempBuffer[0],
NULL, 0,
gacColorDir,
csTitle,
OFN_ALLOWMULTISELECT | OFN_EXPLORER | OFN_HIDEREADONLY |
OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_ENABLEHOOK,
0, 0,
_TEXT("icm"),
(LPARAM) this, OpenFileHookProc, NULL};
if (!GetOpenFileName(&ofn)) {
if (CommDlgExtendedError() == FNERR_BUFFERTOOSMALL) {
CGlobals::Report(TooManyFileSelected);
}
} else {
if (tempBuffer[0] != TEXT('\0')) {
TCHAR *pPath = tempBuffer;
TCHAR *pFile = tempBuffer + lstrlen(tempBuffer) + 1;
// remember the last access-ed directory.
memset(gacColorDir, 0, sizeof pPath);
memcpy(gacColorDir, pPath, ofn.nFileOffset*sizeof(TCHAR));
if (*pFile) {
TCHAR workBuffer[MAX_PATH];
// This is multiple-selection
// Work through the buufer to build profile file list.
while (*pFile) {
lstrcpy(workBuffer,pPath);
lstrcat(workBuffer,TEXT("\\"));
lstrcat(workBuffer,pFile);
// Insert built profile pathname
AddProfile(workBuffer);
// Move on to next.
pFile = pFile + lstrlen(pFile) + 1;
}
}
else {
// Single selection case.
AddProfile(pPath);
#if HIDEYUKN_DBG
MessageBox(NULL,pPath,TEXT(""),MB_OK);
#endif
}
}
}
return;
}
// Printer Profile Management
CONST DWORD PrinterUIHelpIds[] = {
AddButton, IDH_PRINTERUI_ADD,
RemoveButton, IDH_PRINTERUI_REMOVE,
ProfileListControl, IDH_PRINTERUI_LIST,
#if !defined(_WIN95_)
ProfileListControlText, IDH_PRINTERUI_LIST,
PrinterUIIcon, IDH_DISABLED,
DescriptionText, IDH_DISABLED,
DefaultButton, IDH_PRINTERUI_DEFAULTBTN,
AutoSelButton, IDH_PRINTERUI_AUTOMATIC,
AutoSelText, IDH_PRINTERUI_AUTOMATIC,
ManualSelButton, IDH_PRINTERUI_MANUAL,
ManualSelText, IDH_PRINTERUI_MANUAL,
DefaultProfileText, IDH_PRINTERUI_DEFAULTTEXT,
DefaultProfile, IDH_PRINTERUI_DEFAULTTEXT,
#endif
0, 0
};
// Initialize lists override- call the base class, then set the default
void CPrinterProfileManagement::InitList() {
CDeviceProfileManagement::InitList();
m_uDefault = m_cpaProfile.Count() ? 0 : (unsigned) -1;
}
// Fill list override- write the correct default and call the base function
void CPrinterProfileManagement::FillList(DWORD dwFlags) {
// If we are initializing list box, we want to put focus on
// "default" profile. here we won't below FillList set focus
// to first one.
if (dwFlags & DEVLIST_ONINIT) {
dwFlags |= DEVLIST_NOSELECT;
}
CDeviceProfileManagement::FillList(dwFlags);
// There is either no default profile, an existing profile is the
// default, or a newly selected one is. Some people just like the
// selection operator.
// if there is only 1 profile in list box, we treat it as default profile.
if (SendMessage(m_hwndList,LB_GETCOUNT,0,0) == 1) {
m_uDefault = (unsigned)SendMessage(m_hwndList, LB_GETITEMDATA, 0, 0);
}
if (m_uDefault == -1) {
// There is no profile associated for this device.
CString csNoProfile;
csNoProfile.Load(NoProfileString);
SetDlgItemText(m_hwnd, DefaultProfile, csNoProfile);
} else {
// If the default has been deleted, set default as last in list.
if (m_uDefault >= (m_cpaProfile.Count() + m_cpaAdds.Count())) {
m_uDefault = (m_cpaProfile.Count() + m_cpaAdds.Count()) - 1;
}
// Put default profile name in UI.
CProfile *pcpDefault = (m_uDefault < m_cpaProfile.Count()) ? \
m_cpaProfile[m_uDefault] : \
m_cpaAdds[m_uDefault - m_cpaProfile.Count()];
SetDlgItemText(m_hwnd, DefaultProfile, pcpDefault -> GetName());
LRESULT idSelect = SendMessage(m_hwndList, LB_FINDSTRINGEXACT,
(WPARAM) -1, (LPARAM) (LPCTSTR) pcpDefault -> GetName());
// if could not find, just select first item.
if (idSelect == LB_ERR) {
idSelect = 0;
}
// Select it.
SendMessage(m_hwndList, LB_SETCURSEL, idSelect, 0);
}
// 03-08-1997 [email protected] Memphis RAID 18420
// Disable the Default button if there aren't any profiles
if (m_bManualMode && m_bAdminAccess) {
EnableWindow(GetDlgItem(m_hwnd, DefaultButton),
m_cpaAdds.Count() + m_cpaProfile.Count() - m_cuaRemovals.Count());
}
}
// Printer Profile Management class constructor- doesn't need any individual
// code at the moment.
CPrinterProfileManagement::CPrinterProfileManagement(LPCTSTR lpstrName,
HINSTANCE hiWhere) :
CDeviceProfileManagement(lpstrName, hiWhere, PrinterUI, CLASS_PRINTER) {
}
// This class overrides OnInit so it can disable the UI if the user lacks
// authority to make changes.
BOOL CPrinterProfileManagement::OnInit() {
// Call the base class routine first, as it does most of the work...
CDeviceProfileManagement::OnInit();
DWORD dwSize = sizeof(DWORD);
// Query current mode.
if (!InternalGetDeviceConfig((LPCTSTR)m_csDevice, CLASS_PRINTER,
MSCMS_PROFILE_ENUM_MODE, &m_bManualMode, &dwSize)) {
// Auto selection mode as default.
m_bManualMode = FALSE;
}
// Now, see if we have sufficient authority to administer the printer
HANDLE hPrinter;
PRINTER_DEFAULTS pd = {NULL, NULL, PRINTER_ACCESS_ADMINISTER};
m_bAdminAccess = TRUE;
m_bLocalPrinter = TRUE;
if (OpenPrinter(const_cast<LPTSTR> ((LPCTSTR) m_csDevice), &hPrinter, &pd)) {
// We can administer the printer- proceed in the normal way.
#if !defined(_WIN95_)
// If the printer is "Network Printer", we don't allow user to install
// or uninstall color profile.
BYTE StackPrinterData[sizeof(PRINTER_INFO_4)+MAX_PATH*2];
PBYTE pPrinterData = StackPrinterData;
BOOL bSuccess = TRUE;
DWORD dwReturned;
if (!GetPrinter(hPrinter, 4, pPrinterData, sizeof(StackPrinterData), &dwReturned)) {
if ((GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
(pPrinterData = (PBYTE) LocalAlloc(LPTR, dwReturned))) {
if (GetPrinter(hPrinter, 4, pPrinterData, dwReturned, &dwReturned)) {
bSuccess = TRUE;
}
}
} else {
bSuccess = TRUE;
}
if (bSuccess)
{
m_bLocalPrinter = ((PRINTER_INFO_4 *)pPrinterData)->pServerName ? FALSE : TRUE;
}
else
{
m_bAdminAccess = FALSE;
}
if (pPrinterData && (pPrinterData != StackPrinterData))
{
LocalFree(pPrinterData);
}
#endif // !defined(_WIN95_)
ClosePrinter(hPrinter);
} else {
m_bAdminAccess = FALSE;
}
// How many profile in listbox ?
LRESULT itemCount = SendMessage(m_hwndList, LB_GETCOUNT, 0, 0);
if (itemCount == LB_ERR) itemCount = 0;
// make sure the ancestor list code behaves correctly.
// You need Admin Access and a Local Printer to be able to add/remove profiles
m_bReadOnly = !(m_bAdminAccess && m_bLocalPrinter);
// Enable/Disable the controls (if needed)
CheckDlgButton(m_hwnd, AutoSelButton, m_bManualMode ? BST_UNCHECKED : BST_CHECKED);
CheckDlgButton(m_hwnd, ManualSelButton, m_bManualMode ? BST_CHECKED : BST_UNCHECKED);
// Only administrator can change 'auto','manual' configuration.
EnableWindow(GetDlgItem(m_hwnd, AutoSelButton), m_bAdminAccess && m_bLocalPrinter);
EnableWindow(GetDlgItem(m_hwnd, ManualSelButton), m_bAdminAccess && m_bLocalPrinter);
// Only administrator and printer is at local, can install/uninstall color profile.
EnableWindow(GetDlgItem(m_hwnd, AddButton), m_bAdminAccess && m_bLocalPrinter);
EnableWindow(GetDlgItem(m_hwnd, RemoveButton), m_bAdminAccess && m_bLocalPrinter && itemCount);
EnableWindow(m_hwndList, m_bAdminAccess);
EnableWindow(GetDlgItem(m_hwnd, DefaultProfileText), m_bAdminAccess);
EnableWindow(GetDlgItem(m_hwnd, DefaultProfile), m_bAdminAccess);
// Only with manual mode, these controls are enabled.
EnableWindow(GetDlgItem(m_hwnd, DefaultButton), m_bAdminAccess && m_bManualMode
&& m_bLocalPrinter && itemCount);
if (!m_bAdminAccess) {
// Set the focus to the OK button
SetFocus(GetDlgItem(m_hwndSheet, IDOK));
return FALSE; // Because we moved the focus!
}
return TRUE;
}
// Command processing- we never let them click into the edit control, to
// prevent them from editing it.
BOOL CPrinterProfileManagement::OnCommand(WORD wNotifyCode, WORD wid,
HWND hwndCtl) {
switch (wNotifyCode) {
case LBN_DBLCLK: {
// Retrieve the ID of the new default profile
// only accept dblclk changes if the dialog
// is not read only - i.e. user is admin
if (m_bManualMode) {
int id = (int)SendMessage(m_hwndList, LB_GETCURSEL, 0, 0);
m_uDefault = (unsigned)SendMessage(m_hwndList, LB_GETITEMDATA, id, 0);
// Change has been made, update the list
FillList(DEVLIST_CHANGED);
}
return TRUE;
}
case BN_CLICKED:
switch (wid) {
case AutoSelButton:
case ManualSelButton: {
// How many profile in listbox ?
LRESULT itemCount = SendMessage(m_hwndList, LB_GETCOUNT, 0, 0);
if (itemCount == LB_ERR) itemCount = 0;
m_bManualMode = (wid == ManualSelButton) ? TRUE : FALSE;
// Only with manual mode, these controls are enabled.
EnableWindow(GetDlgItem(m_hwnd, DefaultButton), m_bManualMode && itemCount);
// Configuarion has been changed, enable apply button.
EnableApplyButton();
SettingChanged(TRUE);
return TRUE;
}
case RemoveButton: {
// Make sure we've tracked the default profile correctly
// when a profile is removed.
// All cases break, because we then want the base class to
// process this message.
LRESULT id = SendMessage(m_hwndList, LB_GETCURSEL, 0, 0);
unsigned uTarget = (unsigned)SendMessage(m_hwndList, LB_GETITEMDATA,
id, 0);
if (uTarget > m_uDefault || m_uDefault == (unsigned) -1)
break; // Nothing here to worry about
if (m_uDefault == uTarget) {
if (CGlobals::ReportEx(AskRemoveDefault, m_hwnd, FALSE,
MB_YESNO|MB_ICONEXCLAMATION,0) == IDYES) {
// The default has been deleted- the profile
// at the top of monitor profile list will be
// made the default profile, if we have
LRESULT itemCount = SendMessage(m_hwndList, LB_GETCOUNT, 0, 0);
if ((itemCount != LB_ERR) && (itemCount > 1)) {
m_uDefault = (unsigned)SendMessage(m_hwndList, LB_GETITEMDATA, 0, 0);
if (m_uDefault == uTarget) {
m_uDefault = (unsigned)SendMessage(m_hwndList, LB_GETITEMDATA, 1, 0);
}
} else {
m_uDefault = -1;
}
break;
} else {
return TRUE; // opration cancelled.
}
}
if (uTarget < m_cpaProfile.Count())
break; // We're fine
// Must be an added profile below us in the list was
// zapped- we need to decrement ourselves.
m_uDefault--;
break;
}
case DefaultButton: {
LRESULT id = SendMessage(m_hwndList, LB_GETCURSEL, 0, 0);
m_uDefault = (unsigned)SendMessage(m_hwndList, LB_GETITEMDATA, id, 0);
// Change has been made, update the list
FillList(DEVLIST_CHANGED);
return TRUE;
}
}
// Deliberate fall-through (use a break if you add a case here)
}
// Use common command handling if not handled above
return CDeviceProfileManagement::OnCommand(wNotifyCode, wid, hwndCtl);
}
// Property Sheet notification processing
BOOL CPrinterProfileManagement::OnNotify(int idCtrl, LPNMHDR pnmh) {
switch (pnmh -> code) {
case PSN_APPLY: {
DisableApplyButton();
// If nothing changed, nothing need to do.
if (!SettingChanged())
return TRUE;
if (m_bManualMode) {
// If the user hasn't selected a default, and we have
// associated profiles, then we can't allow this.
// 03-08-1997 A-RobKj Fix for Memphis RAID 18416- if there's
// only one profile left, then it must be the default.
if (m_uDefault == (unsigned) -1 && (m_cpaAdds.Count() +
m_cpaProfile.Count() - m_cuaRemovals.Count()) > 1) {
CGlobals::Report(NoDefaultProfile, m_hwndSheet);
SetWindowLongPtr(m_hwnd, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE);
break;
}
// ATTENTION: This behavior is hardly depend on EnumColorProfiles() API
// OK, if the default profile has changed, we have to delete default
// profile associations, and do the association for default profile
// in "last".
// Let the base class handle the cases where the default hasn't
// changed, or we started with no profiles and still have none.
//
// 03-08-1997 Sleazy code note. The case where no default is
// selected but only one is assigned will now fall here. Since the
// default happens to be the "last", and there only is one, letting
// the base class handle it is not a problem. The list filling
// code will take care of the rest for us.
if (m_uDefault == (unsigned) -1) break;
// Remove default first (if default is associated), then associate later.
if (m_uDefault < m_cpaProfile.Count())
m_cpaProfile[m_uDefault] -> Dissociate(m_csDevice);
// Now do the other removals (actually just dissociations)
for (unsigned u = 0; u < m_cuaRemovals.Count(); u++) {
m_cpaProfile[m_cuaRemovals[u]] -> Dissociate(m_csDevice);
}
// Add in the new ones
for (u = 0; u < m_cpaAdds.Count(); u++) {
if (m_uDefault >= m_cpaProfile.Count())
if (u == (m_uDefault - m_cpaProfile.Count()))
continue; // this is default, will be done later
// OK, add it back in...
m_cpaAdds[u] -> Associate(m_csDevice);
}
// Finally, associate back default profile.
if (m_uDefault < m_cpaProfile.Count())
m_cpaProfile[m_uDefault] -> Associate(m_csDevice);
else
m_cpaAdds[m_uDefault - m_cpaProfile.Count()] -> Associate(m_csDevice);
// Update the various working structures...
InitList();
FillList();
SetWindowLongPtr(m_hwnd, DWLP_MSGRESULT, PSNRET_NOERROR);
// Now, we have updated settings.
SettingChanged(FALSE);
}
// Update "auto/manual" status.
InternalSetDeviceConfig((LPCTSTR)m_csDevice, CLASS_PRINTER,
MSCMS_PROFILE_ENUM_MODE, &m_bManualMode, sizeof(DWORD));
}
}
// Let the base class handle everything else
return CDeviceProfileManagement::OnNotify(idCtrl, pnmh);
}
// Context-sensitive help handler
BOOL CPrinterProfileManagement::OnHelp(LPHELPINFO pHelp) {
if (pHelp->iContextType == HELPINFO_WINDOW) {
WinHelp((HWND) pHelp->hItemHandle, WINDOWS_HELP_FILE,
HELP_WM_HELP, (ULONG_PTR) (LPSTR) PrinterUIHelpIds);
}
return (TRUE);
}
BOOL CPrinterProfileManagement::OnContextMenu(HWND hwnd) {
WinHelp(hwnd, WINDOWS_HELP_FILE,
HELP_CONTEXTMENU, (ULONG_PTR) (LPSTR) PrinterUIHelpIds);
return (TRUE);
}
// Scanner Profile Management
// Scanner Profile Management class constructor- doesn't need any individual
// code at the moment.
// Scanner Profile Management
CONST DWORD ScannerUIHelpIds[] = {
#if !defined(_WIN95_)
AddButton, IDH_SCANNERUI_ADD,
RemoveButton, IDH_SCANNERUI_REMOVE,
ProfileListControl, IDH_SCANNERUI_LIST,
ProfileListControlText, IDH_SCANNERUI_LIST,
#endif
0, 0
};
CScannerProfileManagement::CScannerProfileManagement(LPCTSTR lpstrName,
HINSTANCE hiWhere) :
CDeviceProfileManagement(lpstrName, hiWhere, ScannerUI, CLASS_SCANNER) {
m_bReadOnly = !IsAdmin();
}
// This class overrides OnInit so it can disable the UI if the user lacks
// authority to make changes.
BOOL CScannerProfileManagement::OnInit() {
// Call the base class routine first, as it does most of the work...
CDeviceProfileManagement::OnInit();
// Now, see if we have sufficient authority to administer the scanner
//
if (m_bReadOnly) {
// User is not Admin, Disable all of the controls
EnableWindow(GetDlgItem(m_hwnd, AddButton), FALSE);
EnableWindow(GetDlgItem(m_hwnd, RemoveButton), FALSE);
// Set the focus to the OK button
SetFocus(GetDlgItem(m_hwndSheet, IDOK));
return FALSE; // Because we moved the focus!
}
return TRUE;
}
// Context-sensitive help handler
BOOL CScannerProfileManagement::OnHelp(LPHELPINFO pHelp) {
if (pHelp->iContextType == HELPINFO_WINDOW) {
WinHelp((HWND) pHelp->hItemHandle, WINDOWS_HELP_FILE,
HELP_WM_HELP, (ULONG_PTR) (LPSTR) ScannerUIHelpIds);
}
return (TRUE);
}
BOOL CScannerProfileManagement::OnContextMenu(HWND hwnd) {
WinHelp(hwnd, WINDOWS_HELP_FILE,
HELP_CONTEXTMENU, (ULONG_PTR) (LPSTR) ScannerUIHelpIds);
return (TRUE);
}
// Monitor Profile Management class- since the mechanism for default
// profile manipulation is a bit sleazy, so is some of this code.
CONST DWORD MonitorUIHelpIds[] = {
AddButton, IDH_MONITORUI_ADD,
RemoveButton, IDH_MONITORUI_REMOVE,
DefaultButton, IDH_MONITORUI_DEFAULT,
ProfileListControl, IDH_MONITORUI_LIST,
#if !defined(_WIN95_)
ProfileListControlText, IDH_MONITORUI_LIST,
MonitorName, IDH_MONITORUI_DISPLAY,
MonitorNameText, IDH_MONITORUI_DISPLAY,
DefaultProfile, IDH_MONITORUI_PROFILE,
DefaultProfileText, IDH_MONITORUI_PROFILE,
#endif
0, 0
};
// Initialize lists override- call the base class, then set the default
void CMonitorProfileManagement::InitList() {
CDeviceProfileManagement::InitList();
m_uDefault = m_cpaProfile.Count() ? 0 : (unsigned) -1;
}
// Fill list override- write the correct default and call the base function
void CMonitorProfileManagement::FillList(DWORD dwFlags) {
// If we are initializing list box, we want to put focus on
// "default" profile. here we won't below FillList set focus
// to first one.
if (dwFlags & DEVLIST_ONINIT) {
dwFlags |= DEVLIST_NOSELECT;
}
CDeviceProfileManagement::FillList(dwFlags);
// There is either no default profile, an existing profile is the
// default, or a newly selected one is. Some people just like the
// selection operator.
// if there is only 1 profile in list box, we treat it as default profile.
if (SendMessage(m_hwndList,LB_GETCOUNT,0,0) == 1) {
m_uDefault = (unsigned)SendMessage(m_hwndList, LB_GETITEMDATA, 0, 0);
}
if (m_uDefault == -1) {
// There is no profile associated for this device.
CString csNoProfile;
csNoProfile.Load(NoProfileString);
SetDlgItemText(m_hwnd, DefaultProfile, csNoProfile);
} else {
// If the default has been deleted, set default as last in list.
if (m_uDefault >= (m_cpaProfile.Count() + m_cpaAdds.Count())) {
m_uDefault = (m_cpaProfile.Count() + m_cpaAdds.Count()) - 1;
}
// Put default profile name in UI.
CProfile *pcpDefault = (m_uDefault < m_cpaProfile.Count()) ? \
m_cpaProfile[m_uDefault] : \
m_cpaAdds[m_uDefault - m_cpaProfile.Count()];
SetDlgItemText(m_hwnd, DefaultProfile, pcpDefault -> GetName());
// If we are initialing list box, put focus on default profile.
if (dwFlags & DEVLIST_ONINIT) {
LRESULT idSelect = SendMessage(m_hwndList, LB_FINDSTRINGEXACT,
(WPARAM) -1, (LPARAM) (LPCTSTR) pcpDefault -> GetName());
// if could not find, just select first item.
if (idSelect == LB_ERR) {
idSelect = 0;
}
// Select it.
SendMessage(m_hwndList, LB_SETCURSEL, idSelect, 0);
}
}
// 03-08-1997 [email protected] Memphis RAID 18420
// Disable the Default button if there aren't any profiles
// We do it here, because this gets called any time the list changes.
// only allow Default button to be enabled if
// the dialog isn't read only.
// the remove button should remain dissabled
// under all conditions while the user is not
// administrator.
if (m_bReadOnly) {
EnableWindow(GetDlgItem(m_hwnd, RemoveButton), FALSE);
} else {
EnableWindow(GetDlgItem(m_hwnd, DefaultButton),
m_cpaAdds.Count() + m_cpaProfile.Count() - m_cuaRemovals.Count());
}
}
// Constructor
CMonitorProfileManagement::CMonitorProfileManagement(LPCTSTR lpstrName,
LPCTSTR lpstrFriendlyName,
HINSTANCE hiWhere) :
CDeviceProfileManagement(lpstrName, hiWhere, MonitorUI, CLASS_MONITOR) {
// if the user is not the administrator,
// make this property sheet read only.
m_bReadOnly = !IsAdmin();
// Keep friendly name in MonitorProfileManagement class.
m_csDeviceFriendlyName = lpstrFriendlyName;
}
// UI Initialization
BOOL CMonitorProfileManagement::OnInit() {
// Do common initializations
CDeviceProfileManagement::OnInit();
// Mark the device name in the space provided
SetDlgItemText(m_hwnd, MonitorName, m_csDeviceFriendlyName);
// Now, see if we have sufficient authority to administer the monitor
if(m_bReadOnly) {
// User is not Admin, Disable all of the controls
EnableWindow(GetDlgItem(m_hwnd, AddButton), FALSE);
EnableWindow(GetDlgItem(m_hwnd, RemoveButton), FALSE);
EnableWindow(GetDlgItem(m_hwnd, DefaultButton), FALSE);
// EnableWindow(m_hwndList, FALSE);
// Set the focus to the OK button
SetFocus(GetDlgItem(m_hwndSheet, IDOK));
return FALSE; // Because we moved the focus!
}
return TRUE;
}
// Command processing- we never let them click into the edit control, to
// prevent them from editing it.
BOOL CMonitorProfileManagement::OnCommand(WORD wNotifyCode, WORD wid,
HWND hwndCtl) {
switch (wNotifyCode) {
case LBN_DBLCLK: {
// Retrieve the ID of the new default profile
// only accept dblclk changes if the dialog
// is not read only - i.e. user is admin
if (!m_bReadOnly) {
int id = (int)SendMessage(m_hwndList, LB_GETCURSEL, 0, 0);
m_uDefault = (unsigned)SendMessage(m_hwndList, LB_GETITEMDATA, id, 0);
// Change has been made, update the list
FillList(DEVLIST_CHANGED);
}
return TRUE;
}
case BN_CLICKED:
switch (wid) {
case RemoveButton: {
// Make sure we've tracked the default profile correctly
// when a profile is removed.
// All cases break, because we then want the base class to
// process this message.
LRESULT id = SendMessage(m_hwndList, LB_GETCURSEL, 0, 0);
unsigned uTarget = (unsigned)SendMessage(m_hwndList, LB_GETITEMDATA,
id, 0);
if (uTarget > m_uDefault || m_uDefault == (unsigned) -1)
break; // Nothing here to worry about
if (m_uDefault == uTarget) {
if (CGlobals::ReportEx(AskRemoveDefault, m_hwnd, FALSE,
MB_YESNO|MB_ICONEXCLAMATION,0) == IDYES) {
// The default has been deleted- the profile
// at the top of monitor profile list will be
// made the default profile, if we have
LRESULT itemCount = SendMessage(m_hwndList, LB_GETCOUNT, 0, 0);
if ((itemCount != LB_ERR) && (itemCount > 1)) {
m_uDefault = (unsigned)SendMessage(m_hwndList, LB_GETITEMDATA, 0, 0);
if (m_uDefault == uTarget) {
m_uDefault = (unsigned)SendMessage(m_hwndList, LB_GETITEMDATA, 1, 0);
}
} else {
m_uDefault = -1;
}
break;
} else {
return TRUE; // operation cancelled.
}
}
if (uTarget < m_cpaProfile.Count())
break; // We're fine
// Must be an added profile below us in the list was
// zapped- we need to decrement ourselves.
m_uDefault--;
break;
}
case DefaultButton: {
LRESULT id = SendMessage(m_hwndList, LB_GETCURSEL, 0, 0);
m_uDefault = (unsigned)SendMessage(m_hwndList, LB_GETITEMDATA, id, 0);
// Change has been made, update the list
FillList(DEVLIST_CHANGED);
return TRUE;
}
}
// Deliberate fall-through (use a break if you add a case here)
}
// Use common command handling if not handled above
return CDeviceProfileManagement::OnCommand(wNotifyCode, wid, hwndCtl);
}
// Property Sheet notification processing
BOOL CMonitorProfileManagement::OnNotify(int idCtrl, LPNMHDR pnmh) {
switch (pnmh -> code) {
case PSN_APPLY: {
DisableApplyButton();
// If nothing changed, nothing need to do.
if (!SettingChanged())
return TRUE;
// If the user hasn't selected a default, and we have
// associated profiles, then we can't allow this.
// 03-08-1997 A-RobKj Fix for Memphis RAID 18416- if there's
// only one profile left, then it must be the default.
if (m_uDefault == (unsigned) -1 && (m_cpaAdds.Count() +
m_cpaProfile.Count() - m_cuaRemovals.Count()) > 1) {
CGlobals::Report(NoDefaultProfile, m_hwndSheet);
SetWindowLongPtr(m_hwnd, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE);
break;
}
// ATTENTION: This behavior is hardly depend on EnumColorProfiles() API
// OK, if the default profile has changed, we have to delete default
// profile associations, and do the association for default profile
// in "last".
// Let the base class handle the cases where the default hasn't
// changed, or we started with no profiles and still have none.
//
// 03-08-1997 Sleazy code note. The case where no default is
// selected but only one is assigned will now fall here. Since the
// default happens to be the "last", and there only is one, letting
// the base class handle it is not a problem. The list filling
// code will take care of the rest for us.
if (m_uDefault == (unsigned) -1) break;
// Remove default first (if default is associated), then associate later.
if (m_uDefault < m_cpaProfile.Count())
m_cpaProfile[m_uDefault] -> Dissociate(m_csDevice);
// Now do the other removals (actually just dissociations)
for (unsigned u = 0; u < m_cuaRemovals.Count(); u++) {
m_cpaProfile[m_cuaRemovals[u]] -> Dissociate(m_csDevice);
}
// Add in the new ones
for (u = 0; u < m_cpaAdds.Count(); u++) {
if (m_uDefault >= m_cpaProfile.Count())
if (u == (m_uDefault - m_cpaProfile.Count()))
continue; // this is default, will be done later
// OK, add it back in...
m_cpaAdds[u] -> Associate(m_csDevice);
}
// Finally, associate default profile.
if (m_uDefault < m_cpaProfile.Count())
m_cpaProfile[m_uDefault] -> Associate(m_csDevice);
else
m_cpaAdds[m_uDefault - m_cpaProfile.Count()] -> Associate(m_csDevice);
// Update the various working structures...
InitList();
FillList();
SetWindowLongPtr(m_hwnd, DWLP_MSGRESULT, PSNRET_NOERROR);
// Now, we have updated settings.
SettingChanged(FALSE);
}
}
// Let the base class handle everything else
return CDeviceProfileManagement::OnNotify(idCtrl, pnmh);
}
// Context-sensitive help handler
BOOL CMonitorProfileManagement::OnHelp(LPHELPINFO pHelp) {
if (pHelp->iContextType == HELPINFO_WINDOW) {
WinHelp((HWND) pHelp->hItemHandle, WINDOWS_HELP_FILE,
HELP_WM_HELP, (ULONG_PTR) (LPSTR) MonitorUIHelpIds);
}
return (TRUE);
}
BOOL CMonitorProfileManagement::OnContextMenu(HWND hwnd) {
WinHelp(hwnd, WINDOWS_HELP_FILE,
HELP_CONTEXTMENU, (ULONG_PTR) (LPSTR) MonitorUIHelpIds);
return (TRUE);
}