📄 beeper.cpp
字号:
* can be called for a specific locale. We support English,
* German, and neutral (defaults to English) locales. Anything
* else is an error.
*
* After this switch statement, ppITI will either be NULL or
* a valid pointer in it after. If NULL, we know we need to
* load type information, retrieve the ITypeInfo we want, and
* then store it in *ppITI.
*/
switch (PRIMARYLANGID(lcid))
{
case LANG_NEUTRAL:
case LANG_ENGLISH:
ppITI=&m_pITINeutral;
break;
case LANG_GERMAN:
ppITI=&m_pITIGerman;
break;
default:
return ResultFromScode(DISP_E_UNKNOWNLCID);
}
//Load a type lib if we don't have the information already.
if (NULL==*ppITI)
{
/*
* The type libraries are registered under 0 (neutral),
* 7 (German), and 9 (English) with no specific sub-
* language, which would make them 407 or 409 and such.
* If you are sensitive to sub-languages, then use the
* full LCID instead of just the LANGID as done here.
*/
hr=LoadRegTypeLib(LIBID_BeeperTypeLibrary, 1, 0
, PRIMARYLANGID(lcid), &pITypeLib);
/*
* If LoadRegTypeLib fails, try loading directly with
* LoadTypeLib, which will register the library for us.
* Note that there's no default case here because the
* prior switch will have filtered lcid already.
*
* NOTE: You should prepend your DIR registry key to the
* .TLB name so you don't depend on it being it the PATH.
* This sample will be updated later to reflect this.
*/
if (FAILED(hr))
{
switch (PRIMARYLANGID(lcid))
{
case LANG_NEUTRAL:
case LANG_ENGLISH:
hr=LoadTypeLib(OLETEXT("BEEP0000.TLB"), &pITypeLib);
break;
case LANG_GERMAN:
hr=LoadTypeLib(OLETEXT("BEEP0007.TLB"), &pITypeLib);
break;
}
}
if (FAILED(hr))
return hr;
//Got the type lib, get type info for the interface we want
hr=pITypeLib->GetTypeInfoOfGuid(DIID_DIBeeper, ppITI);
pITypeLib->Release();
if (FAILED(hr))
return hr;
}
/*
* Note: the type library is still loaded since we have
* an ITypeInfo from it.
*/
(*ppITI)->AddRef();
*ppITypeInfo=*ppITI;
return NOERROR;
}
/*
* CImpIDispatch::GetIDsOfNames
*
* Purpose:
* Converts text names into DISPIDs to pass to Invoke
*
* Parameters:
* riid REFIID reserved. Must be IID_NULL.
* rgszNames OLECHAR ** pointing to the array of names to be
* mapped.
* cNames UINT number of names to be mapped.
* lcid LCID of the locale.
* rgDispID DISPID * caller allocated array containing IDs
* corresponging to those names in rgszNames.
*
* Return Value:
* HRESULT NOERROR or a general error code.
*/
STDMETHODIMP CImpIDispatch::GetIDsOfNames(REFIID riid
, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgDispID)
{
HRESULT hr;
ITypeInfo *pTI;
if (IID_NULL!=riid)
return ResultFromScode(DISP_E_UNKNOWNINTERFACE);
//Get the right ITypeInfo for lcid.
hr=GetTypeInfo(0, lcid, &pTI);
if (SUCCEEDED(hr))
{
hr=DispGetIDsOfNames(pTI, rgszNames, cNames, rgDispID);
pTI->Release();
}
return hr;
}
/*
* CImpIDispatch::Invoke
*
* Purpose:
* Calls a method in the dispatch interface or manipulates a
* property.
*
* Parameters:
* dispID DISPID of the method or property of interest.
* riid REFIID reserved, must be IID_NULL.
* lcid LCID of the locale.
* wFlags USHORT describing the context of the invocation.
* pDispParams DISPPARAMS * to the array of arguments.
* pVarResult VARIANT * in which to store the result. Is
* NULL if the caller is not interested.
* pExcepInfo EXCEPINFO * to exception information.
* puArgErr UINT * in which to store the index of an
* invalid parameter if DISP_E_TYPEMISMATCH
* is returned.
*
* Return Value:
* HRESULT NOERROR or a general error code.
*/
STDMETHODIMP CImpIDispatch::Invoke(DISPID dispID, REFIID riid
, LCID lcid, unsigned short wFlags, DISPPARAMS *pDispParams
, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
HRESULT hr;
ITypeInfo *pTI;
//riid is supposed to be IID_NULL always
if (IID_NULL!=riid)
return ResultFromScode(DISP_E_UNKNOWNINTERFACE);
//Get the ITypeInfo for lcid
hr=GetTypeInfo(0, lcid, &pTI);
if (FAILED(hr))
return hr;
/*
* Clear exceptions. Note that this mechanism only works
* for a single-thread, which is fine for the initial 32-bit
* release of OLE but not a long-term solution. See Beeper3
* for a way of handling multi-thread exceptions.
*/
m_wException=EXCEPTION_NONE;
//This is exactly what DispInvoke does--so skip the overhead.
hr=pTI->Invoke((IBeeper *)m_pObj, dispID, wFlags
, pDispParams, pVarResult, pExcepInfo, puArgErr);
/*
* Check if an exception was raised. Again, this is not
* thread-safe.
*/
if (EXCEPTION_NONE!=m_wException)
{
pExcepInfo->scode
=(SCODE)MAKELONG(m_wException, PRIMARYLANGID(lcid));
FillException(pExcepInfo);
hr=ResultFromScode(DISP_E_EXCEPTION);
}
pTI->Release();
return hr;
}
/*
* CImpIDispatch::Exception
*
* Purpose:
* Raises an exception for CImpIDispatch::Invoke from within
* ITypeInfo::Invoke. This simply sets the m_wException variable
* to the exception code. Invoke will pick this up and fill in
* the exception structure as necessary.
*
* Parameters:
* wException WORD exception code.
*/
void CImpIDispatch::Exception(WORD wException)
{
/*
* Note: calls to this function will be wrapped in a critical
* section on Win32 because this is always called from within
* DispInvoke which we wrapped above in Invoke.
*/
m_wException=wException;
return;
}
/*
* FillException
*
* Purpose:
* Callback function pointed to in IDispatch::Invoke that fills
* an EXCEPINFO structure based on the code stored inside
* Invoke. This is a nice mechanism to keep all the management
* of error code strings and help IDs centralized in one place,
* even across many different automation objects within the same
* application. It also keeps Invoke cleaner.
*
* Parameters:
* pExcepInfo EXCEPINFO * to fill.
*
* Return Value:
* HRESULT NOERROR if successful, error code otherwise.
*/
HRESULT STDAPICALLTYPE FillException(EXCEPINFO *pExcepInfo)
{
SCODE scode;
LANGID langID;
USHORT wCode;
HRESULT hr;
LPTSTR psz;
LPOLESTR pszHelp;
UINT idsSource;
UINT idsException;
if (NULL==pExcepInfo)
return ResultFromScode(E_INVALIDARG);
scode=pExcepInfo->scode;
langID=HIWORD(scode);
wCode=LOWORD(scode);
//Allocate BSTRs for source and description strings
psz=(LPTSTR)malloc(1024*sizeof(TCHAR));
if (NULL==psz)
return ResultFromScode(E_OUTOFMEMORY);
hr=NOERROR;
switch (wCode)
{
case EXCEPTION_INVALIDSOUND:
//Fill in unused information, macro in inole.h
INITEXCEPINFO(*pExcepInfo);
pExcepInfo->wCode=wCode;
pExcepInfo->dwHelpContext=HID_SOUND_PROPERTY_LIMITATIONS;
//We registered a HELPDIR so we don't include paths
pszHelp=OLETEXT("beep0000.hlp");
idsSource=IDS_0_EXCEPTIONSOURCE;
idsException=IDS_0_EXCEPTIONINVALIDSOUND;
//Get the localized source and exception strings
switch (langID)
{
case LANG_GERMAN:
idsSource=IDS_7_EXCEPTIONSOURCE;
idsException=IDS_7_EXCEPTIONINVALIDSOUND;
pszHelp=OLETEXT("beep0007.hlp");
break;
case LANG_ENGLISH:
case LANG_NEUTRAL:
default:
break;
}
break;
default:
hr=ResultFromScode(E_FAIL);
}
if (SUCCEEDED(hr))
{
pExcepInfo->bstrHelpFile=SysAllocString(pszHelp);
#ifdef WIN32ANSI
OLECHAR szTemp[256];
LoadString(g_hInst, idsSource, psz, 256);
MultiByteToWideChar(CP_ACP, 0, psz, -1, szTemp, 256);
pExcepInfo->bstrSource=SysAllocString(szTemp);
LoadString(g_hInst, idsException, psz, 256);
MultiByteToWideChar(CP_ACP, 0, psz, -1, szTemp, 256);
pExcepInfo->bstrDescription=SysAllocString(szTemp);
#else
LoadString(g_hInst, idsSource, psz, 1024);
pExcepInfo->bstrSource=SysAllocString(psz);
LoadString(g_hInst, idsException, psz, 1024);
pExcepInfo->bstrDescription=SysAllocString(psz);
#endif
}
free(psz);
return hr;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -