autocli2.cpp
字号:
, VARIANT *pva, EXCEPINFO *pExInfo, UINT *puErr)
{
HRESULT hr;
LPTSTR pszMsg=NULL;
LPTSTR pszFmt=NULL;
UINT uRet;
UINT uStyle;
TCHAR szSource[80];
if (NULL==m_pIDispatch)
return ResultFromScode(E_POINTER);
hr=m_pIDispatch->Invoke(dispID, IID_NULL, m_lcid, wFlags
, pdp, pva, pExInfo, puErr);
if (DISP_E_EXCEPTION!=GetScode(hr))
return hr;
//If we're given a deferred filling function, fill now.
if (NULL!=pExInfo->pfnDeferredFillIn)
(*pExInfo->pfnDeferredFillIn)(pExInfo);
/*
* To handle the exception, display a message box with the
* controller's name in the caption and a message:
*
* "Error <code> in <source>: <description>"
*
* where <error> is the exception code in pExInfo->wCode or
* pExInfo->scode, <source> is the value of the ProdID
* in pExInfo->bstrSource and <description> is in
* pExInfo->bstrDescription.
*
* For simplicity, we assume that if description is set, so is
* source.
*
* To be complete, if pExInfo->bstrHelpFile is non-NULL,
* display a Help button. If Help is pressed, launch WinHelp
* with that filename and pExInfo->dwHelpContext.
*/
//Go get the real source name from the ProgID
lstrcpy(szSource, TEXT("Unknown"));
if (NULL!=pExInfo->bstrSource)
{
LONG lRet;
//If this doesn't work, we'll have "Unknown" anyway
#ifdef WIN32ANSI
char szTemp[80];
WideCharToMultiByte(CP_ACP, 0, pExInfo->bstrSource, -1
, szTemp, 80, NULL, NULL);
RegQueryValue(HKEY_CLASSES_ROOT, szTemp, szSource, &lRet);
#else
RegQueryValue(HKEY_CLASSES_ROOT, pExInfo->bstrSource
, szSource, &lRet);
#endif
SysFreeString(pExInfo->bstrSource);
}
if (NULL!=pExInfo->bstrDescription)
{
pszFmt=(LPTSTR)malloc(CCHSTRINGMAX*sizeof(TCHAR));
#ifdef WIN32ANSI
UINT cch;
char *pszDesc;
cch=wcslen(pExInfo->bstrDescription);
pszDesc=(LPSTR)malloc(cch);
WideCharToMultiByte(CP_ACP, 0, pExInfo->bstrDescription, -1
, pszDesc, cch, NULL, NULL);
pszMsg=(LPTSTR)malloc(CCHSTRINGMAX+lstrlen(szSource)+cch);
#else
pszMsg=(LPTSTR)malloc((CCHSTRINGMAX+lstrlen(szSource)
+lstrlen(pExInfo->bstrDescription))*sizeof(TCHAR));
#endif
if (0==pExInfo->wCode)
{
//Formatting for SCODE errors
LoadString(m_hInst, IDS_MESSAGEEXCEPTIONSCODE, pszFmt
, CCHSTRINGMAX);
wsprintf(pszMsg, pszFmt, (long)pExInfo->scode
, (LPTSTR)szSource
#ifdef WIN32ANSI
, pszDesc);
#else
, (LPTSTR)pExInfo->bstrDescription);
#endif
}
else
{
//Formatting for wCode errors
LoadString(m_hInst, IDS_MESSAGEEXCEPTION, pszFmt
, CCHSTRINGMAX);
wsprintf(pszMsg, pszFmt, (UINT)pExInfo->wCode
, (LPTSTR)szSource
#ifdef WIN32ANSI
, pszDesc);
#else
, (LPTSTR)pExInfo->bstrDescription);
#endif
}
free(pszFmt);
}
else
{
pszMsg=(LPTSTR)malloc(CCHSTRINGMAX*sizeof(TCHAR));
LoadString(m_hInst, IDS_MESSAGEUNKNOWNEXCEPTION, pszMsg
, CCHSTRINGMAX);
}
/*
* In Windows 95 there is an MB_HELP style that we use in the
* exception message if pExInfo->bstrHelpFile is non-NULL. For
* Windows NT 3.5 and Windows 3.1x, we'll just use a Cancel
* button to demonstrate since making a Help button is too much
* effort for this sample (requires a custom dialog box and code
* to resize the dialog based on the length of the description
* string which MessageBox does automatically...)
*/
uStyle=MB_OK | MB_ICONEXCLAMATION;
#ifdef MB_HELP
uStyle |=(NULL!=pExInfo->bstrHelpFile) ? MB_HELP : 0;
#else
uStyle |=(NULL!=pExInfo->bstrHelpFile) ? MB_OKCANCEL : 0;
#endif
uRet=Message(pszMsg, uStyle);
if (NULL!=pszMsg)
free(pszMsg);
#ifdef MB_HELP
if (IDHELP==uRet)
#else
if (IDCANCEL==uRet)
#endif
{
TCHAR szHelp[512];
/*
* If we read a HELPDIR, prepend it to the file. Otherwise
* just use the string we got since that's all we have.
*/
if ((TCHAR)0!=m_szHelpDir[0])
{
#ifdef WIN32ANSI
char szTemp[256];
WideCharToMultiByte(CP_ACP, 0, pExInfo->bstrHelpFile
, -1, szTemp, 256, NULL, NULL);
wsprintf(szHelp, TEXT("%s\\%s"), m_szHelpDir, szTemp);
#else
wsprintf(szHelp, TEXT("%s\\%s"), m_szHelpDir
, pExInfo->bstrHelpFile);
#endif
}
else
#ifdef WIN32ANSI
WideCharToMultiByte(CP_ACP, 0, pExInfo->bstrHelpFile
, -1, szHelp, 512, NULL, NULL);
#else
lstrcpy(szHelp, pExInfo->bstrHelpFile);
#endif
WinHelp(NULL, szHelp, HELP_CONTEXT, pExInfo->dwHelpContext);
}
//We're responsible for cleaning up the strings.
SysFreeString(pExInfo->bstrDescription);
SysFreeString(pExInfo->bstrHelpFile);
return ResultFromScode(DISP_E_EXCEPTION);
}
/*
* CApp::Message (overloaded)
*
* Purpose:
* Scribbles a message onto the client area of the window
* or displays the message in a message box if a message
* box style is given.
*
* Parameters:
* pszMsg LPTSTR to the message string.
* uStyle (message box only) UINT style bits
*
* Return Value:
* UINT Return value of MessageBox (MessageBox version
* only)
*/
void CApp::Message(LPTSTR pszMsg)
{
HDC hDC;
RECT rc;
hDC=GetDC(m_hWnd);
GetClientRect(m_hWnd, &rc);
SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
/*
* We'll just be sloppy and clear the whole window as
* well as write the string with one ExtTextOut call.
* No word wrapping here...
*/
ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rc, pszMsg
, lstrlen(pszMsg), NULL);
ReleaseDC(m_hWnd, hDC);
return;
}
UINT CApp::Message(LPTSTR pszMsg, UINT uStyle)
{
return MessageBox(m_hWnd, pszMsg, TEXT("Automation Client")
, uStyle);
}
/*
* HelpDirFromCLSID
*
* Purpose:
* Given a CLSID, looks up the TypeLib entry in the registry then
* extracts the HELPDIR entry for that type information, storing
* the path in pszPath.
*
* Parameters:
* clsID CLSID of the object we're looking up.
* pszPath LPTSTR buffer in which to store the directory.
*
* Return Value:
* None
*/
void HelpDirFromCLSID(CLSID clsID, LPTSTR pszPath)
{
TCHAR szCLSID[80];
TCHAR szKey[512];
UINT cch;
long lRet;
if (NULL==pszPath)
return;
*pszPath=0;
cch=sizeof(szCLSID)/sizeof(TCHAR);
StringFromGUID2(clsID, szCLSID, cch);
wsprintf(szKey, TEXT("CLSID\\%s\\TypeLib"), szCLSID);
//Get LIBID from under CLSID
if (ERROR_SUCCESS==RegQueryValue(HKEY_CLASSES_ROOT, szKey
, szCLSID, &lRet))
{
//Get HELPDIR from under TypeLib
wsprintf(szKey, TEXT("TypeLib\\%s\\HELPDIR"), szCLSID);
RegQueryValue(HKEY_CLASSES_ROOT, szKey, pszPath, &lRet);
}
return;
}
/*
* CApp::ShowProperties
*
* Purpose:
* Invokes the standard property page frame using the
* property pages specified by the object we maintain
* (only a single one).
*/
void CApp::ShowProperties(void)
{
ISpecifyPropertyPages *pISPP;
CAUUID caGUID;
HRESULT hr;
if (FAILED(m_pIDispatch->QueryInterface
(IID_ISpecifyPropertyPages, (void **)&pISPP)))
{
Message(TEXT("Object has no property pages"));
return;
}
hr=pISPP->GetPages(&caGUID);
pISPP->Release();
if (FAILED(hr))
{
Message(TEXT("Failed to retrieve property page GUIDs"));
return;
}
hr=OleCreatePropertyFrame(m_hWnd, 10, 10, OLETEXT("Beeper")
, 1, (IUnknown **)&m_pIDispatch, caGUID.cElems
, caGUID.pElems, m_lcid, 0L, NULL);
if (FAILED(hr))
Message(TEXT("OleCreatePropertyFrame failed"));
//Free the GUIDs
CoTaskMemFree((void *)caGUID.pElems);
return;
}
/***
*** IPropertyNotifySink Object
***/
/*
* CPropertyNotifySink::CPropertyNotifySink
* CPropertyNotifySink::~CPropertyNotifySink
*
* Constructor Parameters:
* pApp PCApp of the application.
*/
CPropertyNotifySink::CPropertyNotifySink(PCApp pApp)
{
m_cRef=0;
m_pApp=pApp;
return;
}
CPropertyNotifySink::~CPropertyNotifySink(void)
{
return;
}
/*
* CPropertyNotifySink::QueryInterface
* CPropertyNotifySink::AddRef
* CPropertyNotifySink::Release
*/
STDMETHODIMP CPropertyNotifySink::QueryInterface(REFIID riid
, LPVOID *ppv)
{
*ppv=NULL;
if (IID_IUnknown==riid || IID_IPropertyNotifySink==riid)
*ppv=this;
if (NULL!=*ppv)
{
((LPUNKNOWN)*ppv)->AddRef();
return NOERROR;
}
return ResultFromScode(E_NOINTERFACE);
}
STDMETHODIMP_(ULONG) CPropertyNotifySink::AddRef(void)
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG) CPropertyNotifySink::Release(void)
{
if (0!=--m_cRef)
return m_cRef;
delete this;
return 0;
}
/*
* CPropertyNotifySink::OnChanged
*
* Purpose:
* Notifies this sink that the property identified with dispID
* has changed in whatever object this sink is connected to.
*
* Parameters:
* dispID DISPID of the property that changed,
* which can be DISPID_UNKNOWN for unspecified
* changes to multiple properties.
*
* Return Value:
* HRESULT NOERROR always.
*/
STDMETHODIMP CPropertyNotifySink::OnChanged(DISPID dispID)
{
TCHAR szTemp[200];
wsprintf(szTemp
, TEXT("OnChanged notification received for DISPID=%lu")
, dispID);
m_pApp->Message(szTemp);
return NOERROR;
}
/*
* CPropertyNotifySink::OnRequestEdit
*
* Purpose:
* Notifies this sink that the property identified with dispID
* is about to change and that the sink can prevent the change
* if desired. This can be used to enforce read-only states or
* to save prior states before the change occurs.
*
* Parameters:
* dispID DISPID of the property that is changing
* which can be DISPID_UNKNOWN for multiple
* properties.
*
* Return Value:
* HRESULT NOERROR if the property can change, S_FALSE
* if it cannot change, error code otherwise.
*/
STDMETHODIMP CPropertyNotifySink::OnRequestEdit(DISPID dispID)
{
TCHAR szTemp[200];
wsprintf(szTemp
, TEXT("OnRequestEdit received for DISPID=%lu"), dispID);
m_pApp->Message(szTemp);
return ResultFromScode(m_pApp->m_fReadOnly ? S_FALSE : S_OK);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -