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.
1574 lines
35 KiB
1574 lines
35 KiB
// This is a part of the Microsoft Foundation Classes C++ library.
|
|
// Copyright (C) 1992-1995 Microsoft Corporation
|
|
// All rights reserved.
|
|
//
|
|
// This source code is only intended as a supplement to the
|
|
// Microsoft Foundation Classes Reference and related
|
|
// electronic documentation provided with the library.
|
|
// See these sources for detailed information regarding the
|
|
// Microsoft Foundation Classes product.
|
|
|
|
#include "stdafx.h"
|
|
|
|
#ifdef AFXCTL_PROP_SEG
|
|
#pragma code_seg(AFXCTL_PROP_SEG)
|
|
#endif
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
#ifndef _DEBUG
|
|
#pragma intrinsic(memset)
|
|
#endif
|
|
|
|
#define new DEBUG_NEW
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Stock property mask
|
|
|
|
#define STOCKPROP_BACKCOLOR 0x00000001
|
|
#define STOCKPROP_CAPTION 0x00000002
|
|
#define STOCKPROP_FONT 0x00000004
|
|
#define STOCKPROP_FORECOLOR 0x00000008
|
|
#define STOCKPROP_TEXT 0x00000010
|
|
#define STOCKPROP_BORDERSTYLE 0x00000020
|
|
#define STOCKPROP_ENABLED 0x00000040
|
|
#define STOCKPROP_APPEARANCE 0x00000080
|
|
|
|
void COleControl::InitStockPropMask()
|
|
{
|
|
static const DWORD _dwStockFlags[] =
|
|
{
|
|
STOCKPROP_BACKCOLOR, // -501
|
|
0, // -502
|
|
0, // -503
|
|
STOCKPROP_BORDERSTYLE, // -504
|
|
0, // -505
|
|
0, // -506
|
|
0, // -507
|
|
0, // -508
|
|
0, // -509
|
|
0, // -510
|
|
0, // -511
|
|
STOCKPROP_FONT, // -512
|
|
STOCKPROP_FORECOLOR, // -513
|
|
STOCKPROP_ENABLED, // -514
|
|
0, // -515
|
|
0, // -516
|
|
STOCKPROP_TEXT, // -517
|
|
STOCKPROP_CAPTION, // -518
|
|
0, // -519
|
|
STOCKPROP_APPEARANCE, // -520
|
|
};
|
|
|
|
const AFX_DISPMAP* pDispMap = GetDispatchMap();
|
|
const AFX_DISPMAP_ENTRY* pEntry;
|
|
ASSERT(pDispMap != NULL);
|
|
|
|
// If stock property mask is already initialized, we're outta here.
|
|
if (*pDispMap->lpStockPropMask != (DWORD)-1)
|
|
return;
|
|
|
|
AfxLockGlobals(CRIT_STOCKMASK);
|
|
|
|
if (*pDispMap->lpStockPropMask == (DWORD)-1)
|
|
{
|
|
const AFX_DISPMAP* pDispMapTop = pDispMap;
|
|
DWORD dwStockPropMask = 0;
|
|
|
|
while (pDispMap != NULL)
|
|
{
|
|
pEntry = pDispMap->lpEntries;
|
|
while (pEntry->nPropOffset != -1)
|
|
{
|
|
int nIndex = DISPID_BACKCOLOR - pEntry->lDispID;
|
|
DWORD dwFlag;
|
|
if (nIndex >= 0 && nIndex < _countof(_dwStockFlags) &&
|
|
(dwFlag = _dwStockFlags[nIndex]) != 0)
|
|
{
|
|
dwStockPropMask |= dwFlag;
|
|
}
|
|
|
|
++pEntry;
|
|
}
|
|
// check base class
|
|
#ifdef _AFXDLL
|
|
pDispMap = (*pDispMap->pfnGetBaseMap)();
|
|
#else
|
|
pDispMap = pDispMap->pBaseMap;
|
|
#endif
|
|
}
|
|
|
|
*pDispMapTop->lpStockPropMask = dwStockPropMask;
|
|
}
|
|
|
|
AfxUnlockGlobals(CRIT_STOCKMASK);
|
|
}
|
|
|
|
static void ToggleBorderStyle(CWnd* pWnd)
|
|
{
|
|
if (pWnd->m_hWnd != NULL)
|
|
{
|
|
// toggle border style and force redraw of border
|
|
::SetWindowLong(pWnd->m_hWnd, GWL_STYLE, pWnd->GetStyle() ^ WS_BORDER);
|
|
::SetWindowPos(pWnd->m_hWnd, NULL, 0, 0, 0, 0,
|
|
SWP_DRAWFRAME | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
|
|
}
|
|
}
|
|
|
|
static void ToggleAppearance(CWnd* pWnd)
|
|
{
|
|
if (pWnd->m_hWnd != NULL)
|
|
{
|
|
// toggle border style and force redraw of border
|
|
::SetWindowLong(pWnd->m_hWnd, GWL_EXSTYLE, pWnd->GetExStyle() ^
|
|
WS_EX_CLIENTEDGE);
|
|
::SetWindowPos(pWnd->m_hWnd, NULL, 0, 0, 0, 0,
|
|
SWP_DRAWFRAME | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Property exchange for stock properties
|
|
|
|
void COleControl::ExchangeStockProps(CPropExchange* pPX)
|
|
{
|
|
BOOL bLoading = pPX->IsLoading();
|
|
DWORD dwStockPropMask = GetStockPropMask();
|
|
DWORD dwPersistMask = dwStockPropMask;
|
|
|
|
PX_ULong(pPX, _T("_StockProps"), dwPersistMask);
|
|
|
|
if (dwStockPropMask & (STOCKPROP_CAPTION | STOCKPROP_TEXT))
|
|
{
|
|
CString strText;
|
|
|
|
if (dwPersistMask & (STOCKPROP_CAPTION | STOCKPROP_TEXT))
|
|
{
|
|
if (!bLoading)
|
|
strText = InternalGetText();
|
|
if (dwStockPropMask & STOCKPROP_CAPTION)
|
|
PX_String(pPX, _T("Caption"), strText, _T(""));
|
|
if (dwStockPropMask & STOCKPROP_TEXT)
|
|
PX_String(pPX, _T("Text"), strText, _T(""));
|
|
}
|
|
if (bLoading)
|
|
{
|
|
TRY
|
|
SetText(strText);
|
|
END_TRY
|
|
}
|
|
}
|
|
|
|
if (dwStockPropMask & STOCKPROP_FORECOLOR)
|
|
{
|
|
if (dwPersistMask & STOCKPROP_FORECOLOR)
|
|
PX_Color(pPX, _T("ForeColor"), m_clrForeColor, AmbientForeColor());
|
|
else if (bLoading)
|
|
m_clrForeColor = AmbientForeColor();
|
|
}
|
|
|
|
if (dwStockPropMask & STOCKPROP_BACKCOLOR)
|
|
{
|
|
if (dwPersistMask & STOCKPROP_BACKCOLOR)
|
|
PX_Color(pPX, _T("BackColor"), m_clrBackColor, AmbientBackColor());
|
|
else if (bLoading)
|
|
m_clrBackColor = AmbientBackColor();
|
|
}
|
|
|
|
if (dwStockPropMask & STOCKPROP_FONT)
|
|
{
|
|
LPFONTDISP pFontDispAmbient = AmbientFont();
|
|
BOOL bChanged = TRUE;
|
|
|
|
if (dwPersistMask & STOCKPROP_FONT)
|
|
bChanged = PX_Font(pPX, _T("Font"), m_font, NULL, pFontDispAmbient);
|
|
else if (bLoading)
|
|
m_font.InitializeFont(NULL, pFontDispAmbient);
|
|
|
|
if (bLoading && bChanged)
|
|
OnFontChanged();
|
|
|
|
RELEASE(pFontDispAmbient);
|
|
}
|
|
|
|
if (dwStockPropMask & STOCKPROP_BORDERSTYLE)
|
|
{
|
|
short sBorderStyle = m_sBorderStyle;
|
|
|
|
if (dwPersistMask & STOCKPROP_BORDERSTYLE)
|
|
PX_Short(pPX, _T("BorderStyle"), m_sBorderStyle, 0);
|
|
else if (bLoading)
|
|
m_sBorderStyle = 0;
|
|
|
|
if (sBorderStyle != m_sBorderStyle)
|
|
ToggleBorderStyle(this);
|
|
}
|
|
|
|
if (dwStockPropMask & STOCKPROP_ENABLED)
|
|
{
|
|
BOOL bEnabled = m_bEnabled;
|
|
|
|
if (dwPersistMask & STOCKPROP_ENABLED)
|
|
PX_Bool(pPX, _T("Enabled"), m_bEnabled, TRUE);
|
|
else if (bLoading)
|
|
m_bEnabled = TRUE;
|
|
|
|
if ((bEnabled != m_bEnabled) && (m_hWnd != NULL))
|
|
::EnableWindow(m_hWnd, m_bEnabled);
|
|
}
|
|
|
|
if (dwStockPropMask & STOCKPROP_APPEARANCE)
|
|
{
|
|
short sAppearance = m_sAppearance;
|
|
|
|
if (dwPersistMask & STOCKPROP_APPEARANCE)
|
|
PX_Short(pPX, _T("Appearance"), m_sAppearance, 0);
|
|
else if (bLoading)
|
|
m_sAppearance = AmbientAppearance();
|
|
|
|
if (sAppearance != m_sAppearance)
|
|
ToggleAppearance(this);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Serialization for stock properties
|
|
|
|
void COleControl::SerializeStockProps(CArchive& ar)
|
|
{
|
|
BOOL bLoading = ar.IsLoading();
|
|
DWORD dwStockPropMask = GetStockPropMask();
|
|
DWORD dwPersistMask = dwStockPropMask;
|
|
|
|
if (bLoading)
|
|
{
|
|
ar >> dwPersistMask;
|
|
|
|
if (dwStockPropMask & (STOCKPROP_CAPTION | STOCKPROP_TEXT))
|
|
{
|
|
if (dwPersistMask & (STOCKPROP_CAPTION | STOCKPROP_TEXT))
|
|
{
|
|
CString strText;
|
|
ar >> strText;
|
|
TRY
|
|
SetText(strText);
|
|
END_TRY
|
|
}
|
|
else
|
|
{
|
|
TRY
|
|
SetText(_T(""));
|
|
END_TRY
|
|
}
|
|
}
|
|
|
|
if (dwStockPropMask & STOCKPROP_FORECOLOR)
|
|
{
|
|
if (dwPersistMask & STOCKPROP_FORECOLOR)
|
|
ar >> m_clrForeColor;
|
|
else
|
|
m_clrForeColor = AmbientForeColor();
|
|
}
|
|
|
|
if (dwStockPropMask & STOCKPROP_BACKCOLOR)
|
|
{
|
|
if (dwPersistMask & STOCKPROP_BACKCOLOR)
|
|
ar >> m_clrBackColor;
|
|
else
|
|
m_clrBackColor = AmbientBackColor();
|
|
}
|
|
|
|
if (dwStockPropMask & STOCKPROP_FONT)
|
|
{
|
|
BOOL bRead = FALSE;
|
|
|
|
if (dwPersistMask & STOCKPROP_FONT)
|
|
{
|
|
BYTE bFlag;
|
|
ar >> bFlag;
|
|
if (bFlag != 0xFF)
|
|
{
|
|
CArchiveStream stm(&ar);
|
|
LPSTREAM pstm = _AfxGetArchiveStream(ar, stm);
|
|
LPFONT pFont = _AfxCreateFontFromStream(pstm);
|
|
if (pFont != NULL)
|
|
{
|
|
m_font.SetFont(pFont);
|
|
bRead = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (! bRead)
|
|
{
|
|
LPFONTDISP pFontDispAmbient = AmbientFont();
|
|
m_font.InitializeFont(NULL, pFontDispAmbient);
|
|
RELEASE(pFontDispAmbient);
|
|
}
|
|
|
|
OnFontChanged();
|
|
}
|
|
|
|
if (dwStockPropMask & STOCKPROP_BORDERSTYLE)
|
|
{
|
|
if (dwPersistMask & STOCKPROP_BORDERSTYLE)
|
|
{
|
|
short sBorderStyle = m_sBorderStyle;
|
|
ar >> m_sBorderStyle;
|
|
if (sBorderStyle != m_sBorderStyle)
|
|
ToggleBorderStyle(this);
|
|
}
|
|
else
|
|
{
|
|
m_sBorderStyle = 0;
|
|
}
|
|
}
|
|
|
|
if (dwStockPropMask & STOCKPROP_ENABLED)
|
|
{
|
|
if (dwPersistMask & STOCKPROP_ENABLED)
|
|
{
|
|
BOOL bEnabled = m_bEnabled;
|
|
ar >> m_bEnabled;
|
|
if ((bEnabled != m_bEnabled) && (m_hWnd != NULL))
|
|
::EnableWindow(m_hWnd, m_bEnabled);
|
|
}
|
|
else
|
|
{
|
|
m_bEnabled = TRUE;
|
|
}
|
|
}
|
|
|
|
if (dwStockPropMask & STOCKPROP_APPEARANCE)
|
|
{
|
|
if (dwPersistMask & STOCKPROP_APPEARANCE)
|
|
{
|
|
short sAppearance = m_sAppearance;
|
|
ar >> m_sAppearance;
|
|
|
|
if (sAppearance != m_sAppearance)
|
|
ToggleAppearance(this);
|
|
}
|
|
else
|
|
{
|
|
m_sAppearance = AmbientAppearance();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ar << dwPersistMask;
|
|
|
|
if (dwStockPropMask & (STOCKPROP_CAPTION | STOCKPROP_TEXT))
|
|
ar << m_strText;
|
|
|
|
if (dwStockPropMask & STOCKPROP_FORECOLOR)
|
|
ar << m_clrForeColor;
|
|
|
|
if (dwStockPropMask & STOCKPROP_BACKCOLOR)
|
|
ar << m_clrBackColor;
|
|
|
|
if (dwStockPropMask & STOCKPROP_FONT)
|
|
{
|
|
BOOL bWrite = FALSE;
|
|
LPFONT pFont = m_font.m_pFont;
|
|
if (pFont != NULL)
|
|
{
|
|
// If same as ambient font (or error), write 0xFF for the flag
|
|
LPFONTDISP pFontDispAmbient = AmbientFont();
|
|
if (!_AfxIsSameFont(m_font, NULL, pFontDispAmbient))
|
|
{
|
|
LPPERSISTSTREAM pps = NULL;
|
|
if (SUCCEEDED(pFont->QueryInterface(IID_IPersistStream,
|
|
(LPVOID*)&pps)))
|
|
{
|
|
ASSERT_POINTER(pps, IPersistStream);
|
|
ar << (BYTE)0x00;
|
|
CArchiveStream stm(&ar);
|
|
LPSTREAM pstm = _AfxGetArchiveStream(ar, stm);
|
|
bWrite = SUCCEEDED(::OleSaveToStream(pps, pstm));
|
|
pps->Release();
|
|
if (!bWrite)
|
|
AfxThrowArchiveException(CArchiveException::generic);
|
|
}
|
|
}
|
|
RELEASE(pFontDispAmbient);
|
|
}
|
|
if (! bWrite)
|
|
{
|
|
ar << (BYTE)0xFF;
|
|
}
|
|
}
|
|
|
|
if (dwStockPropMask & STOCKPROP_BORDERSTYLE)
|
|
ar << m_sBorderStyle;
|
|
|
|
if (dwStockPropMask & STOCKPROP_ENABLED)
|
|
ar << m_bEnabled;
|
|
|
|
if (dwStockPropMask & STOCKPROP_APPEARANCE)
|
|
ar << m_sAppearance;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Initialization for stock properties
|
|
|
|
void COleControl::ResetStockProps()
|
|
{
|
|
DWORD dwStockPropMask = GetStockPropMask();
|
|
|
|
if (dwStockPropMask & (STOCKPROP_CAPTION | STOCKPROP_TEXT))
|
|
{
|
|
TRY
|
|
SetText(_T(""));
|
|
END_TRY
|
|
}
|
|
|
|
if (dwStockPropMask & STOCKPROP_FORECOLOR)
|
|
m_clrForeColor = AmbientForeColor();
|
|
|
|
if (dwStockPropMask & STOCKPROP_BACKCOLOR)
|
|
m_clrBackColor = AmbientBackColor();
|
|
|
|
if (dwStockPropMask & STOCKPROP_FONT)
|
|
{
|
|
LPFONTDISP pFontDispAmbient = AmbientFont();
|
|
m_font.InitializeFont(NULL, pFontDispAmbient);
|
|
RELEASE(pFontDispAmbient);
|
|
OnFontChanged();
|
|
}
|
|
|
|
if (dwStockPropMask & STOCKPROP_BORDERSTYLE)
|
|
m_sBorderStyle = 0;
|
|
|
|
if (dwStockPropMask & STOCKPROP_ENABLED)
|
|
m_bEnabled = TRUE;
|
|
|
|
if (dwStockPropMask & STOCKPROP_APPEARANCE)
|
|
m_sAppearance = AmbientAppearance();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Appearance property
|
|
|
|
short COleControl::GetAppearance()
|
|
{
|
|
return m_sAppearance;
|
|
}
|
|
|
|
void COleControl::SetAppearance(short sAppearance)
|
|
{
|
|
if (sAppearance != 0 && sAppearance != 1)
|
|
ThrowError(CTL_E_INVALIDPROPERTYVALUE, AFX_IDP_E_INVALIDPROPERTYVALUE);
|
|
|
|
// Is the property changing?
|
|
if (m_sAppearance == sAppearance)
|
|
return;
|
|
|
|
if (!BoundPropertyRequestEdit(DISPID_APPEARANCE))
|
|
SetNotPermitted();
|
|
|
|
ASSERT((m_hWnd == NULL) ||
|
|
((GetExStyle() & WS_EX_CLIENTEDGE) == (DWORD)(m_sAppearance ?
|
|
WS_EX_CLIENTEDGE : 0)));
|
|
|
|
m_sAppearance = sAppearance;
|
|
m_bModified = TRUE;
|
|
|
|
ToggleAppearance(this);
|
|
OnAppearanceChanged();
|
|
|
|
BoundPropertyChanged(DISPID_APPEARANCE);
|
|
}
|
|
|
|
void COleControl::OnAppearanceChanged()
|
|
{
|
|
// Can be overridden by subclass
|
|
|
|
InvalidateControl();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// BackColor property
|
|
|
|
OLE_COLOR COleControl::GetBackColor()
|
|
{
|
|
return m_clrBackColor;
|
|
}
|
|
|
|
void COleControl::SetBackColor(OLE_COLOR clrBackColor)
|
|
{
|
|
// Is the property changing?
|
|
if (m_clrBackColor == clrBackColor)
|
|
return;
|
|
|
|
if (FAILED(::OleTranslateColor(clrBackColor, NULL, NULL)))
|
|
ThrowError(CTL_E_INVALIDPROPERTYVALUE, AFX_IDP_E_INVALIDPROPERTYVALUE);
|
|
|
|
if (!BoundPropertyRequestEdit(DISPID_BACKCOLOR))
|
|
SetNotPermitted();
|
|
|
|
m_clrBackColor = clrBackColor;
|
|
m_bModified = TRUE;
|
|
OnBackColorChanged();
|
|
|
|
BoundPropertyChanged(DISPID_BACKCOLOR);
|
|
}
|
|
|
|
void COleControl::OnBackColorChanged()
|
|
{
|
|
// Can be overridden by subclass
|
|
InvalidateControl();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// BorderStyle property
|
|
|
|
short COleControl::GetBorderStyle()
|
|
{
|
|
return m_sBorderStyle;
|
|
}
|
|
|
|
void COleControl::SetBorderStyle(short sBorderStyle)
|
|
{
|
|
if (sBorderStyle != 0 && sBorderStyle != 1)
|
|
ThrowError(CTL_E_INVALIDPROPERTYVALUE, AFX_IDP_E_INVALIDPROPERTYVALUE);
|
|
|
|
// Is the property changing?
|
|
if (m_sBorderStyle == sBorderStyle)
|
|
return;
|
|
|
|
if (!BoundPropertyRequestEdit(DISPID_BORDERSTYLE))
|
|
SetNotPermitted();
|
|
|
|
ASSERT((m_hWnd == NULL) ||
|
|
((GetStyle() & WS_BORDER) == (DWORD)(m_sBorderStyle ? WS_BORDER : 0)));
|
|
|
|
m_sBorderStyle = sBorderStyle;
|
|
m_bModified = TRUE;
|
|
|
|
ToggleBorderStyle(this);
|
|
OnBorderStyleChanged();
|
|
|
|
BoundPropertyChanged(DISPID_BORDERSTYLE);
|
|
}
|
|
|
|
void COleControl::OnBorderStyleChanged()
|
|
{
|
|
// Can be overridden by subclass
|
|
|
|
InvalidateControl();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Text and Caption properties
|
|
|
|
const CString& COleControl::InternalGetText()
|
|
{
|
|
// Some subclassed controls (such as edit controls and comboboxes) change
|
|
// the window text without sending WM_SETTEXT. Therefore, we need to
|
|
// ensure that m_strText is up-to-date.
|
|
|
|
if (m_hWnd != NULL && IsSubclassedControl())
|
|
{
|
|
// Usually, the window text will be shorter than 32 characters.
|
|
// When it is, we can be more efficient.
|
|
|
|
static const int _cchUsual = 32;
|
|
|
|
if (DefWindowProc(WM_GETTEXT, (WPARAM)_cchUsual,
|
|
(LPARAM)m_strText.GetBufferSetLength(_cchUsual)) >= _cchUsual - 1)
|
|
{
|
|
// Text was too long: allocate a bigger buffer.
|
|
|
|
int nLen = DefWindowProc(WM_GETTEXTLENGTH, (WPARAM)0, (LPARAM)0) + 1;
|
|
DefWindowProc(WM_GETTEXT, (WPARAM)nLen,
|
|
(LPARAM)m_strText.GetBufferSetLength(nLen));
|
|
}
|
|
m_strText.ReleaseBuffer();
|
|
}
|
|
|
|
return m_strText;
|
|
}
|
|
|
|
BSTR COleControl::GetText()
|
|
{
|
|
return ((CString&)InternalGetText()).AllocSysString();
|
|
}
|
|
|
|
void COleControl::SetText(LPCTSTR pszText)
|
|
{
|
|
LRESULT lResult;
|
|
if (m_hWnd != NULL)
|
|
lResult = SendMessage(WM_SETTEXT, 0, (LPARAM)pszText);
|
|
else
|
|
lResult = OnSetText(0, (LPARAM)pszText);
|
|
|
|
if (lResult == -1)
|
|
SetNotPermitted();
|
|
}
|
|
|
|
LRESULT COleControl::OnSetText(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
ASSERT(lParam == 0 || AfxIsValidString((LPCTSTR)lParam));
|
|
|
|
// Is the property changing?
|
|
if ((lParam == 0 && InternalGetText().IsEmpty()) ||
|
|
(lParam != 0 && m_strText == (LPCTSTR)lParam))
|
|
return 0;
|
|
|
|
DWORD dwStockPropMask = GetStockPropMask();
|
|
|
|
if (dwStockPropMask & STOCKPROP_CAPTION)
|
|
if (!BoundPropertyRequestEdit(DISPID_CAPTION))
|
|
return -1;
|
|
|
|
if (dwStockPropMask & STOCKPROP_TEXT)
|
|
if (!BoundPropertyRequestEdit(DISPID_TEXT))
|
|
return -1;
|
|
|
|
LRESULT lResult = 0;
|
|
m_strText = (LPCTSTR)lParam;
|
|
m_bModified = TRUE;
|
|
|
|
if (m_hWnd != NULL)
|
|
lResult = DefWindowProc(WM_SETTEXT, wParam, lParam);
|
|
|
|
OnTextChanged();
|
|
|
|
if (dwStockPropMask & STOCKPROP_CAPTION)
|
|
BoundPropertyChanged(DISPID_CAPTION);
|
|
|
|
if (dwStockPropMask & STOCKPROP_TEXT)
|
|
BoundPropertyChanged(DISPID_TEXT);
|
|
|
|
return lResult;
|
|
}
|
|
|
|
void COleControl::OnTextChanged()
|
|
{
|
|
// Can be overridden by subclass
|
|
InvalidateControl();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Enabled property
|
|
|
|
BOOL COleControl::GetEnabled()
|
|
{
|
|
return m_bEnabled;
|
|
}
|
|
|
|
void COleControl::SetEnabled(BOOL bEnabled)
|
|
{
|
|
// Is the property changing?
|
|
if (m_bEnabled == bEnabled)
|
|
return;
|
|
|
|
if (!BoundPropertyRequestEdit(DISPID_ENABLED))
|
|
SetNotPermitted();
|
|
|
|
m_bEnabled = bEnabled;
|
|
m_bModified = TRUE;
|
|
if (m_hWnd != NULL)
|
|
::EnableWindow(m_hWnd, m_bEnabled);
|
|
|
|
// If the control is UI Active and the Enabled property changed to FALSE,
|
|
// then UI Deactivate the control.
|
|
|
|
if (m_bUIActive && !bEnabled)
|
|
m_xOleInPlaceObject.UIDeactivate();
|
|
|
|
OnEnabledChanged();
|
|
|
|
BoundPropertyChanged(DISPID_ENABLED);
|
|
}
|
|
|
|
void COleControl::OnEnabledChanged()
|
|
{
|
|
// Can be overridden by subclass
|
|
InvalidateControl();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Font property
|
|
|
|
CFontHolder& COleControl::InternalGetFont()
|
|
{
|
|
return m_font;
|
|
}
|
|
|
|
LPFONTDISP COleControl::GetFont()
|
|
{
|
|
return m_font.GetFontDispatch();
|
|
}
|
|
|
|
void COleControl::SetFont(LPFONTDISP pFontDisp)
|
|
{
|
|
ASSERT((pFontDisp == NULL) ||
|
|
AfxIsValidAddress(pFontDisp, sizeof(IDispatch), FALSE));
|
|
|
|
m_font.InitializeFont(NULL, pFontDisp);
|
|
m_bModified = TRUE;
|
|
OnFontChanged();
|
|
|
|
BoundPropertyChanged(DISPID_FONT);
|
|
}
|
|
|
|
void COleControl::OnFontChanged()
|
|
{
|
|
// Can be overridden by subclass
|
|
|
|
// Send WM_SETFONT to control's window
|
|
if ((m_hWnd != NULL) &&
|
|
(GetStockPropMask() & STOCKPROP_FONT) &&
|
|
IsSubclassedControl())
|
|
{
|
|
HFONT hFontPrev = (HFONT)SendMessage(WM_GETFONT, 0, 0);
|
|
|
|
CFontHolder& font = InternalGetFont();
|
|
|
|
if (font.m_pFont != NULL)
|
|
{
|
|
HFONT hFont = font.GetFontHandle();
|
|
font.m_pFont->AddRefHfont(hFont);
|
|
SendMessage(WM_SETFONT, (WPARAM)hFont, 0);
|
|
|
|
if (m_hFontPrev != NULL)
|
|
{
|
|
ASSERT(hFontPrev == m_hFontPrev);
|
|
font.m_pFont->ReleaseHfont(hFontPrev);
|
|
}
|
|
m_hFontPrev = hFont;
|
|
}
|
|
else
|
|
{
|
|
SendMessage(WM_SETFONT, NULL, 0);
|
|
m_hFontPrev = NULL;
|
|
}
|
|
}
|
|
|
|
// Invalidate the control
|
|
InvalidateControl();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// ForeColor property
|
|
|
|
OLE_COLOR COleControl::GetForeColor()
|
|
{
|
|
return m_clrForeColor;
|
|
}
|
|
|
|
void COleControl::SetForeColor(OLE_COLOR clrForeColor)
|
|
{
|
|
// Is the property changing?
|
|
if (m_clrForeColor == clrForeColor)
|
|
return;
|
|
|
|
if (FAILED(::OleTranslateColor(clrForeColor, NULL, NULL)))
|
|
ThrowError(CTL_E_INVALIDPROPERTYVALUE, AFX_IDP_E_INVALIDPROPERTYVALUE);
|
|
|
|
if (!BoundPropertyRequestEdit(DISPID_FORECOLOR))
|
|
SetNotPermitted();
|
|
|
|
m_clrForeColor = clrForeColor;
|
|
m_bModified = TRUE;
|
|
OnForeColorChanged();
|
|
|
|
BoundPropertyChanged(DISPID_FORECOLOR);
|
|
}
|
|
|
|
void COleControl::OnForeColorChanged()
|
|
{
|
|
// Can be overridden by subclass
|
|
InvalidateControl();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// hWnd property
|
|
|
|
OLE_HANDLE COleControl::GetHwnd()
|
|
{
|
|
return (OLE_HANDLE)((m_bInPlaceActive || m_bOpen) ? m_hWnd : NULL);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// ReadyState property
|
|
|
|
long COleControl::GetReadyState()
|
|
{
|
|
return m_lReadyState;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// COleControl::XFontNotification
|
|
|
|
STDMETHODIMP_(ULONG) COleControl::XFontNotification::AddRef()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) COleControl::XFontNotification::Release()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
STDMETHODIMP COleControl::XFontNotification::QueryInterface(
|
|
REFIID iid, LPVOID* ppvObj)
|
|
{
|
|
ASSERT(ppvObj != NULL);
|
|
|
|
if (IsEqualIID(iid, IID_IUnknown) ||
|
|
IsEqualIID(iid, IID_IPropertyNotifySink))
|
|
{
|
|
*ppvObj = this;
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
STDMETHODIMP COleControl::XFontNotification::OnChanged(DISPID)
|
|
{
|
|
METHOD_PROLOGUE_EX(COleControl, FontNotification)
|
|
pThis->OnFontChanged();
|
|
pThis->m_bModified = TRUE;
|
|
pThis->BoundPropertyChanged(DISPID_FONT);
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP COleControl::XFontNotification::OnRequestEdit(DISPID)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
CFont* COleControl::SelectStockFont(CDC* pDC)
|
|
{
|
|
return SelectFontObject(pDC, m_font);
|
|
}
|
|
|
|
CFont* COleControl::SelectFontObject(CDC* pDC, CFontHolder& fontHolder)
|
|
{
|
|
return fontHolder.Select(pDC, m_rcBounds.Height(), m_cyExtent);
|
|
}
|
|
|
|
void COleControl::GetStockTextMetrics(LPTEXTMETRIC lptm)
|
|
{
|
|
m_font.QueryTextMetrics(lptm);
|
|
}
|
|
|
|
void COleControl::GetFontTextMetrics(LPTEXTMETRIC lptm, CFontHolder& fontHolder)
|
|
{
|
|
fontHolder.QueryTextMetrics(lptm);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Ambient property access
|
|
|
|
BOOL AFXAPI _GetI4Property(LPDISPATCH pDispatch, DISPID dwDispID, DWORD* pdwResult)
|
|
{
|
|
if (pDispatch == NULL)
|
|
return FALSE;
|
|
|
|
DISPPARAMS dispparams;
|
|
memset(&dispparams, 0, sizeof dispparams);
|
|
|
|
VARIANT vaResult;
|
|
AfxVariantInit(&vaResult);
|
|
|
|
EXCEPINFO excepInfo;
|
|
memset(&excepInfo, 0, sizeof excepInfo);
|
|
|
|
UINT nArgErr = (UINT)-1; // initialize to invalid arg
|
|
|
|
HRESULT hr = pDispatch->Invoke(dwDispID, IID_NULL, 0, DISPATCH_PROPERTYGET,
|
|
&dispparams, &vaResult, &excepInfo, &nArgErr);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if ((V_VT(&vaResult) == VT_I4) ||
|
|
SUCCEEDED(VariantChangeType(&vaResult, &vaResult, 0, VT_I4)))
|
|
{
|
|
*pdwResult = V_I4(&vaResult);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
VariantClear(&vaResult);
|
|
|
|
if (excepInfo.bstrSource != NULL)
|
|
SysFreeString(excepInfo.bstrSource);
|
|
if (excepInfo.bstrDescription != NULL)
|
|
SysFreeString(excepInfo.bstrDescription);
|
|
if (excepInfo.bstrHelpFile != NULL)
|
|
SysFreeString(excepInfo.bstrHelpFile);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
COleDispatchDriver* COleControl::GetAmbientDispatchDriver()
|
|
{
|
|
if (m_ambientDispDriver.m_lpDispatch == NULL)
|
|
{
|
|
// Initialize pointer to ambient property dispinterface.
|
|
IDispatch* pDispatch = NULL;
|
|
|
|
if (m_pClientSite != NULL &&
|
|
SUCCEEDED(m_pClientSite->QueryInterface(IID_IDispatch,
|
|
reinterpret_cast<void**>(&pDispatch))))
|
|
{
|
|
ASSERT(pDispatch != NULL);
|
|
m_ambientDispDriver.AttachDispatch(pDispatch);
|
|
}
|
|
}
|
|
|
|
return &m_ambientDispDriver;
|
|
}
|
|
|
|
BOOL COleControl::GetAmbientProperty(DISPID dwDispID, VARTYPE vtProp, void* pvProp)
|
|
{
|
|
// First, check whether ambient property can be obtained from cache.
|
|
|
|
_AFXCTL_AMBIENT_CACHE* pAmbientCache = _afxAmbientCache;
|
|
if (pAmbientCache->m_bValid)
|
|
{
|
|
switch (vtProp)
|
|
{
|
|
// Fetch boolean by selecting appropriate flag in cache.
|
|
case VT_BOOL:
|
|
{
|
|
static const DWORD _dwAmbientFlags[] =
|
|
{
|
|
QACONTAINER_MESSAGEREFLECT, // -706
|
|
0, // -707
|
|
0, // -708
|
|
QACONTAINER_USERMODE, // -709
|
|
QACONTAINER_UIDEAD, // -710
|
|
QACONTAINER_SHOWGRABHANDLES, // -711
|
|
QACONTAINER_SHOWHATCHING, // -712
|
|
QACONTAINER_DISPLAYASDEFAULT, // -713
|
|
QACONTAINER_SUPPORTSMNEMONICS, // -714
|
|
QACONTAINER_AUTOCLIP, // -715
|
|
};
|
|
|
|
int nIndex = DISPID_AMBIENT_MESSAGEREFLECT - dwDispID;
|
|
DWORD dwFlag;
|
|
if (nIndex >= 0 && nIndex < _countof(_dwAmbientFlags) &&
|
|
(dwFlag = _dwAmbientFlags[nIndex]) != 0)
|
|
{
|
|
*(BOOL*)pvProp =
|
|
((pAmbientCache->m_dwAmbientFlags & dwFlag) != 0);
|
|
return TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
// Fetch color, appearance, or font from corresponding cache entry.
|
|
case VT_I4:
|
|
switch (dwDispID)
|
|
{
|
|
case DISPID_AMBIENT_FORECOLOR:
|
|
*(DWORD*)pvProp = pAmbientCache->m_colorFore;
|
|
return TRUE;
|
|
|
|
case DISPID_AMBIENT_BACKCOLOR:
|
|
*(DWORD*)pvProp = pAmbientCache->m_colorBack;
|
|
return TRUE;
|
|
|
|
case DISPID_AMBIENT_APPEARANCE:
|
|
*(DWORD*)pvProp = pAmbientCache->m_dwAppearance;
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
case VT_I2:
|
|
if (dwDispID == DISPID_AMBIENT_APPEARANCE)
|
|
{
|
|
*(short*)pvProp = (short)pAmbientCache->m_dwAppearance;
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
case VT_DISPATCH:
|
|
if ((dwDispID == DISPID_AMBIENT_FONT) &&
|
|
(pAmbientCache->m_pFont != NULL) &&
|
|
SUCCEEDED(pAmbientCache->m_pFont->QueryInterface(IID_IFontDisp,
|
|
reinterpret_cast<void**>(pvProp))))
|
|
{
|
|
return TRUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If there's no ambient dispatch interface available, then fail.
|
|
|
|
COleDispatchDriver* pDispDriver = GetAmbientDispatchDriver();
|
|
if (pDispDriver->m_lpDispatch == NULL)
|
|
return FALSE;
|
|
|
|
// If requested property is of type VT_I4, use optimized function.
|
|
|
|
if (vtProp == VT_I4)
|
|
return _GetI4Property(pDispDriver->m_lpDispatch, dwDispID,
|
|
(DWORD*)pvProp);
|
|
|
|
// If none of the above apply, just use the dispatch driver.
|
|
|
|
BOOL bSuccess = FALSE;
|
|
TRY
|
|
{
|
|
pDispDriver->GetProperty(dwDispID, vtProp, pvProp);
|
|
bSuccess = TRUE;
|
|
}
|
|
END_TRY
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
short COleControl::AmbientAppearance()
|
|
{
|
|
DWORD dwAppearance;
|
|
if (!GetAmbientProperty(DISPID_AMBIENT_APPEARANCE, VT_I4, &dwAppearance))
|
|
dwAppearance = 0;
|
|
return (short)dwAppearance;
|
|
}
|
|
|
|
OLE_COLOR COleControl::AmbientBackColor()
|
|
{
|
|
OLE_COLOR clrBackColor;
|
|
if (!GetAmbientProperty(DISPID_AMBIENT_BACKCOLOR, VT_I4, &clrBackColor))
|
|
clrBackColor = GetSysColor(COLOR_WINDOW);
|
|
return clrBackColor;
|
|
}
|
|
|
|
CString COleControl::AmbientDisplayName()
|
|
{
|
|
CString strDisplayName;
|
|
GetAmbientProperty(DISPID_AMBIENT_DISPLAYNAME, VT_BSTR, &strDisplayName);
|
|
return strDisplayName;
|
|
}
|
|
|
|
LPFONTDISP COleControl::AmbientFont()
|
|
{
|
|
// Note: Caller MUST Release the font!
|
|
LPFONTDISP pDisp;
|
|
if (!GetAmbientProperty(DISPID_AMBIENT_FONT, VT_DISPATCH, &pDisp))
|
|
pDisp = NULL;
|
|
return pDisp;
|
|
}
|
|
|
|
OLE_COLOR COleControl::AmbientForeColor()
|
|
{
|
|
OLE_COLOR clrForeColor;
|
|
if (!GetAmbientProperty(DISPID_AMBIENT_FORECOLOR, VT_I4, &clrForeColor))
|
|
clrForeColor = GetSysColor(COLOR_WINDOWTEXT);
|
|
return clrForeColor;
|
|
}
|
|
|
|
LCID COleControl::AmbientLocaleID()
|
|
{
|
|
LCID lcid;
|
|
if (!GetAmbientProperty(DISPID_AMBIENT_LOCALEID, VT_I4, &lcid))
|
|
lcid = 0;
|
|
return lcid;
|
|
}
|
|
|
|
CString COleControl::AmbientScaleUnits()
|
|
{
|
|
CString strScaleUnits;
|
|
GetAmbientProperty(DISPID_AMBIENT_SCALEUNITS, VT_BSTR, &strScaleUnits);
|
|
return strScaleUnits;
|
|
}
|
|
|
|
short COleControl::AmbientTextAlign()
|
|
{
|
|
short iTextAlign;
|
|
if (!GetAmbientProperty(DISPID_AMBIENT_TEXTALIGN, VT_I2, &iTextAlign))
|
|
iTextAlign = 0;
|
|
return iTextAlign;
|
|
}
|
|
|
|
BOOL COleControl::AmbientUserMode()
|
|
{
|
|
BOOL bUserMode;
|
|
if (!GetAmbientProperty(DISPID_AMBIENT_USERMODE, VT_BOOL, &bUserMode))
|
|
bUserMode = TRUE;
|
|
return bUserMode;
|
|
}
|
|
|
|
BOOL COleControl::AmbientUIDead()
|
|
{
|
|
BOOL bUIDead;
|
|
if (!GetAmbientProperty(DISPID_AMBIENT_UIDEAD, VT_BOOL, &bUIDead))
|
|
bUIDead = FALSE;
|
|
return bUIDead;
|
|
}
|
|
|
|
BOOL COleControl::AmbientShowGrabHandles()
|
|
{
|
|
BOOL bShowGrab;
|
|
if (!GetAmbientProperty(DISPID_AMBIENT_SHOWGRABHANDLES, VT_BOOL, &bShowGrab))
|
|
bShowGrab = TRUE;
|
|
return bShowGrab;
|
|
}
|
|
|
|
BOOL COleControl::AmbientShowHatching()
|
|
{
|
|
BOOL bShowHatch;
|
|
if (!GetAmbientProperty(DISPID_AMBIENT_SHOWHATCHING, VT_BOOL, &bShowHatch))
|
|
bShowHatch = TRUE;
|
|
return bShowHatch;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Calls to IPropertyNotifySink
|
|
|
|
void COleControl::BoundPropertyChanged(DISPID dispid)
|
|
{
|
|
POSITION pos = m_xPropConnPt.GetStartPosition();
|
|
LPPROPERTYNOTIFYSINK pPropNotifySink;
|
|
|
|
while (pos != NULL)
|
|
{
|
|
pPropNotifySink =
|
|
(LPPROPERTYNOTIFYSINK)m_xPropConnPt.GetNextConnection(pos);
|
|
ASSERT(pPropNotifySink != NULL);
|
|
pPropNotifySink->OnChanged(dispid);
|
|
}
|
|
}
|
|
|
|
BOOL COleControl::BoundPropertyRequestEdit(DISPID dispid)
|
|
{
|
|
POSITION pos = m_xPropConnPt.GetStartPosition();
|
|
LPPROPERTYNOTIFYSINK pPropNotifySink;
|
|
|
|
while (pos != NULL)
|
|
{
|
|
pPropNotifySink =
|
|
(LPPROPERTYNOTIFYSINK)m_xPropConnPt.GetNextConnection(pos);
|
|
ASSERT(pPropNotifySink != NULL);
|
|
if (pPropNotifySink->OnRequestEdit(dispid) != S_OK)
|
|
return FALSE;
|
|
}
|
|
|
|
// All of the sinks said yes, so it's ok.
|
|
return TRUE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Function to call when BoundPropertyRequestEdit fails
|
|
|
|
void COleControl::SetNotPermitted()
|
|
{
|
|
ThrowError(CTL_E_SETNOTPERMITTED, AFX_IDP_E_SETNOTPERMITTED);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Placeholder functions for read-only or write-only properties
|
|
|
|
void COleControl::SetNotSupported()
|
|
{
|
|
ThrowError(CTL_E_SETNOTSUPPORTED, AFX_IDP_E_SETNOTSUPPORTED);
|
|
}
|
|
|
|
void COleControl::GetNotSupported()
|
|
{
|
|
ThrowError(CTL_E_GETNOTSUPPORTED, AFX_IDP_E_GETNOTSUPPORTED);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// COleControl::XPerPropertyBrowsing
|
|
|
|
STDMETHODIMP_(ULONG) COleControl::XPerPropertyBrowsing::AddRef()
|
|
{
|
|
METHOD_PROLOGUE_EX_(COleControl, PerPropertyBrowsing)
|
|
return (ULONG)pThis->ExternalAddRef();
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) COleControl::XPerPropertyBrowsing::Release()
|
|
{
|
|
METHOD_PROLOGUE_EX_(COleControl, PerPropertyBrowsing)
|
|
return (ULONG)pThis->ExternalRelease();
|
|
}
|
|
|
|
STDMETHODIMP COleControl::XPerPropertyBrowsing::QueryInterface(
|
|
REFIID iid, LPVOID* ppvObj)
|
|
{
|
|
METHOD_PROLOGUE_EX_(COleControl, PerPropertyBrowsing)
|
|
return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
|
|
}
|
|
|
|
STDMETHODIMP COleControl::XPerPropertyBrowsing::GetDisplayString(
|
|
DISPID dispid, BSTR* lpbstr)
|
|
{
|
|
METHOD_PROLOGUE_EX(COleControl, PerPropertyBrowsing)
|
|
|
|
ASSERT_NULL_OR_POINTER(lpbstr, BSTR);
|
|
|
|
CString strValue;
|
|
BOOL bSuccess = pThis->OnGetDisplayString(dispid, strValue);
|
|
|
|
if (lpbstr != NULL)
|
|
*lpbstr = (bSuccess ? strValue.AllocSysString() : NULL);
|
|
|
|
return bSuccess ? S_OK : S_FALSE;
|
|
}
|
|
|
|
BOOL COleControl::OnGetDisplayString(DISPID dispid, CString& strValue)
|
|
{
|
|
TRY
|
|
{
|
|
switch (dispid)
|
|
{
|
|
case DISPID_FONT:
|
|
return m_font.GetDisplayString(strValue);
|
|
|
|
case DISPID_BORDERSTYLE:
|
|
return strValue.LoadString(m_sBorderStyle == 0 ?
|
|
AFX_IDS_BORDERSTYLE_0 : AFX_IDS_BORDERSTYLE_1);
|
|
}
|
|
}
|
|
END_TRY
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
STDMETHODIMP COleControl::XPerPropertyBrowsing::MapPropertyToPage(
|
|
DISPID dispid, LPCLSID lpclsid)
|
|
{
|
|
METHOD_PROLOGUE_EX(COleControl, PerPropertyBrowsing)
|
|
|
|
ASSERT_NULL_OR_POINTER(lpclsid, CLSID);
|
|
|
|
CLSID clsid = GUID_NULL;
|
|
BOOL bPageOptional = FALSE;
|
|
BOOL bSuccess = pThis->OnMapPropertyToPage(dispid, &clsid, &bPageOptional);
|
|
|
|
if (lpclsid != NULL)
|
|
*lpclsid = (bSuccess ? clsid : GUID_NULL);
|
|
|
|
return bSuccess ? (bPageOptional ? S_OK : S_FALSE) :
|
|
PERPROP_E_NOPAGEAVAILABLE;
|
|
}
|
|
|
|
BOOL COleControl::OnMapPropertyToPage(DISPID dispid, LPCLSID lpclsid,
|
|
BOOL* pbPageOptional)
|
|
{
|
|
switch (dispid)
|
|
{
|
|
case DISPID_FONT:
|
|
*lpclsid = CLSID_CFontPropPage;
|
|
*pbPageOptional = TRUE;
|
|
return TRUE;
|
|
|
|
case DISPID_BACKCOLOR:
|
|
case DISPID_FORECOLOR:
|
|
*lpclsid = CLSID_CColorPropPage;
|
|
*pbPageOptional = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
inline LPOLESTR AFXAPI _AfxCopyString(LPCTSTR psz)
|
|
{
|
|
if (psz == NULL)
|
|
return NULL;
|
|
|
|
int cch = lstrlen(psz) + 1;
|
|
LPOLESTR pszCopy = NULL;
|
|
|
|
if ((pszCopy = (LPOLESTR)CoTaskMemAlloc(cch * sizeof(OLECHAR))) != NULL)
|
|
{
|
|
#ifdef _UNICODE
|
|
wcscpy(pszCopy, psz);
|
|
#else
|
|
MultiByteToWideChar(CP_ACP, 0, psz, -1, pszCopy, cch);
|
|
#endif
|
|
}
|
|
|
|
return pszCopy;
|
|
}
|
|
|
|
STDMETHODIMP COleControl::XPerPropertyBrowsing::GetPredefinedStrings(
|
|
DISPID dispid, CALPOLESTR* lpcaStringsOut, CADWORD* lpcaCookiesOut)
|
|
{
|
|
METHOD_PROLOGUE_EX(COleControl, PerPropertyBrowsing)
|
|
|
|
if ((lpcaStringsOut == NULL) || (lpcaCookiesOut == NULL))
|
|
return E_POINTER;
|
|
|
|
ASSERT_POINTER(lpcaStringsOut, CALPOLESTR);
|
|
ASSERT_POINTER(lpcaCookiesOut, CADWORD);
|
|
|
|
CStringArray stringArray;
|
|
CDWordArray cookieArray;
|
|
|
|
BOOL bSuccess = pThis->OnGetPredefinedStrings(dispid, &stringArray,
|
|
&cookieArray);
|
|
|
|
if (bSuccess)
|
|
{
|
|
// Allocate and fill arrays to return.
|
|
|
|
ASSERT(stringArray.GetSize() == cookieArray.GetSize());
|
|
|
|
int iElem = 0;
|
|
LPOLESTR lpszCopy;
|
|
ULONG cElems = stringArray.GetSize();
|
|
|
|
lpcaStringsOut->pElems = (LPOLESTR*)CoTaskMemAlloc(
|
|
sizeof(LPOLESTR) * cElems);
|
|
|
|
if (lpcaStringsOut->pElems == NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
lpcaCookiesOut->pElems = (DWORD*)CoTaskMemAlloc(
|
|
sizeof(DWORD*) * cElems);
|
|
|
|
if (lpcaCookiesOut->pElems == NULL)
|
|
{
|
|
CoTaskMemFree(lpcaStringsOut->pElems);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
lpcaStringsOut->cElems = cElems;
|
|
lpcaCookiesOut->cElems = cElems;
|
|
|
|
for (iElem = 0; iElem < (int)cElems; iElem++)
|
|
{
|
|
lpszCopy = _AfxCopyString(stringArray.GetAt(iElem));
|
|
|
|
if (lpszCopy == NULL)
|
|
{
|
|
// cleanup everything allocated so far...
|
|
while (--iElem >= 0)
|
|
CoTaskMemFree(lpcaStringsOut->pElems[iElem]);
|
|
|
|
CoTaskMemFree(lpcaCookiesOut->pElems);
|
|
CoTaskMemFree(lpcaStringsOut->pElems);
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
lpcaStringsOut->pElems[iElem] = lpszCopy;
|
|
lpcaCookiesOut->pElems[iElem] = cookieArray.GetAt(iElem);
|
|
}
|
|
}
|
|
|
|
return bSuccess ? S_OK : S_FALSE;
|
|
}
|
|
|
|
BOOL COleControl::OnGetPredefinedStrings(DISPID dispid,
|
|
CStringArray* pStringArray, CDWordArray* pCookieArray)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
|
|
switch (dispid)
|
|
{
|
|
case DISPID_BORDERSTYLE:
|
|
TRY
|
|
{
|
|
CString str;
|
|
str.LoadString(AFX_IDS_BORDERSTYLE_0);
|
|
pStringArray->Add(str);
|
|
pCookieArray->Add(0);
|
|
str.LoadString(AFX_IDS_BORDERSTYLE_1);
|
|
pStringArray->Add(str);
|
|
pCookieArray->Add(1);
|
|
bResult = TRUE;
|
|
}
|
|
CATCH (CException, e)
|
|
{
|
|
pStringArray->RemoveAll();
|
|
pCookieArray->RemoveAll();
|
|
bResult = FALSE;
|
|
}
|
|
END_CATCH
|
|
break;
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
STDMETHODIMP COleControl::XPerPropertyBrowsing::GetPredefinedValue(
|
|
DISPID dispid, DWORD dwCookie, VARIANT* lpvarOut)
|
|
{
|
|
METHOD_PROLOGUE_EX(COleControl, PerPropertyBrowsing)
|
|
|
|
ASSERT_POINTER(lpvarOut, VARIANT);
|
|
|
|
return pThis->OnGetPredefinedValue(dispid, dwCookie, lpvarOut) ?
|
|
S_OK : E_FAIL;
|
|
}
|
|
|
|
BOOL COleControl::OnGetPredefinedValue(DISPID dispid, DWORD dwCookie,
|
|
VARIANT* lpvarOut)
|
|
{
|
|
switch (dispid)
|
|
{
|
|
case DISPID_BORDERSTYLE:
|
|
if ((dwCookie == 0) || (dwCookie == 1))
|
|
{
|
|
VariantClear(lpvarOut);
|
|
V_VT(lpvarOut) = VT_I4;
|
|
V_I4(lpvarOut) = dwCookie;
|
|
return TRUE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#ifndef _MAC
|
|
void COleControl::Load(LPCTSTR strNewPath, CDataPathProperty& prop)
|
|
{
|
|
prop.SetControl(this);
|
|
prop.Open(strNewPath);
|
|
}
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CDataPathProperty implementation
|
|
|
|
#ifndef _MAC
|
|
|
|
BOOL CDataPathProperty::Open(CFileException* pError)
|
|
{
|
|
return Open(m_strPath, m_pControl ? m_pControl->GetClientSite() : NULL, pError);
|
|
}
|
|
|
|
BOOL CDataPathProperty::Open(LPCTSTR lpszPath, CFileException* pError)
|
|
{
|
|
SetPath(lpszPath);
|
|
return Open(pError);
|
|
}
|
|
|
|
BOOL CDataPathProperty::Open(COleControl* pControl, CFileException* pError)
|
|
{
|
|
SetControl(pControl);
|
|
return Open(pError);
|
|
}
|
|
|
|
BOOL CDataPathProperty::Open(LPCTSTR lpszPath, COleControl* pControl, CFileException* pError)
|
|
{
|
|
SetControl(pControl);
|
|
SetPath(lpszPath);
|
|
return Open(pError);
|
|
}
|
|
|
|
void CDataPathProperty::ResetData()
|
|
{
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
void CDataPathProperty::AssertValid() const
|
|
{
|
|
CAsyncMonikerFile::AssertValid();
|
|
}
|
|
|
|
void CDataPathProperty::Dump(CDumpContext& dc) const
|
|
{
|
|
CAsyncMonikerFile::Dump(dc);
|
|
|
|
dc << "\nm_pControl = " << m_pControl;
|
|
dc << "\nm_strPath = \"" << m_strPath;
|
|
dc << "\"\n";
|
|
}
|
|
#endif //_DEBUG
|
|
|
|
#endif // !_MAC
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CCachedDataPathProperty implementation
|
|
|
|
#ifndef _MAC
|
|
|
|
static inline
|
|
DWORD AfxTransferFileContent(CFile* pFrom, CFile* pTo, DWORD dwAmount)
|
|
{
|
|
BYTE buff[1024];
|
|
DWORD dwRead = 0;
|
|
DWORD dwActual = 1; // bogus value to enter the loop
|
|
while ((dwAmount > 0) && (dwActual > 0))
|
|
{
|
|
dwActual = pFrom->Read(buff, min(dwAmount, 1024));
|
|
pTo->Write(buff, dwActual);
|
|
|
|
dwAmount -= dwActual;
|
|
dwRead += dwActual;
|
|
}
|
|
return dwRead;
|
|
}
|
|
|
|
void CCachedDataPathProperty::OnDataAvailable(DWORD dwSize, DWORD bscfFlag)
|
|
{
|
|
UNUSED_ALWAYS(bscfFlag);
|
|
TRY
|
|
{
|
|
// Cache the data in our mem file.
|
|
DWORD dwPos = m_Cache.GetPosition();
|
|
|
|
m_Cache.SeekToEnd();
|
|
DWORD dwEndPos = m_Cache.GetPosition();
|
|
if (dwSize > dwEndPos)
|
|
{
|
|
DWORD dwReadAmount = dwSize - dwEndPos;
|
|
VERIFY(dwReadAmount == AfxTransferFileContent(this, &m_Cache, dwReadAmount));
|
|
}
|
|
|
|
m_Cache.Seek(dwPos, CFile::begin);
|
|
}
|
|
CATCH_ALL(e)
|
|
{
|
|
DELETE_EXCEPTION(e);
|
|
}
|
|
END_CATCH_ALL
|
|
}
|
|
|
|
void CCachedDataPathProperty::Close()
|
|
{
|
|
m_Cache.SetLength(0);
|
|
CDataPathProperty::Close();
|
|
}
|
|
|
|
void CCachedDataPathProperty::ResetData()
|
|
{
|
|
m_Cache.SetLength(0);
|
|
}
|
|
#ifdef _DEBUG
|
|
void CCachedDataPathProperty::AssertValid() const
|
|
{
|
|
CDataPathProperty::AssertValid();
|
|
m_Cache.AssertValid();
|
|
}
|
|
|
|
void CCachedDataPathProperty::Dump(CDumpContext& dc) const
|
|
{
|
|
CDataPathProperty::Dump(dc);
|
|
|
|
m_Cache.Dump(dc);
|
|
}
|
|
#endif //_DEBUG
|
|
|
|
#endif // !_MAC
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Force any extra compiler-generated code into AFX_INIT_SEG
|
|
|
|
#ifdef AFX_INIT_SEG
|
|
#pragma code_seg(AFX_INIT_SEG)
|
|
#endif
|
|
|
|
#ifndef _MAC
|
|
IMPLEMENT_DYNAMIC(CDataPathProperty, CAsyncMonikerFile)
|
|
IMPLEMENT_DYNAMIC(CCachedDataPathProperty, CDataPathProperty)
|
|
#endif //!_MAC
|