METHODSINK.CPP


/******************************************************************************\
********************************************************************************
* Filename: MethodSink.cpp
*
* Description: Sink for Method events
*
* This file is provided as part of the Microsoft Transaction Server
* Software Development Kit
*
*THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT
*WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
*INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
*OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
*PURPOSE.
*
* Copyright (C) 1997 Microsoft Corporation, All rights reserved
********************************************************************************
\******************************************************************************/
#include "stdafx.h"
#include "mtsspyctl.h"
#include "mtsevents.h"
#include "MtsSink.h"
#include "MtsAudit.h"
#include "MTSSpy.h"
#include "packagesink.h"
#include "PackageInfo.h"
#include "methodsink.h"

extern LONGLONG PerformanceFrequency;

STDMETHODIMP CMethodSink::OnMethodCall(LONGLONG perfCount, MTS_OBJID oid,REFCLSID guidCid, REFIID guidRid, ULONG iMeth)
{
TimeStack * pStack = m_map[oid];
if (!pStack)
{
pStack = new TimeStack;
m_map[oid] = pStack;
}
_ASSERTE(pStack);
pStack -> push_front(perfCount);

m_pSpy -> AddEventToList(perfCount, _TEXT("OnMethodCall"), m_sPackageName);
WCHAR id[16];
wsprintfW(id,L"0x%08X", oid);
m_pSpy -> AddParamValueToList(L"ObjectID", id);

CComBSTR sCid = GuidToBstr(guidCid);
CComBSTR sIid = GuidToBstr(guidRid);

m_pSpy -> AddParamValueToList(L"CLSID", sCid);
m_pSpy -> AddParamValueToList(L"riid", sIid);

TCHAR * pszGuidName = NULL;
HRESULT hr;
hr = GetMethodName(guidRid, iMeth, &pszGuidName) ;
if(hr == S_OK)
{
m_pSpy -> AddParamValueToList(L"Method Name", pszGuidName);
}
else
{
pszGuidName = new _TCHAR[8] ;
wsprintf(pszGuidName, _T("%X"), iMeth) ;
m_pSpy -> AddParamValueToList(L"v-table index", pszGuidName);
}
IF_AUDIT_DO(OnMethodCall)(perfCount,
oid,
sCid,
sIid,
pszGuidName);



delete pszGuidName ;
pszGuidName = NULL ;
return S_OK;
}

STDMETHODIMP CMethodSink::OnMethodReturn(LONGLONG perfCount,
MTS_OBJID oid,
REFCLSID guidCid,
REFIID guidRid,
ULONG iMeth,
HRESULT hrRet)
{
m_pSpy -> AddEventToList(perfCount, _TEXT("OnMethodReturn"), m_sPackageName);
WCHAR id[16];
wsprintfW(id,L"0x%08X", oid);
m_pSpy -> AddParamValueToList(L"ObjectID", id);

CComBSTR sCid = GuidToBstr(guidCid);
CComBSTR sIid = GuidToBstr(guidRid);

m_pSpy -> AddParamValueToList(L"CLSID", sCid);
m_pSpy -> AddParamValueToList(L"riid", sIid);

TCHAR * pszGuidName = NULL ;
HRESULT hr;
hr = GetMethodName(guidRid, iMeth, &pszGuidName) ;
if(hr != S_OK)
{
pszGuidName = new _TCHAR[8] ;
wsprintf(pszGuidName, _T("%X"), iMeth) ;
m_pSpy -> AddParamValueToList(L"v-table index", pszGuidName);
}
else
{
m_pSpy -> AddParamValueToList(L"Method Name", pszGuidName);
}

IF_AUDIT_DO(OnMethodReturn)(perfCount,
oid,
sCid,
sIid,
pszGuidName,
hrRet);


delete pszGuidName ;
pszGuidName = NULL ;


wsprintf(id, L"0x%08X", hrRet);
m_pSpy -> AddParamValueToList(L"Return Value", id);

TCHAR sTime[16];
TimeStack * pStack = m_map[oid];
LONGLONG oldTime = pStack -> front();
pStack -> pop_front();
_ASSERTE(oldTime);

DWORD timeDiff = (DWORD)((1000*(perfCount-oldTime))/PerformanceFrequency);
wsprintf(sTime, _T("%d"), timeDiff);

m_pSpy -> AddParamValueToList(L"Call time (ms)", sTime);
if (pStack -> empty())
{
delete pStack;
m_map.erase(oid);
}
return S_OK;
}

STDMETHODIMP CMethodSink::OnMethodException(LONGLONG perfCount, MTS_OBJID oid,REFCLSID guidCid, REFIID guidRid, ULONG iMeth)
{
m_pSpy -> AddEventToList(perfCount, _TEXT("OnInstanceException"), m_sPackageName);

WCHAR id[16];
wsprintfW(id,L"0x%08X", oid);
m_pSpy -> AddParamValueToList(L"ObjectID", id);

CComBSTR sCid = GuidToBstr(guidCid);
CComBSTR sIid = GuidToBstr(guidRid);

m_pSpy -> AddParamValueToList(L"CLSID", sCid);
m_pSpy -> AddParamValueToList(L"riid", sIid);

TCHAR * pszGuidName = NULL ;
HRESULT hr;
hr = GetMethodName(guidRid, iMeth, &pszGuidName) ;
if(hr != S_OK) { pszGuidName = new _TCHAR[64] ; lstrcpy(pszGuidName, L"Unknown (no TypeLibrary)") ; }
m_pSpy -> AddParamValueToList(L"Method Name", pszGuidName);

IF_AUDIT_DO(OnMethodException)(perfCount,
oid,
sCid,
sIid,
pszGuidName);


delete pszGuidName ;
pszGuidName = NULL ;
return S_OK;
}

