📄 beeper.cpp
字号:
WideCharToMultiByte(CP_ACP, 0, rgszNames[0], -1
, szTemp, 80, NULL, NULL);
if (0==lstrcmpi(psz, szTemp))
#else
if (0==lstrcmpi(psz, rgszNames[0]))
#endif
{
//Found a match, return the DISPID
rgDispID[0]=i;
hr=NOERROR;
break;
}
}
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;
//riid is supposed to be IID_NULL always
if (IID_NULL!=riid)
return ResultFromScode(DISP_E_UNKNOWNINTERFACE);
/*
* There is nothing locale-sensitive in any of our properties
* or methods. Some automation objects may have currency,
* date/time, or string values in properties or methods which
* would be sensitive to lcid; be sure the handle them properly.
*/
/*
* Process the invoked member or property. For members,
* call whatever functions are necessary to carry out the
* action. For properties, either return the value you have
* or change it according to wFlags.
*
* This object supports one property and one method:
* ID 0 "Sound" property, a long that must be one of
* MB_OK, MB_ICONHAND, MB_ICONQUESTION,
* MB_ICONEXCLAMATION, and MB_ICONASTERISK.
* ID 1 "Beep" method, no parameters, return value of type
* long which is the sound that was played.
*
* Note that the IDs are assigned in the implementation of
* IDispatch::GetIDsOfNames.
*/
switch (dispID)
{
case PROPERTY_SOUND:
/*
* Some controllers might not be able to differentiate
* between a property get and a function call, so we
* have to handle both as a property get here.
*/
if (DISPATCH_PROPERTYGET & wFlags
|| DISPATCH_METHOD & wFlags)
{
//Make sure we have a place for the result
if (NULL==pVarResult)
return ResultFromScode(E_INVALIDARG);
VariantInit(pVarResult);
V_VT(pVarResult)=VT_I4;
V_I4(pVarResult)=m_pObj->m_lSound;
return NOERROR;
}
else
{
//DISPATCH_PROPERTYPUT
long lSound;
int c;
VARIANT vt;
//Validate parameter count
if (1!=pDispParams->cArgs)
return ResultFromScode(DISP_E_BADPARAMCOUNT);
//Check that we have a named DISPID_PROPERTYPUT
c=pDispParams->cNamedArgs;
if (1!=c || (1==c && DISPID_PROPERTYPUT
!=pDispParams->rgdispidNamedArgs[0]))
return ResultFromScode(DISP_E_PARAMNOTOPTIONAL);
/*
* Try to coerce the new property value into a
* type VT_I4. VariantChangeType will do this for
* us and return an appropriate error code if the
* type cannot be coerced. On error we store 0
* (first parameter) into puArgErr.
*
* We could also use DispGetParam here to do the
* same thing:
* DispGetParam(pDispParams, 0, VT_I4
* , &vtNew, puArgErr);
*/
VariantInit(&vt);
hr=VariantChangeType(&vt, &pDispParams->rgvarg[0]
, 0, VT_I4);
if (FAILED(hr))
{
if (NULL!=puArgErr)
*puArgErr=0;
return hr;
}
//With the right type, now check the right value
lSound=vt.lVal;
if (MB_OK!=lSound && MB_ICONEXCLAMATION!=lSound
&& MB_ICONQUESTION!=lSound && MB_ICONHAND!=lSound
&& MB_ICONASTERISK!=lSound)
{
if (NULL==pExcepInfo)
return ResultFromScode(E_INVALIDARG);
/*
* This is the right place for an exception--
* the best we can tell the caller with a
* return value is something like E_INVALIDARG.
* But that doesn't at all indiate the problem.
* So we use EXCEPTION_INVALIDSOUND and the
* FillException callback to fill the EXCEPINFO.
*
* Note: DispTest and Visual Basic 3 don't
* support deferred filling of the EXCEPINFO
* structure; Visual Basic 4 does. Even if you
* don't use deferred filling, a separate
* function is still useful as you can just call
* it here to fill the structure immediately.
*
* Deferred fill-in code would appear:
*
* INITEXCEPINFO(*pExcepInfo);
* pExcepInfo->scode
* =(SCODE)MAKELONG(EXCEPTION_INVALIDSOUND
* , PRIMARYLANGID(lcid));
* pExcepInfo->pfnDeferredFillIn=FillException;
*/
/*
* So we can make a localized exception, we'll
* store the language ID and our exception code
* into the scode field; in FillException we move
* the code into wCode and clear scode. Otherwise
* there's no way to tell FillException about
* the locale.
*/
pExcepInfo->scode
=(SCODE)MAKELONG(EXCEPTION_INVALIDSOUND
, PRIMARYLANGID(lcid));
FillException(pExcepInfo);
return ResultFromScode(DISP_E_EXCEPTION);
}
//Everything checks out: save the new value
m_pObj->m_lSound=lSound;
}
break;
case METHOD_BEEP:
if (!(DISPATCH_METHOD & wFlags))
return ResultFromScode(DISP_E_MEMBERNOTFOUND);
if (0!=pDispParams->cArgs)
return ResultFromScode(DISP_E_BADPARAMCOUNT);
MessageBeep((UINT)m_pObj->m_lSound);
//The result of this method is the sound we played
if (NULL!=pVarResult)
{
VariantInit(pVarResult);
V_VT(pVarResult)=VT_I4;
V_I4(pVarResult)=m_pObj->m_lSound;
}
break;
default:
return ResultFromScode(DISP_E_MEMBERNOTFOUND);
}
return NOERROR;
}
/*
* 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);
/*
* Parts of our implementation that raise exceptions put the
* WORD exception code in the loword of scode and the LANGID
* in the hiword.
*/
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;
/*
* DispTest and Visual Basic 3 ignore the help file and
* context ID. A complete controller such as Visual
* Basic 4 checks if these fields are set, and if so,
* displays a Help button in a message box. If Help
* is pressed, the controller calls WinHelp with this
* filename and context ID for complete integration.
*
* The sources for beeper.hlp are in
* \inole\chap14\beephelp along with the actual help
* file. For this sample I assume it's on C drive.
* Normally you'll want to read your own HELPDIR
* registry entry from under TypeLib and prepend that
* to the name of the help file, but since this sample
* doesn't have a type library, that entry doesn't
* exist so I just hard-code it.
*/
pExcepInfo->dwHelpContext=HID_SOUND_PROPERTY_LIMITATIONS;
//Set defaults
pszHelp=OLETEXT("c:\\inole\\chap14\\beephelp\\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("c:\\inole\\chap14\\beephelp\\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 + -