437 lines
9.8 KiB
C++
437 lines
9.8 KiB
C++
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1995 - 1999
|
|
All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
spllibex.cxx
|
|
|
|
Abstract:
|
|
|
|
spllib extentions
|
|
|
|
Author:
|
|
|
|
Lazar Ivanov (LazarI) 29-Mar-2000
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.hxx"
|
|
#pragma hdrstop
|
|
|
|
#include "spllibex.hxx"
|
|
|
|
////////////////////////////////////////////////
|
|
//
|
|
// class CMsgBoxCounter
|
|
//
|
|
// this class counts the popups which have come up
|
|
// during it's lifetime.
|
|
//
|
|
|
|
static DWORD g_dwTlsMsgsCounterCookie = -1;
|
|
|
|
CMsgBoxCounter::CMsgBoxCounter(UINT uFlags)
|
|
: m_uCount(0),
|
|
m_uFlags(uFlags),
|
|
m_uMsgID(0)
|
|
{
|
|
if( IsInitialized() )
|
|
{
|
|
// Only one instance of CMsgBoxCounter at a time can use
|
|
// the TLS cookie
|
|
ASSERT(NULL == TlsGetValue(g_dwTlsMsgsCounterCookie));
|
|
TlsSetValue(g_dwTlsMsgsCounterCookie, reinterpret_cast<LPVOID>(this));
|
|
}
|
|
}
|
|
|
|
CMsgBoxCounter::~CMsgBoxCounter()
|
|
{
|
|
if( IsInitialized() )
|
|
{
|
|
ASSERT(this == TlsGetValue(g_dwTlsMsgsCounterCookie));
|
|
TlsSetValue(g_dwTlsMsgsCounterCookie, NULL);
|
|
}
|
|
}
|
|
|
|
BOOL CMsgBoxCounter::Initialize()
|
|
{
|
|
// allocate TLS cookies
|
|
if( !IsInitialized() )
|
|
{
|
|
g_dwTlsMsgsCounterCookie = TlsAlloc();
|
|
}
|
|
return IsInitialized();
|
|
}
|
|
|
|
BOOL CMsgBoxCounter::Uninitialize()
|
|
{
|
|
// free up the TLS cookies
|
|
if( -1 != g_dwTlsMsgsCounterCookie )
|
|
{
|
|
VERIFY(TlsFree(g_dwTlsMsgsCounterCookie));
|
|
g_dwTlsMsgsCounterCookie = -1;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
UINT CMsgBoxCounter::GetCount()
|
|
{
|
|
UINT uReturn = INVALID_COUNT;
|
|
if( IsInitialized() )
|
|
{
|
|
// lookup the value in the TLS
|
|
CMsgBoxCounter *pThis = reinterpret_cast<CMsgBoxCounter*>(TlsGetValue(g_dwTlsMsgsCounterCookie));
|
|
uReturn = pThis->m_uCount;
|
|
}
|
|
return uReturn;
|
|
}
|
|
|
|
BOOL CMsgBoxCounter::IsInitialized()
|
|
{
|
|
// the TLS cookie should be valid to assume success
|
|
return (-1 != g_dwTlsMsgsCounterCookie);
|
|
}
|
|
|
|
void CMsgBoxCounter::LogMessage(UINT uFlags)
|
|
{
|
|
if( IsInitialized() )
|
|
{
|
|
CMsgBoxCounter *pThis = reinterpret_cast<CMsgBoxCounter*>(TlsGetValue(g_dwTlsMsgsCounterCookie));
|
|
|
|
if( pThis && (pThis->m_uFlags & uFlags) )
|
|
{
|
|
// increment the message box counter
|
|
pThis->m_uCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CMsgBoxCounter::SetMsg(UINT uMsgID)
|
|
{
|
|
if( IsInitialized() )
|
|
{
|
|
CMsgBoxCounter *pThis = reinterpret_cast<CMsgBoxCounter*>(TlsGetValue(g_dwTlsMsgsCounterCookie));
|
|
|
|
if( pThis )
|
|
{
|
|
pThis->m_uMsgID = uMsgID;
|
|
}
|
|
}
|
|
}
|
|
|
|
UINT CMsgBoxCounter::GetMsg()
|
|
{
|
|
UINT uMsgID = 0;
|
|
|
|
if( IsInitialized() )
|
|
{
|
|
CMsgBoxCounter *pThis = reinterpret_cast<CMsgBoxCounter*>(TlsGetValue(g_dwTlsMsgsCounterCookie));
|
|
|
|
if( pThis )
|
|
{
|
|
uMsgID = pThis->m_uMsgID;
|
|
}
|
|
}
|
|
|
|
return uMsgID;
|
|
}
|
|
|
|
////////////////////////////////////////////////
|
|
//
|
|
// class CPrintNotify
|
|
//
|
|
// printer notifications listener
|
|
//
|
|
|
|
CPrintNotify::CPrintNotify(
|
|
IPrinterChangeCallback *pClient,
|
|
DWORD dwCount,
|
|
const PPRINTER_NOTIFY_OPTIONS_TYPE arrNotifications,
|
|
DWORD dwFlags
|
|
):
|
|
m_bRegistered(FALSE),
|
|
m_uCookie(0),
|
|
m_dwCount(dwCount),
|
|
m_arrNotifications(arrNotifications),
|
|
m_dwFlags(dwFlags)
|
|
{
|
|
SINGLETHREADRESET(TrayUIThread)
|
|
|
|
ASSERT(pClient);
|
|
m_spClient.CopyFrom(pClient);
|
|
}
|
|
|
|
CPrintNotify::~CPrintNotify()
|
|
{
|
|
SINGLETHREAD(TrayUIThread)
|
|
|
|
// make sure we uninitialize here
|
|
Uninitialize();
|
|
}
|
|
|
|
HRESULT CPrintNotify::Initialize(LPCTSTR pszPrinter)
|
|
{
|
|
SINGLETHREAD(TrayUIThread)
|
|
|
|
ASSERT(!m_shPrinter);
|
|
ASSERT(!m_shNotify);
|
|
ASSERT(pszPrinter);
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
SetLastError(0);
|
|
if( NULL == m_pPrintLib.pGet() )
|
|
{
|
|
// aquire a reference to the printui lib object. this will be used
|
|
// to register/unregister notification handles in the folder cache.
|
|
TPrintLib::bGetSingleton(m_pPrintLib);
|
|
}
|
|
|
|
if( m_pPrintLib.pGet() )
|
|
{
|
|
hr = m_strPrinter.bUpdate(pszPrinter) ? S_OK : E_OUTOFMEMORY;
|
|
|
|
if( SUCCEEDED(hr) )
|
|
{
|
|
DWORD dwAccess = 0;
|
|
DWORD dwErr = TPrinter::sOpenPrinter(m_strPrinter, &dwAccess, &m_shPrinter);
|
|
hr = HRESULT_FROM_WIN32(dwErr);
|
|
}
|
|
|
|
if( SUCCEEDED(hr) )
|
|
{
|
|
ASSERT(m_dwFlags);
|
|
PRINTER_NOTIFY_OPTIONS opt = {2, 0, m_dwCount, m_arrNotifications};
|
|
m_shNotify = FindFirstPrinterChangeNotification(m_shPrinter, m_dwFlags, 0, &opt);
|
|
|
|
// setup the HRESULT here
|
|
hr = m_shNotify ? S_OK : CreateHRFromWin32();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// build an appropriate HRESULT
|
|
hr = CreateHRFromWin32();
|
|
}
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
// if something has failed we don't want to
|
|
// keep the handles around in this case
|
|
m_shNotify = NULL;
|
|
m_shPrinter = NULL;
|
|
m_strPrinter.bUpdate(NULL);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CPrintNotify::Uninitialize()
|
|
{
|
|
SINGLETHREAD(TrayUIThread)
|
|
|
|
// make sure we don't listen anymore
|
|
HRESULT hr = StopListen();
|
|
|
|
// clear the handles
|
|
m_shNotify = NULL;
|
|
m_shPrinter = NULL;
|
|
m_strPrinter.bUpdate(NULL);
|
|
|
|
return hr;
|
|
}
|
|
|
|
// this is just wrappers around _NotifyRegister
|
|
HRESULT CPrintNotify::StartListen()
|
|
{
|
|
SINGLETHREAD(TrayUIThread)
|
|
|
|
ASSERT(m_shNotify);
|
|
ASSERT(m_spClient);
|
|
|
|
// register ourselves in the wait list
|
|
return _NotifyRegister(TRUE);
|
|
}
|
|
|
|
HRESULT CPrintNotify::Refresh(LPVOID lpCookie, PFN_PrinterChange pfn)
|
|
{
|
|
SINGLETHREAD(TrayUIThread)
|
|
|
|
ASSERT(m_shNotify);
|
|
ASSERT(m_spClient);
|
|
ASSERT(m_dwFlags);
|
|
|
|
HRESULT hr = S_OK;
|
|
DWORD dwChange = 0;
|
|
CAutoPtrPrinterNotify pInfo;
|
|
|
|
PRINTER_NOTIFY_OPTIONS opt = {2, PRINTER_NOTIFY_OPTIONS_REFRESH, m_dwCount, m_arrNotifications };
|
|
if( FindNextPrinterChangeNotification(m_shNotify, &dwChange, &opt, pInfo.GetPPV()) )
|
|
{
|
|
// we hope the client callback will process this call quickly as there shouldn't
|
|
// be any delays here if we don't want to loose notifications.
|
|
// we don't really care what the retirn value is here.
|
|
if( pfn )
|
|
{
|
|
pfn(lpCookie, m_uCookie, dwChange, pInfo);
|
|
}
|
|
else
|
|
{
|
|
m_spClient->PrinterChange(m_uCookie, dwChange, pInfo);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// this is just wrappers around _NotifyRegister
|
|
HRESULT CPrintNotify::StopListen()
|
|
{
|
|
SINGLETHREAD(TrayUIThread)
|
|
|
|
// unregister ourselves from the wait list
|
|
return _NotifyRegister(FALSE);
|
|
}
|
|
|
|
HRESULT CPrintNotify::SetCookie(ULONG_PTR uCookie)
|
|
{
|
|
SINGLETHREAD(TrayUIThread)
|
|
|
|
m_uCookie = uCookie;
|
|
return S_OK;
|
|
}
|
|
|
|
LPCTSTR CPrintNotify::GetPrinter() const
|
|
{
|
|
// !!MT NOTES!!
|
|
// this function can be invoked only from the bkgnd threads,
|
|
// but it never touches the object state.
|
|
|
|
return (0 == m_strPrinter.uLen() ? NULL : m_strPrinter);
|
|
}
|
|
|
|
HANDLE CPrintNotify::GetPrinterHandle() const
|
|
{
|
|
SINGLETHREAD(TrayUIThread)
|
|
|
|
return m_shPrinter;
|
|
}
|
|
|
|
HRESULT CPrintNotify::_NotifyRegister(BOOL bRegister)
|
|
{
|
|
SINGLETHREAD(TrayUIThread)
|
|
|
|
DWORD dw = 0;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
//
|
|
// m_pPrintLib.pGet() could be NULL here in case of partial
|
|
// initialization
|
|
//
|
|
|
|
if( m_pPrintLib.pGet() && m_pPrintLib->pNotify().pGet() )
|
|
{
|
|
if( bRegister )
|
|
{
|
|
//
|
|
// Only register when in a unregistered state
|
|
//
|
|
if( m_bRegistered )
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
dw = m_pPrintLib->pNotify()->sRegister(this);
|
|
hr = HRESULT_FROM_WIN32(dw);
|
|
}
|
|
|
|
m_bRegistered = SUCCEEDED(hr) ? TRUE : m_bRegistered;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Only unregister when in a registered state
|
|
//
|
|
if( !m_bRegistered )
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
dw = m_pPrintLib->pNotify()->sUnregister(this);
|
|
hr = HRESULT_FROM_WIN32(dw);
|
|
}
|
|
|
|
m_bRegistered = SUCCEEDED(hr) ? FALSE : m_bRegistered;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HANDLE CPrintNotify::hEvent() const
|
|
{
|
|
// !!MT NOTES!!
|
|
// this function can be invoked only from the bkgnd threads,
|
|
// but it never touches the object state.
|
|
|
|
ASSERT(m_shNotify);
|
|
return m_shNotify;
|
|
}
|
|
|
|
void CPrintNotify::vProcessNotifyWork(TNotify *pNotify)
|
|
{
|
|
// !!MT NOTES!!
|
|
// this function can be invoked only from the bkgnd threads,
|
|
// but it never touches the object state.
|
|
|
|
ASSERT(m_shNotify);
|
|
ASSERT(m_spClient);
|
|
|
|
DWORD dwChange = 0;
|
|
CAutoPtrPrinterNotify pInfo;
|
|
|
|
PRINTER_NOTIFY_OPTIONS opt = {2, 0, m_dwCount, m_arrNotifications };
|
|
if( FindNextPrinterChangeNotification(m_shNotify, &dwChange, &opt, pInfo.GetPPV()) )
|
|
{
|
|
// we hope the client callback will process this call quickly as there shouldn't
|
|
// be any delays here if we don't want to loose notifications.
|
|
// we don't really care what the retirn value is here.
|
|
m_spClient->PrinterChange(m_uCookie, dwChange, pInfo);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////
|
|
// class CMultilineEditBug
|
|
//
|
|
|
|
LRESULT CMultilineEditBug::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HWND hDlg = GetParent(hwnd);
|
|
if( hDlg && GetParent(hDlg) )
|
|
{
|
|
hDlg = GetParent(hDlg);
|
|
}
|
|
|
|
if( hDlg && WM_KEYDOWN == uMsg && VK_RETURN == wParam && GetKeyState(VK_CONTROL) >= 0 )
|
|
{
|
|
LRESULT lr = SendMessage(hDlg, DM_GETDEFID, 0, 0);
|
|
if( lr && LOWORD(lr) && DC_HASDEFID == HIWORD(lr) )
|
|
{
|
|
HWND hwndButton = GetDlgItem(hDlg, LOWORD(lr));
|
|
PostMessage(hDlg, WM_COMMAND, MAKEWPARAM(LOWORD(lr), BN_CLICKED), (LPARAM)hwndButton);
|
|
}
|
|
}
|
|
|
|
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
}
|