STDMETHODIMP CMethodSink::Advise()
{
if (m_dwAdviseCookie)
return E_FAIL;

_ASSERTE(m_pCPC);
HRESULT hr;
hr = m_pCPC -> FindConnectionPoint(GetIID(), &m_pConPt);
if (hr == S_OK)
{
hr = m_pConPt -> Advise((IUnknown *)(IMtsMethodEvents *)this, &m_dwAdviseCookie);
_ASSERTE(hr == S_OK);
}

return hr;
}

HRESULT CMethodSink::GetClsidOfTypeLib2 (IID * piid, UUID * puuidClsid)
{
WCHAR*pszBuffIID= 0x0;
HRESULThr= S_OK;
WCHARrgBufferIid [40];
WCHARszBufferClsid[40];
RPC_STATUSRpcStatus;
WCHARrgBufferKey [256];
longlRetVal;
HKEYhkey;
longlcbszClsidBuff= 40 * sizeof(WCHAR) ;

//-------------------------------------------------------------------------
//Convert the iid to it's string form
RpcStatus = UuidToString ( piid, &pszBuffIID);


lstrcpy (rgBufferIid, pszBuffIID);
RpcStringFree (&pszBuffIID);


//-------------------------------------------------------------------------
//Create the Registry key to do the lookup with
lstrcpy (rgBufferKey, L"Interface\\{");
lstrcat (rgBufferKey, rgBufferIid);
lstrcat (rgBufferKey, L"}\\TypeLib");

//UNDONE -- gaganc Perhaps should handle the \interface\<iid1>\forward\<iid2|
//case also.

//-------------------------------------------------------------------------
//Open the appropriate registry key
//HKEY_CLASSES_ROOT\Interface\{<...interface iid ...>}\Typelib

lRetVal = RegOpenKey(
HKEY_CLASSES_ROOT,
rgBufferKey,
&hkey
);

if (lRetVal != ERROR_SUCCESS)
{
return E_FAIL;
}



//-------------------------------------------------------------------------
//Obain the clsid from the open key
lRetVal = RegQueryValueEx(
hkey,
NULL,
NULL,
NULL,
(unsigned char *)szBufferClsid,
(unsigned long *)&lcbszClsidBuff
);


if(lRetVal != ERROR_SUCCESS)
{
RegCloseKey(hkey) ;
return E_FAIL ;
}


//-------------------------------------------------------------------------
//Get rid of the braces in the begining and the end.

//Remove the trailing brace
szBufferClsid[37] = '\0';

//convert the string form of the clsid to a binary form. Plus 1 will
//remove the first brace.
lRetVal = UuidFromString ((szBufferClsid + 1), puuidClsid);

if(lRetVal != ERROR_SUCCESS)
{
RegCloseKey(hkey) ;
return E_UNEXPECTED ;
}

//-------------------------------------------------------------------------
//Prepare to return

lRetVal = RegCloseKey (hkey);

return hr;
} //end GetClsidOfTypeLib


//----------------------------------------------------------------------------
// Function:GetMethodName (INTERNAL FUNCTION)
// Description:Takes an IID and a method index returns the corresponding
// method name.
//
// Exceptions:n/a
// Process:
// Notes:ppszMethodName should be freed by the client using standard
//C++ delete. If hr != S_OK, ppszMethodName will be set to
//NULL.
//----------------------------------------------------------------------------
HRESULT CMethodSink::GetMethodName (REFIID riid, int iMeth, _TCHAR** ppszMethodName)
{
BOOLfRet= FALSE;
HRESULThr;
UUIDuuidClsid;
LCIDlcid= 0x0;
ITypeLib*pITypeLib= 0x0;
ITypeInfo*pITypeInfo= 0x0;
FUNCDESC * pFuncDesc = 0x0;
_TCHAR * pszMethod = 0x0;
BSTR bstrName ;
UINT lcNames = 0 ;

IID * piid = (IID *) &riid;

//Obtain the clsid of the typelib for this interface
hr = GetClsidOfTypeLib2 (piid, &uuidClsid);

if (hr != S_OK) goto errExit ;

//-------------------------------------------------------------------------
//Obtain the ITypeLib interface on the typelib
hr = LoadRegTypeLib (
uuidClsid,//CLSID
1,//Major version number
0,//Minor version number
0,//the locale id
&pITypeLib
);

// if the default system lcid (0) doesn't work, we try
// LCID 9 (standard english) and if that doesn't work, we failfast
if(FAILED(hr))
{
hr = LoadRegTypeLib (uuidClsid,1,0,9,&pITypeLib);
}


if(FAILED(hr)) goto errExit ;

hr = pITypeLib->GetTypeInfoOfGuid (*piid, &pITypeInfo);

if(FAILED(hr)) goto errExit ;

hr = pITypeInfo->GetFuncDesc(iMeth, &pFuncDesc) ;

if(FAILED(hr)) goto errExit ;

hr = pITypeInfo->GetNames(pFuncDesc->memid, &bstrName, 1, &lcNames) ;

if(FAILED(hr)) goto errExit ;

pszMethod = new _TCHAR[lstrlen(bstrName)+1] ;

if(! pszMethod)
{
hr = E_OUTOFMEMORY ;
goto errExit ;
}

lstrcpy(pszMethod, bstrName) ;

SysFreeString(bstrName) ;

errExit:

if (pFuncDesc)
{
pITypeInfo->ReleaseFuncDesc(pFuncDesc) ;
}


if (pITypeInfo)
{
pITypeInfo->Release();
}

if (pITypeLib)
{
pITypeLib->Release() ;
}

*ppszMethodName = pszMethod ;

return hr ;
}

/* ----------------------------------------------------------------------------
@func Description

Usage:<nl>
----------------------------------------------------------------------------- */