📄 beeper.cpp
字号:
/*
* BEEPER.CPP
* Beeper Automation Object #1 Chapter 14
*
* Implementation of the CBeeper class which demonstrate a fully
* custom IDispatch implementation that only supports mapping of
* names to IDs through IDispatch::GetIDsOfNames.
*
* Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
*
* Kraig Brockschmidt, Microsoft
* Internet : kraigb@microsoft.com
* Compuserve: >INTERNET:kraigb@microsoft.com
*/
#include "beeper.h"
extern HINSTANCE g_hInst;
/*
* CBeeper::CBeeper
* CBeeper::~CBeeper
*
* Parameters (Constructor):
* pUnkOuter LPUNKNOWN of a controlling unknown.
* pfnDestroy PFNDESTROYED to call when an object
* is destroyed.
*/
CBeeper::CBeeper(LPUNKNOWN pUnkOuter, PFNDESTROYED pfnDestroy)
{
m_cRef=0;
m_pUnkOuter=pUnkOuter;
m_pfnDestroy=pfnDestroy;
m_lSound=0;
m_pImpIDispatch=NULL;
return;
}
CBeeper::~CBeeper(void)
{
if (NULL==m_pszScratch)
free(m_pszScratch);
DeleteInterfaceImp(m_pImpIDispatch);
return;
}
/*
* CBeeper::Init
*
* Purpose:
* Performs any intiailization of a CBeeper that's prone to failure
* that we also use internally before exposing the object outside.
*
* Parameters:
* None
*
* Return Value:
* BOOL TRUE if the function is successful,
* FALSE otherwise.
*/
BOOL CBeeper::Init(void)
{
LPUNKNOWN pIUnknown=this;
if (NULL!=m_pUnkOuter)
pIUnknown=m_pUnkOuter;
m_pImpIDispatch=new CImpIDispatch(this, pIUnknown);
if (NULL==m_pImpIDispatch)
return FALSE;
//Pre-allocate scratch space for IDispatch::GetIDsOfNames
m_pszScratch=(LPTSTR)malloc(256*sizeof(TCHAR));
if (NULL==m_pszScratch)
return FALSE;
return TRUE;
}
/*
* CBeeper::QueryInterface
* CBeeper::AddRef
* CBeeper::Release
*
* Purpose:
* IUnknown members for CBeeper object.
*/
STDMETHODIMP CBeeper::QueryInterface(REFIID riid, PPVOID ppv)
{
*ppv=NULL;
/*
* The only calls for IUnknown are either in a nonaggregated
* case or when created in an aggregation, so in either case
* always return our IUnknown for IID_IUnknown.
*/
if (IID_IUnknown==riid)
*ppv=this;
/*
* QueryInterface must respond not only to IID_IDispatch for
* the primary automation interface, but also to the DIID of the
* dispinterface itself, which in our case is DIID_DIBeeper.
*/
if (IID_IDispatch==riid || DIID_DIBeeper==riid)
*ppv=m_pImpIDispatch;
//AddRef any interface we'll return.
if (NULL!=*ppv)
{
((LPUNKNOWN)*ppv)->AddRef();
return NOERROR;
}
return ResultFromScode(E_NOINTERFACE);
}
STDMETHODIMP_(ULONG) CBeeper::AddRef(void)
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG) CBeeper::Release(void)
{
if (0L!=--m_cRef)
return m_cRef;
//Inform the server about destruction so it can handle shutdown
if (NULL!=m_pfnDestroy)
(*m_pfnDestroy)();
delete this;
return 0L;
}
//IDispatch interface implementation
/*
* CImpIDispatch::CImpIDispatch
* CImpIDispatch::~CImpIDispatch
*
* Parameters (Constructor):
* pObj PCBeeper of the object we're in.
* pUnkOuter LPUNKNOWN to which we delegate.
*/
CImpIDispatch::CImpIDispatch(PCBeeper pObj, LPUNKNOWN pUnkOuter)
{
m_cRef=0;
m_pObj=pObj;
m_pUnkOuter=pUnkOuter;
return;
}
CImpIDispatch::~CImpIDispatch(void)
{
return;
}
/*
* CImpIDispatch::QueryInterface
* CImpIDispatch::AddRef
* CImpIDispatch::Release
*
* Purpose:
* IUnknown members for CImpIDispatch object.
*/
STDMETHODIMP CImpIDispatch::QueryInterface(REFIID riid, PPVOID ppv)
{
return m_pUnkOuter->QueryInterface(riid, ppv);
}
STDMETHODIMP_(ULONG) CImpIDispatch::AddRef(void)
{
++m_cRef;
return m_pUnkOuter->AddRef();
}
STDMETHODIMP_(ULONG) CImpIDispatch::Release(void)
{
--m_cRef;
return m_pUnkOuter->Release();
}
/*
* CImpIDispatch::GetTypeInfoCount
*
* Purpose:
* Returns the number of type information (ITypeInfo) interfaces
* that the object provides (0 or 1).
*
* Parameters:
* pctInfo UINT * to the location to receive
* the count of interfaces.
*
* Return Value:
* HRESULT NOERROR or a general error code.
*/
STDMETHODIMP CImpIDispatch::GetTypeInfoCount(UINT *pctInfo)
{
//We don't implement GetTypeInfo, so return 0
*pctInfo=0;
return NOERROR;
}
/*
* CImpIDispatch::GetTypeInfo
*
* Purpose:
* Retrieves type information for the automation interface.
*
* Parameters:
* itinfo UINT reserved. Must be zero.
* lcid LCID providing the locale for the type
* information. If the object does not support
* localization, this is ignored.
* pptinfo ITypeInfo ** in which to store the ITypeInfo
* interface for the object.
*
* Return Value:
* HRESULT NOERROR or a general error code.
*/
STDMETHODIMP CImpIDispatch::GetTypeInfo(UINT itinfo, LCID lcid
, ITypeInfo **pptInfo)
{
/*
* Since we returned zero from GetTypeInfoCount, this function
* should not be called. If it is, be sure to NULL the pptInfo
* pointer according to normal out-parameter rules.
*/
*pptInfo=NULL;
return ResultFromScode(E_NOTIMPL);
}
/*
* 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;
int i;
int idsMin;
LPTSTR psz;
if (IID_NULL!=riid)
return ResultFromScode(DISP_E_UNKNOWNINTERFACE);
/*
* This function will support English and German languages,
* where in English we have a "Sound" property and "Beep"
* method; in German these are "Ton" and "Peip" This particular
* coding will handle either language identically, so a
* controller using even both languages simultaneously can work
* with this same automation object.
*
* To check the passed LCID, we use the PRIMARYLANGID macro
* to check for LANG_ENGLISH and LANG_GERMAN, which means we
* support any dialect of english (US, UK, AUS, CAN, NZ, EIRE)
* and german (GER, SWISS, AUS). The high byte of an LCID
* specifies the sub-language, and the macro here strips that
* differentiation.
*
* Note that LANG_NEUTRAL is considered here to be English.
*/
//Set up idsMin to the right stringtable in our resources
switch (PRIMARYLANGID(lcid))
{
case LANG_NEUTRAL:
case LANG_ENGLISH:
idsMin=IDS_0_NAMESMIN;
break;
case LANG_GERMAN:
idsMin=IDS_7_NAMESMIN;
break;
default:
return ResultFromScode(DISP_E_UNKNOWNLCID);
}
/*
* The index in this loop happens to correspond to the DISPIDs
* for each element which also matches the stringtable entry
* ordering, where i+idsMin is the string to compare. If we
* find a match, i is the DISPID to return.
*/
rgDispID[0]=DISPID_UNKNOWN;
hr=ResultFromScode(DISP_E_UNKNOWNNAME);
psz=m_pObj->m_pszScratch;
for (i=0; i < CNAMES; i++)
{
/*
* If we had more than one name per method or property,
* we'd need to loop over the cNames parameter as well.
*/
LoadString(g_hInst, idsMin+i, psz, 256);
#ifdef WIN32ANSI
char szTemp[80];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -