541 lines
13 KiB
C++
541 lines
13 KiB
C++
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
WizList.cpp : implementation file
|
|
|
|
File History:
|
|
|
|
JonY Jan-96 created
|
|
|
|
--*/
|
|
|
|
#include "stdafx.h"
|
|
#include "Mustard.h"
|
|
#include "WizList.h"
|
|
#include "Listdata.h"
|
|
#include "startd.h"
|
|
#include <winnetwk.h>
|
|
#include <shlobj.h>
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
const USHORT BITMAP_WIDTH = 32;
|
|
const USHORT BITMAP_HEIGHT = 32;
|
|
const USHORT MAX_PRINTER_NAME = 256 + 2;
|
|
const USHORT CELL_HEIGHT = 71;
|
|
const USHORT CELL_WIDTH = 300;
|
|
|
|
typedef BOOL (*BPRINTERSETUP)(HWND, UINT, UINT, LPTSTR, UINT*, LPCTSTR);
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CWizList
|
|
|
|
CWizList::CWizList()
|
|
{
|
|
CString fontname;
|
|
fontname.LoadString(IDS_FONT_NAME);
|
|
CString fontheight;
|
|
fontheight.LoadString(IDS_FONT_SIZE);
|
|
|
|
// regular font
|
|
m_pFont = new CFont;
|
|
LOGFONT lf;
|
|
|
|
memset(&lf, 0, sizeof(LOGFONT)); // Clear out structure.
|
|
lf.lfHeight = (LONG)_tcstoul(fontheight, NULL, 10);
|
|
_tcscpy(lf.lfFaceName, fontname);
|
|
lf.lfWeight = 100;
|
|
m_pFont->CreateFontIndirect(&lf); // Create the font.
|
|
|
|
// bold font
|
|
m_pFontBold = new CFont;
|
|
|
|
memset(&lf, 0, sizeof(LOGFONT)); // Clear out structure.
|
|
lf.lfHeight = (LONG)_tcstoul(fontheight, NULL, 10);
|
|
_tcscpy(lf.lfFaceName, fontname);
|
|
lf.lfWeight = 700;
|
|
m_pFontBold->CreateFontIndirect(&lf); // Create the font.
|
|
|
|
m_hPrinterLib = NULL;
|
|
|
|
}
|
|
|
|
CWizList::~CWizList()
|
|
{
|
|
if (m_pFont != NULL) delete m_pFont;
|
|
if (m_pFontBold != NULL) delete m_pFontBold;
|
|
if (m_hPrinterLib != NULL) FreeLibrary(m_hPrinterLib);
|
|
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CWizList, CListBox)
|
|
//{{AFX_MSG_MAP(CWizList)
|
|
ON_WM_MOUSEMOVE()
|
|
ON_WM_LBUTTONDOWN()
|
|
ON_CONTROL_REFLECT(LBN_SETFOCUS, OnSetfocus)
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CWizList message handlers
|
|
|
|
void CWizList::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
|
|
{
|
|
COLORREF crefOldText;
|
|
|
|
CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
|
|
pDC->SetBkMode(OPAQUE);
|
|
|
|
// save the current font for later
|
|
CFont* pOldFont = (CFont*)pDC->SelectObject(m_pFont);
|
|
|
|
CItemData* pData = (CItemData*)GetItemData(lpDrawItemStruct->itemID);
|
|
LPCTSTR pName2 = (const TCHAR*)pData->csDesc;
|
|
LPCTSTR pName = (const TCHAR*)pData->csName;
|
|
|
|
HICON hIcon = pData->hIcon;
|
|
HICON hSelIcon = pData->hSelIcon;
|
|
|
|
int nTop = (lpDrawItemStruct->rcItem.bottom + lpDrawItemStruct->rcItem.top) / 2;
|
|
switch (lpDrawItemStruct->itemAction)
|
|
{
|
|
case ODA_SELECT:
|
|
case ODA_DRAWENTIRE:
|
|
|
|
// paint the left side - then draw text
|
|
CRect crRight(50, lpDrawItemStruct->rcItem.top,
|
|
lpDrawItemStruct->rcItem.right,
|
|
lpDrawItemStruct->rcItem.bottom);
|
|
|
|
CBrush* pBrush = new CBrush;
|
|
pBrush->CreateSolidBrush(GetSysColor(COLOR_WINDOW));
|
|
|
|
pDC->FillRect(crRight, pBrush);
|
|
|
|
// paint the right - then draw text
|
|
pDC->SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
|
|
|
|
crRight = CRect(lpDrawItemStruct->rcItem.left, lpDrawItemStruct->rcItem.top,
|
|
50,
|
|
lpDrawItemStruct->rcItem.bottom);
|
|
pDC->FillRect(crRight, pBrush);
|
|
|
|
crRight = CRect(lpDrawItemStruct->rcItem.left + 5, lpDrawItemStruct->rcItem.top + 3,
|
|
140,
|
|
lpDrawItemStruct->rcItem.bottom);
|
|
|
|
// Is the item selected?
|
|
if (lpDrawItemStruct->itemState & ODS_SELECTED)
|
|
{
|
|
// Display bitmap
|
|
nTop = (lpDrawItemStruct->rcItem.bottom + lpDrawItemStruct->rcItem.top - BITMAP_HEIGHT) / 2;
|
|
pDC->DrawIcon(lpDrawItemStruct->rcItem.left + 9, nTop - 9, hSelIcon);
|
|
|
|
// paint the right - then draw text
|
|
crefOldText = pDC->SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT));
|
|
pDC->SetBkColor(GetSysColor(COLOR_HIGHLIGHT));
|
|
}
|
|
else
|
|
{
|
|
// Display bitmap
|
|
nTop = (lpDrawItemStruct->rcItem.bottom + lpDrawItemStruct->rcItem.top - BITMAP_HEIGHT) / 2;
|
|
pDC->DrawIcon(lpDrawItemStruct->rcItem.left + 9, nTop - 9, hIcon);
|
|
|
|
crefOldText = pDC->SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
|
|
pDC->SetBkColor(GetSysColor(COLOR_WINDOW));
|
|
}
|
|
|
|
// draw the top (bold) text
|
|
pDC->SelectObject(m_pFontBold);
|
|
CRect crTop = CRect(60, lpDrawItemStruct->rcItem.top + 8,
|
|
lpDrawItemStruct->rcItem.right - 10, lpDrawItemStruct->rcItem.bottom);
|
|
|
|
pDC->DrawText(pName, _tcslen(pName),
|
|
crTop,
|
|
DT_WORDBREAK);
|
|
|
|
// draw the lower text
|
|
pDC->SelectObject(m_pFont);
|
|
|
|
CRect crBottom = CRect(60, lpDrawItemStruct->rcItem.top + 28,
|
|
lpDrawItemStruct->rcItem.right - 10, lpDrawItemStruct->rcItem.bottom);
|
|
|
|
pDC->DrawText(pName2, _tcslen(pName2),
|
|
crBottom,
|
|
DT_WORDBREAK);
|
|
|
|
pDC->SelectObject(pOldFont);
|
|
|
|
pDC->SetTextColor(crefOldText );
|
|
|
|
delete pBrush;
|
|
break;
|
|
}
|
|
// Restore the original font
|
|
pDC->SelectObject(pOldFont);
|
|
|
|
}
|
|
|
|
void CWizList::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
|
|
{
|
|
lpMeasureItemStruct->itemHeight = CELL_HEIGHT;
|
|
lpMeasureItemStruct->itemWidth = CELL_WIDTH;
|
|
}
|
|
|
|
void CWizList::OnMouseMove(UINT nFlags, CPoint point)
|
|
{
|
|
if (((CStartD*)GetParent())->IsActive())
|
|
{
|
|
USHORT y = (USHORT)(point.y / CELL_HEIGHT);
|
|
USHORT usCurSel = (USHORT)GetCurSel();
|
|
|
|
if (usCurSel != y) SetCurSel(y);
|
|
|
|
// tell the other guy not to show any selection
|
|
m_pOtherGuy->SetCurSel(-1);
|
|
}
|
|
|
|
CListBox::OnMouseMove(nFlags, point);
|
|
}
|
|
|
|
void CWizList::OnLButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
USHORT usCurSel = (USHORT)GetCurSel();
|
|
|
|
// Exit if there's no selection.
|
|
if (usCurSel == (USHORT)-1)
|
|
return;
|
|
|
|
CItemData* pData = (CItemData*)GetItemData(usCurSel);
|
|
|
|
// is this the printer wiz?
|
|
if (pData->csAppStart1 == "")
|
|
{
|
|
try
|
|
{
|
|
LaunchPrinterWizard();
|
|
}
|
|
catch (...)
|
|
{
|
|
TRACE(_T("An exception occurred while attempting to start the Add Printer Wizard.\n"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// otherwise
|
|
CString csCmdLine = pData->csAppStart1 + " ";
|
|
csCmdLine += pData->csAppStart2;
|
|
TCHAR* pCmdLine = csCmdLine.GetBuffer(csCmdLine.GetLength());
|
|
|
|
STARTUPINFO sInfo;
|
|
ZeroMemory(&sInfo, sizeof(sInfo));
|
|
sInfo.cb = sizeof(sInfo);
|
|
|
|
PROCESS_INFORMATION pInfo;
|
|
|
|
BOOL bProc = CreateProcess(NULL,
|
|
pCmdLine,
|
|
NULL, NULL,
|
|
TRUE,
|
|
NORMAL_PRIORITY_CLASS,
|
|
NULL, NULL,
|
|
&sInfo,
|
|
&pInfo);
|
|
|
|
if (!bProc) AfxMessageBox(IDS_NO_START);
|
|
csCmdLine.ReleaseBuffer();
|
|
|
|
}
|
|
|
|
// CListBox::OnLButtonDown(nFlags, point);
|
|
}
|
|
|
|
void CWizList::PumpMessages()
|
|
{
|
|
MSG msg;
|
|
// check outstanding messages
|
|
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
|
{
|
|
if (!IsDialogMessage(&msg))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL CWizList::LaunchPrinterWizard()
|
|
{
|
|
CWaitCursor wc;
|
|
BOOL bReturn = TRUE;
|
|
HRESULT hr;
|
|
LPSHELLFOLDER pshf, pshfPrinters;
|
|
LPITEMIDLIST pidlPrintFolder, pidlPrintObj;
|
|
LPMALLOC pMalloc;
|
|
|
|
// Get a pointer to the shell's IMalloc interface.
|
|
hr = SHGetMalloc(&pMalloc);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Get a pointer to the shell's IShellFolder interface.
|
|
hr = SHGetDesktopFolder(&pshf);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Get a PIDL for the Printers folder.
|
|
hr = SHGetSpecialFolderLocation(GetSafeHwnd(), CSIDL_PRINTERS, &pidlPrintFolder);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Get a pointer to the IShellFolder interface for the Printer folder.
|
|
hr = pshf->BindToObject(pidlPrintFolder, NULL, IID_IShellFolder, (LPVOID*)&pshfPrinters);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Get a PIDL for the Add Printer object in the Printers folder.
|
|
hr = GetAddPrinterObject(pshfPrinters, &pidlPrintObj);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPCONTEXTMENU pcm;
|
|
|
|
// Get a pointer to the Printer folder's IContextMenu interface.
|
|
hr = pshfPrinters->GetUIObjectOf(GetSafeHwnd(), 1, (LPCITEMIDLIST*)&pidlPrintObj, IID_IContextMenu, NULL, (LPVOID*)&pcm);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Create a popup menu to hold the items in the context menu.
|
|
HMENU hMenu = CreatePopupMenu();
|
|
|
|
if (hMenu != NULL)
|
|
{
|
|
// Fill the menu.
|
|
hr = pcm->QueryContextMenu(hMenu, 0, 1, 0x7FFF, CMF_EXPLORE);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CString strCmd(CMDSTR_NEWFOLDER);
|
|
CHAR szCmd[MAX_PATH + 1];
|
|
int i, nCmd, nItems = ::GetMenuItemCount(hMenu);
|
|
|
|
for (i = 0; i < nItems; i++)
|
|
{
|
|
// Search through the menu to find the language-independent
|
|
// identifier for the Add Printer object's Open command.
|
|
nCmd = GetMenuItemID(hMenu, i);
|
|
hr = pcm->GetCommandString(i, GCS_VERB, NULL, szCmd, MAX_PATH);
|
|
|
|
TCHAR wStr[255];
|
|
memcpy(wStr, szCmd, 255);
|
|
if (SUCCEEDED(hr) && strCmd == wStr)
|
|
{
|
|
|
|
CMINVOKECOMMANDINFO cmi;
|
|
|
|
cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
|
|
cmi.fMask = 0;
|
|
cmi.hwnd = GetSafeHwnd();
|
|
cmi.lpVerb = (LPSTR)MAKEINTRESOURCE(nCmd - 1);
|
|
cmi.lpParameters = NULL;
|
|
cmi.lpDirectory = NULL;
|
|
cmi.nShow = SW_SHOW;
|
|
cmi.dwHotKey = 0;
|
|
cmi.hIcon = NULL;
|
|
|
|
// Invoke the Open command.
|
|
hr = pcm->InvokeCommand(&cmi);
|
|
|
|
// Exit the loop.
|
|
break;
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE(_T("IContextMenu::InvokeCommand failed.\n"));
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("IContextMenu::GetCommandString failed.\n"));
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
|
|
pcm->Release();
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("IShellFolder::GetUIObjectOf failed.\n"));
|
|
bReturn = FALSE;
|
|
}
|
|
|
|
// Destroy the temporary menu.
|
|
if (!DestroyMenu(hMenu))
|
|
TRACE(_T("DestroyMenu failed.\n"));
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("CreatePopupMenu failed.\n"));
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
|
|
// Release the IShellFolder interface for the Printers folder.
|
|
pshfPrinters->Release();
|
|
}
|
|
|
|
// Free the PIDL for the Add Printer object.
|
|
pMalloc->Free(pidlPrintObj);
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("IShellFolder::BindToObject failed.\n"));
|
|
bReturn = FALSE;
|
|
}
|
|
|
|
// Free the PIDL for the Printers folder.
|
|
pMalloc->Free(pidlPrintFolder);
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("SHGetSpecialFolderLocation failed.\n"));
|
|
bReturn = FALSE;
|
|
}
|
|
|
|
// Release the pointer to the shell's IShellFolder interface.
|
|
pshf->Release();
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("SHGetDesktopFolder failed.\n"));
|
|
bReturn = FALSE;
|
|
}
|
|
|
|
// Release the pointer to the shell's IMalloc interface.
|
|
pMalloc->Release();
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("SHGetMalloc failed.\n"));
|
|
bReturn = FALSE;
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
HRESULT CWizList::GetAddPrinterObject(LPSHELLFOLDER pshf, LPITEMIDLIST* ppidl)
|
|
{
|
|
HRESULT hr;
|
|
LPENUMIDLIST pEnum;
|
|
LPMALLOC pMalloc;
|
|
|
|
// Get a pointer to the shell's IMalloc interface.
|
|
hr = SHGetMalloc(&pMalloc);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Get a pointer to the folder's IEnumIDList interface.
|
|
hr = pshf->EnumObjects(GetSafeHwnd(), SHCONTF_NONFOLDERS, &pEnum);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
STRRET str;
|
|
CString strPrintObj, strEnumObj;
|
|
|
|
// Load the display name for the Add Printer object.
|
|
strPrintObj.LoadString(IDS_ADD_PRINTER);
|
|
|
|
// Enumerate the objects in the Printers folder.
|
|
while (pEnum->Next(1, ppidl, NULL) == NOERROR)
|
|
{
|
|
// Get the display name for the object.
|
|
hr = pshf->GetDisplayNameOf((LPCITEMIDLIST)*ppidl, SHGDN_INFOLDER, &str);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Copy the display name to the strEnumObj string.
|
|
switch (str.uType)
|
|
{
|
|
case STRRET_CSTR:
|
|
strEnumObj = str.cStr;
|
|
break;
|
|
|
|
case STRRET_OFFSET:
|
|
char pStr[255];
|
|
strcpy(pStr, (LPCSTR)(((UINT_PTR)*ppidl) + str.uOffset));
|
|
TCHAR wStr[255];
|
|
mbstowcs(wStr, pStr, 255);
|
|
strEnumObj = wStr;
|
|
break;
|
|
|
|
case STRRET_WSTR:
|
|
strEnumObj = str.pOleStr;
|
|
break;
|
|
|
|
case 0x04: //STRRET_OFFSETW
|
|
strEnumObj = (LPCTSTR)(((UINT_PTR)*ppidl) + str.uOffset);
|
|
break;
|
|
|
|
case 0x05:
|
|
{
|
|
TCHAR pStr[255];
|
|
memcpy(pStr, str.cStr, 255);
|
|
strEnumObj = pStr;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
strEnumObj.Empty();
|
|
}
|
|
|
|
// If we found the correct object, exit the loop.
|
|
if (strPrintObj == strEnumObj)
|
|
break;
|
|
|
|
// Free the PIDL returned by IEnumIDList::Next().
|
|
pMalloc->Free(*ppidl);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE(_T("IMalloc::Free failed.\n"));
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("IShellFolder::GetDisplayNameOf failed.\n"));
|
|
}
|
|
}
|
|
|
|
// Release the IEnumIDList pointer.
|
|
pEnum->Release();
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("IShellFolder::EnumObjects failed.\n"));
|
|
}
|
|
|
|
// Release the IMalloc pointer.
|
|
pMalloc->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
void CWizList::OnSetfocus()
|
|
{
|
|
// tell the other guy not to show any selection
|
|
m_pOtherGuy->SetCurSel(-1);
|
|
|
|
}
|