📄 atlcontrolwin.cpp
字号:
// if there is an old brush
if(hOldBrush)
{
// get the DC
HDC hDC = this->GetDC();
// select the old brush back
::SelectObject(hDC, hOldBrush);
// release the DC
this->ReleaseDC(hDC);
}
// if we created a brush
if(hBrush)
// destroy the brush we created
::DeleteObject(hBrush);
return TRUE;
}
static FONTDESC _fdDefault =
{
sizeof(FONTDESC),
L"MS Sans Serif",
FONTSIZE(8),
FW_NORMAL,
DEFAULT_CHARSET,
FALSE,
FALSE,
FALSE
};
void CATLControlWin::LoadFont(void)
{
// if there isn't a font object
if(!m_pFont)
// get the font from the container
this->GetAmbientFont(&m_pFont);
// if there still isn't a font object
if(!m_pFont)
// create a default font object
::OleCreateFontIndirect(&_fdDefault, IID_IFont, (void **) &m_pFont);
}
void CATLControlWin::GetTextExtent(HDC hDC, LPCTSTR lpctstrString, int & cx, int & cy)
{
// if we haven't gotten the dimensions yet
if(!bRetrievedDimensions)
{
// get all of the widths for all of the chars
::GetCharWidth(hDC, 0, 255, &iCharWidthArray[0]);
// get the spacing between the chars
iCharacterSpacing = ::GetTextCharacterExtra(hDC);
// make sure that this only executes once
bRetrievedDimensions = TRUE;
// get the metrics of this DC
TEXTMETRIC tmMetrics;
::GetTextMetrics(hDC, &tmMetrics);
// get the height
iCharacterHeight = tmMetrics.tmHeight;
}
// return the height
cy = iCharacterHeight;
// set the initial value to 0
int iTextWidth = 0;
// get the number of characters in our string
long lTextLength = lstrlen(lpctstrString);
// if we have a character
if(lTextLength)
{
long lEndCharPos = lTextLength - 1;
// add up the widths of the characters and the spacing
for(long lCount = 0; lCount <= lEndCharPos; lCount++)
iTextWidth += (iCharWidthArray[(BYTE)(lpctstrString[lCount])] + iCharacterSpacing);
}
// return the width
cx = iTextWidth;
}
STDMETHODIMP CATLControlWin::get_ReadyState(long * pVal)
{
// set the return value to the value of the member variable
*pVal = m_lReadyState;
return S_OK;
}
STDMETHODIMP CATLControlWin::get_TextDataPath(BSTR * pVal)
{
// return a copy of the member variable
*pVal = m_bstrTextDataPath.Copy();
return S_OK;
}
STDMETHODIMP CATLControlWin::put_TextDataPath(BSTR newVal)
{
HRESULT hResult = S_OK;
// copy the new string to the member variable
m_bstrTextDataPath = newVal;
// start the asynchronous download of the data
CBindStatusCallback<CATLControlWin>::Download(this, OnData, m_bstrTextDataPath, m_spClientSite, FALSE);
// let the container know that the property has changed
this->SetDirty(TRUE);
// this->SetModifiedFlag(); <== MFC version
return hResult;
}
//OnData will be used as a callback functin by the CBindStatusCallback object.
//OnData will be called periodically with data from the asynchronous transfer
void CATLControlWin::OnData(CBindStatusCallback<CATLControlWin>* pbsc, BYTE* pBytes, DWORD dwSize)
{
// if we have not read any data yet
if(pbsc->m_dwTotalRead == 0)
{
// clear the buffer
m_bstrText = _T("");
// set the ready state of the control
m_lReadyState = READYSTATE_LOADING;
// let the container know that the property has changed
this->Fire_ReadyStateChange();
}
// add the data to our buffer
m_bstrText.Append((LPCSTR) pBytes);
long lRetVal;
VARIANT varAlignment;
// initialize the variant
::VariantInit(&varAlignment);
// defer to the CaptionMethod implementation
this->CaptionMethod(m_bstrText, varAlignment, &lRetVal);
// if the function returned success
if(TRUE == lRetVal)
// let the control know that the property has changed
this->SetDirty(TRUE);
// this->SetModifiedFlag(); <== MFC version
// if there is nothing left
if(pbsc->m_dwAvailableToRead == 0)
{
// set the ready state of the control
m_lReadyState = READYSTATE_COMPLETE;
// let the container know that the property has changed
this->Fire_ReadyStateChange();
}
}
STDMETHODIMP CATLControlWin::MapPropertyToPage(DISPID dispID, CLSID *pClsid)
{
// if this is the dispid property
if(dispID == dispidAlignment)
// defer to the property enumeration and not the property page
return E_NOTIMPL;
else
// defer to the base class implementation
return IPerPropertyBrowsingImpl<CATLControlWin>::MapPropertyToPage(dispID, pClsid);
}
STDMETHODIMP CATLControlWin::GetPredefinedStrings(DISPID dispid, CALPOLESTR * lpcaStringsOut, CADWORD * lpcaCookiesOut)
{
USES_CONVERSION;
HRESULT hResult = S_FALSE;
// we should have gotten two pointers if we didn't
if((lpcaStringsOut == NULL) || (lpcaCookiesOut == NULL))
// we are out of here
return E_POINTER;
// if this is the property that we are looking for
if(dispid == dispidAlignment)
{
ULONG ulElems = 3;
// allocate the memory for our string array
lpcaStringsOut->pElems = (LPOLESTR *) ::CoTaskMemAlloc(sizeof(LPOLESTR) * ulElems);
// if we couldn't allocate the memory
if(lpcaStringsOut->pElems == NULL)
// were out of here
return E_OUTOFMEMORY;
// allocate the memory for our cookie array
lpcaCookiesOut->pElems = (DWORD*) ::CoTaskMemAlloc(sizeof(DWORD*) * ulElems);
// if we couldn't allocate the memory
if (lpcaCookiesOut->pElems == NULL)
{
// free the string array
::CoTaskMemFree(lpcaStringsOut->pElems);
// exit the function
return E_OUTOFMEMORY;
}
// store the number of elements in each array
lpcaStringsOut->cElems = ulElems;
lpcaCookiesOut->cElems = ulElems;
// allocate the strings
lpcaStringsOut->pElems[0] = ATLA2WHELPER((LPWSTR)::CoTaskMemAlloc((lstrlen(EALIGN_LEFT_TEXT) + 1) * 2), EALIGN_LEFT_TEXT, lstrlen(EALIGN_LEFT_TEXT) + 1);
lpcaStringsOut->pElems[1] = ATLA2WHELPER((LPWSTR)::CoTaskMemAlloc((lstrlen(EALIGN_CENTER_TEXT) + 1) * 2), EALIGN_CENTER_TEXT, lstrlen(EALIGN_CENTER_TEXT) + 1);
lpcaStringsOut->pElems[2] = ATLA2WHELPER((LPWSTR)::CoTaskMemAlloc((lstrlen(EALIGN_RIGHT_TEXT) + 1) * 2), EALIGN_RIGHT_TEXT, lstrlen(EALIGN_RIGHT_TEXT) + 1);
// assign the cookie value
lpcaCookiesOut->pElems[0] = EALIGN_LEFT;
lpcaCookiesOut->pElems[1] = EALIGN_CENTER;
lpcaCookiesOut->pElems[2] = EALIGN_RIGHT;
hResult = S_OK;
}
return hResult;
}
STDMETHODIMP CATLControlWin::GetPredefinedValue(DISPID dispid, DWORD dwCookie, VARIANT* lpvarOut)
{
BOOL bResult = FALSE;
// which property is it
switch(dispid)
{
case dispidAlignment:
// clear the variant
::VariantInit(lpvarOut);
// set the type to a long
lpvarOut->vt = VT_I4;
// set the value to the value that was stored with the string
lpvarOut->lVal = dwCookie;
// set the return value
bResult = TRUE;
break;
}
return bResult;
}
STDMETHODIMP CATLControlWin::GetDisplayString(DISPID dispid, BSTR* lpbstr)
{
USES_CONVERSION;
HRESULT hResult = S_FALSE;
// which property is it
switch(dispid)
{
case dispidAlignment:
{
switch(m_lAlignment)
{
case EALIGN_LEFT:
*lpbstr = ::SysAllocString(T2OLE(EALIGN_LEFT_TEXT));
break;
case EALIGN_CENTER:
*lpbstr = ::SysAllocString(T2OLE(EALIGN_CENTER_TEXT));
break;
case EALIGN_RIGHT:
*lpbstr = ::SysAllocString(T2OLE(EALIGN_RIGHT_TEXT));
break;
}
// set the return value
hResult = S_OK;
}
break;
}
return hResult;
}
LRESULT CATLControlWin::OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled)
{
UINT nChar = wParam;
UINT nRepCnt = LOWORD(lParam);
UINT nFlags = HIWORD(lParam);
// find out if the shift key is being held down
short sShift = ::GetKeyState(VK_SHIFT);
// find out if the control key is being held down
short sControl = ::GetKeyState(VK_CONTROL);
switch(nChar)
{
// PASTE
case 0x56: // 'V'
case 0x76: // 'v'
// if the control key is being held down
if(sControl & 0x8000)
{
// get any text from the clipboard
this->GetDataFromClipboard();
// force the control to repaint itself
this->FireViewChange();
// this->InvalidateControl(); <== MFC Version
// we don't need to pass this key to the base implementation
bHandled = TRUE;
}
break;
// COPY or PASTE
case 0x43: // 'C'
case 0x63: // 'c'
case VK_INSERT:
// if the control key is being held down
if(sControl & 0x8000)
{
// copy the data to the clipboard
this->CopyDataToClipboard();
// we don't need to pass this key to the base implementation
bHandled = TRUE;
}
// if the shift key is being held down it is a PASTE
else if(sShift & 0x8000 && nChar == VK_INSERT)
{
// get any text from the clipboard
this->GetDataFromClipboard();
// force the control to repaint itself
this->FireViewChange();
// this->InvalidateControl(); <== MFC Version
// we don't need to pass this key to the base implementation
bHandled = TRUE;
}
break;
// CUT
case 0x58: // 'X'
case 0x78: // 'x'
case VK_DELETE:
// if this is a shift delete OR CTRL-X/x
if((nChar == VK_DELETE && (sShift & 0x8000)) ||
((nChar == 0x58 || nChar == 0x78) && (sControl & 0x8000)))
{
this->CopyDataToClipboard();
// clear the string since this is a CUT operation
delete [] m_lptstrCaption;
// NULL terminate the string reference
m_lptstrCaption = new TCHAR[1];
m_lptstrCaption[0] = '\0';
// fire the global change event
this->FireChange();
// force the control to repaint itself
this->FireViewChange();
// this->InvalidateControl(); <== MFC Version
// we don't need to pass this key to the base implementation
bHandled = TRUE;
}
break;
}
return TRUE;
}
void CATLControlWin::CopyDataToClipboard(void)
{
BOOL bHaveClipboard = TRUE;
// if we don't have an IDataObject on the clipboard?
if(::OleIsCurrentClipboard((IDataObject *) this) != S_OK)
// set the flag
bHaveClipboard = FALSE;
// put data in the storage
this->PrepareDataForTransfer();
// if we don't have the clipboard
if(!bHaveClipboard)
{
// clear the clipboard
::OleFlushClipboard();
// put the data on the clipboard
::OleSetClipboard(reinterpret_cast<IDataObject*>
(static_cast<IDataObjectImpl<CATLControlWin>*>(this)));
}
}
void CATLControlWin::PrepareDataForTransfer(void)
{
// get the length of the data to copy
long lLength = lstrlen(m_lptstrCaption) + 1;
// create a global memory object
HGLOBAL hGlobal = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, sizeof(TCHAR) * lLength);
// lock the memory down
LPTSTR lpTempBuffer = (LPTSTR) ::GlobalLock(hGlobal);
// copy the string
for(long lCount = 0; lCount < lLength - 1; lCount++)
lpTempBuffer[lCount] = m_lptstrCaption[lCount];
// null terminate the string
lpTempBuffer[lCount] = '\0';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -