windows-nt/Source/XPSP1/NT/ds/security/services/ca/certlib/dispatch.cpp
2020-09-26 16:20:57 +08:00

811 lines
17 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1995 - 1999
//
// File: csdisp.cpp
//
// Contents: IDispatch helper functions
//
// History: 09-Dec-96 vich created
//
//--------------------------------------------------------------------------
#include <pch.cpp>
#pragma hdrstop
#include <stdlib.h>
#include "csdisp.h"
#ifndef DBG_DISPATCH
# define DBG_DISPATCH 0
#endif
TCHAR szRegKeyClsidValue[] = TEXT("");
HRESULT
DispatchGetReturnValue(
VARIANT *pvar,
IN LONG Type,
OUT VOID *pretval)
{
HRESULT hr = S_OK;
if (VT_EMPTY == pvar->vt)
{
hr = CERTSRV_E_PROPERTY_EMPTY;
_JumpError2(hr, error, "VT_EMPTY", hr);
}
if (Type != pvar->vt)
{
DBGPRINT((
DBG_SS_CERTLIB,
"pvar->vt=%x, expected %x\n",
pvar->vt,
Type));
hr = TYPE_E_WRONGTYPEKIND;
_JumpError(hr, error, "pvar->vt != Type");
}
switch (Type)
{
case VT_I4:
*(LONG *) pretval = pvar->lVal;
break;
case VT_DATE:
*(DATE *) pretval = pvar->date;
break;
case VT_BSTR:
*(BSTR *) pretval = pvar->bstrVal;
pvar->vt = VT_EMPTY;
break;
case VT_DISPATCH:
*(IDispatch **) pretval = pvar->pdispVal;
pvar->vt = VT_EMPTY;
break;
default:
hr = E_INVALIDARG;
goto error;
}
error:
return(hr);
}
HRESULT
DispatchSetErrorInfoSub(
IN HRESULT hrError,
OPTIONAL IN WCHAR const *pwszIDispatchMethod,
OPTIONAL IN WCHAR const *pwszDescription,
OPTIONAL IN WCHAR const *pwszSource,
OPTIONAL IN IID const *piid,
OPTIONAL IN WCHAR const *pwszHelpFile,
IN DWORD dwHelpFileContext)
{
HRESULT hr;
WCHAR const *pwszError = NULL;
ICreateErrorInfo *pCreateErrorInfo = NULL;
IErrorInfo *pErrorInfo = NULL;
#ifdef DBG_CERTSRV_DEBUG_PRINT
if (NULL != pwszIDispatchMethod || DbgIsSSActive(DBG_SS_CERTLIBI))
#else
if (NULL != pwszIDispatchMethod)
#endif
{
pwszError = myGetErrorMessageText(hrError, TRUE);
if (NULL != pwszIDispatchMethod)
{
CONSOLEPRINT1((
MAXDWORD,
"IDispatch->Invoke(%ws) Exception:\n",
pwszIDispatchMethod));
}
else
{
CONSOLEPRINT0((MAXDWORD, "COM Error:\n"));
}
CONSOLEPRINT5((
MAXDWORD,
" Source=%ws\n Description=%ws\n HelpFile=%ws[%x]\n %ws\n",
pwszSource,
pwszDescription,
pwszHelpFile,
dwHelpFileContext,
pwszError));
}
hr = CreateErrorInfo(&pCreateErrorInfo);
_JumpIfError(hr, error, "CreateErrorInfo");
if (NULL != piid)
{
hr = pCreateErrorInfo->SetGUID(*piid);
_PrintIfError(hr, "SetGUID");
}
if (NULL != pwszSource)
{
hr = pCreateErrorInfo->SetSource(const_cast<WCHAR *>(pwszSource));
_PrintIfError(hr, "SetSource");
}
if (NULL != pwszDescription)
{
hr = pCreateErrorInfo->SetDescription(
const_cast<WCHAR *>(pwszDescription));
_PrintIfError(hr, "SetDescription");
}
if (NULL != pwszHelpFile)
{
hr = pCreateErrorInfo->SetHelpFile(const_cast<WCHAR *>(pwszHelpFile));
_PrintIfError(hr, "SetHelpFile");
hr = pCreateErrorInfo->SetHelpContext(dwHelpFileContext);
_PrintIfError(hr, "SetHelpContext");
}
hr = pCreateErrorInfo->QueryInterface(
IID_IErrorInfo,
(VOID **) &pErrorInfo);
_JumpIfError(hr, error, "QueryInterface");
SetErrorInfo(0, pErrorInfo);
hr = S_OK;
error:
if (NULL != pwszError)
{
LocalFree(const_cast<WCHAR *>(pwszError));
}
if (NULL != pErrorInfo)
{
pErrorInfo->Release();
}
if (NULL != pCreateErrorInfo)
{
pCreateErrorInfo->Release();
}
return(hr);
}
HRESULT
DispatchInvoke(
IN DISPATCHINTERFACE *pDispatchInterface,
IN LONG MethodIndex,
IN DWORD cvar,
IN VARIANT avar[],
IN LONG Type,
OUT VOID *pretval)
{
HRESULT hr;
DISPATCHTABLE const *pdt;
EXCEPINFO excepinfo;
VARIANT varResult;
DISPPARAMS parms;
unsigned iArgErr;
DISPID *adispid;
VariantInit(&varResult);
CSASSERT(NULL != pDispatchInterface->pDispatchTable);
CSASSERT((DWORD) MethodIndex < pDispatchInterface->m_cDispatchTable);
pdt = &pDispatchInterface->pDispatchTable[MethodIndex];
adispid = &pDispatchInterface->m_adispid[pdt->idispid];
CSASSERT(NULL != pDispatchInterface->m_adispid);
CSASSERT(pdt->idispid + pdt->cdispid <= pDispatchInterface->m_cdispid);
parms.rgvarg = avar;
parms.rgdispidNamedArgs = &adispid[1];
parms.cArgs = pdt->cdispid - 1;
parms.cNamedArgs = parms.cArgs;
if (parms.cArgs != cvar)
{
CSASSERT(parms.cArgs == cvar);
hr = HRESULT_FROM_WIN32(ERROR_INTERNAL_ERROR);
_JumpError(hr, error, "cvar");
}
CSASSERT(NULL != pDispatchInterface->pDispatch);
hr = pDispatchInterface->pDispatch->Invoke(
adispid[0],
IID_NULL,
LOCALE_SYSTEM_DEFAULT,
DISPATCH_METHOD,
&parms,
&varResult,
&excepinfo,
&iArgErr);
if (S_OK != hr)
{
_PrintErrorStr(hr, "Invoke", pdt->apszNames[0]);
if (DISP_E_EXCEPTION == hr)
{
HRESULT hr2;
IID const *piid;
if (FAILED(excepinfo.scode))
{
hr = excepinfo.scode;
}
hr2 = DispatchSetErrorInfoSub(
hr,
pdt->apszNames[0],
excepinfo.bstrDescription,
excepinfo.bstrSource,
pDispatchInterface->GetIID(),
excepinfo.bstrHelpFile,
excepinfo.dwHelpContext);
_PrintIfError(hr2, "DispatchSetErrorInfoSub");
}
goto error;
}
if (CLSCTX_INPROC_SERVER != pDispatchInterface->m_ClassContext)
{
myRegisterMemAlloc(&varResult, 0, CSM_VARIANT);
}
if (NULL != pretval)
{
hr = DispatchGetReturnValue(&varResult, Type, pretval);
_JumpIfErrorStr2(
hr,
error,
"DispatchGetReturnValue",
pdt->apszNames[0],
CERTSRV_E_PROPERTY_EMPTY);
}
error:
VariantClear(&varResult);
return(hr);
}
HRESULT
DispatchGetIds(
IN IDispatch *pDispatch,
IN DWORD cDispatchTable,
IN OUT DISPATCHTABLE *pDispatchTable,
IN OUT DISPATCHINTERFACE *pDispatchInterface)
{
HRESULT hr = S_OK;
DISPATCHTABLE *pdt;
DISPATCHTABLE *pdtEnd;
DISPID *adispid = NULL;
DWORD idispid;
pdtEnd = &pDispatchTable[cDispatchTable];
pDispatchInterface->m_cdispid = 0;
for (pdt = pDispatchTable; pdt < pdtEnd; pdt++)
{
if (0 == pdt->idispid)
{
pdt->idispid = pDispatchInterface->m_cdispid;
}
CSASSERT(pdt->idispid == pDispatchInterface->m_cdispid);
pDispatchInterface->m_cdispid += pdt->cdispid;
}
adispid = (DISPID *) LocalAlloc(
LMEM_FIXED,
pDispatchInterface->m_cdispid * sizeof(adispid[0]));
if (NULL == adispid)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
idispid = 0;
for (pdt = pDispatchTable; pdt < pdtEnd; pdt++)
{
CSASSERT(idispid + pdt->cdispid <= pDispatchInterface->m_cdispid);
hr = pDispatch->GetIDsOfNames(
IID_NULL,
pdt->apszNames,
pdt->cdispid,
LOCALE_SYSTEM_DEFAULT,
&adispid[idispid]);
#if DBG_CERTSRV
if (S_OK != hr || DBG_DISPATCH)
{
DWORD i;
DBGPRINT((
MAXDWORD,
"GetIDsOfNames(%ws) --> %x, dispid=%x" szLPAREN,
pdt->apszNames[0],
hr,
adispid[idispid]));
for (i = 1; i < pdt->cdispid; i++)
{
DBGPRINT((
MAXDWORD,
"%ws%x",
i == 1? L"" : L", ",
adispid[idispid + i]));
}
DBGPRINT((MAXDWORD, szRPAREN "\n"));
}
#endif
_JumpIfError(hr, error, "GetIDsOfNames");
idispid += pdt->cdispid;
}
pDispatchInterface->m_cDispatchTable = cDispatchTable;
pDispatchInterface->pDispatchTable = pDispatchTable;
pDispatchInterface->m_adispid = adispid;
adispid = NULL;
error:
if (NULL != adispid)
{
LocalFree(adispid);
}
return(hr);
}
HRESULT
DispatchSetup(
IN DWORD Flags,
IN DWORD ClassContext,
OPTIONAL IN TCHAR const *pszProgID, // for IDispatch
OPTIONAL IN CLSID const *pclsid, // for COM
OPTIONAL IN IID const *piid, // for COM
IN DWORD cDispatchTable, // for IDispatch
IN OUT DISPATCHTABLE *pDispatchTable,
IN OUT DISPATCHINTERFACE *pDispatchInterface)
{
HRESULT hr;
CLSID clsid;
pDispatchInterface->SetIID(piid);
while (TRUE)
{
pDispatchInterface->pDispatch = NULL;
pDispatchInterface->pUnknown = NULL;
pDispatchInterface->m_adispid = NULL;
CSASSERT(NULL != pszProgID || DISPSETUP_COM == Flags);
CSASSERT(NULL != pclsid || DISPSETUP_IDISPATCH == Flags);
CSASSERT(NULL != piid || DISPSETUP_IDISPATCH == Flags);
if (DISPSETUP_IDISPATCH == Flags)
{
// use win32 version, not our own hack
hr = CLSIDFromProgID(pszProgID, &clsid);
_JumpIfError2(
hr,
error,
"ClassNameToCLSID",
HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
pclsid = &clsid;
piid = &IID_IDispatch;
}
hr = CoCreateInstance(
*pclsid,
NULL, // pUnkOuter
ClassContext,
*piid,
DISPSETUP_IDISPATCH == Flags?
(VOID **) &pDispatchInterface->pDispatch :
(VOID **) &pDispatchInterface->pUnknown);
#if DBG_DISPATCH
printf("CoCreateInstance(%x) --> %x\n", Flags, hr);
#endif
if (S_OK != hr)
{
if (DISPSETUP_COMFIRST != Flags)
{
_JumpError2(hr, error, "CoCreateInstance", E_NOINTERFACE);
}
Flags = DISPSETUP_IDISPATCH;
continue;
}
pDispatchInterface->m_ClassContext = ClassContext;
break;
}
if (DISPSETUP_IDISPATCH == Flags)
{
hr = DispatchGetIds(
pDispatchInterface->pDispatch,
cDispatchTable,
pDispatchTable,
pDispatchInterface);
if (S_OK != hr)
{
DispatchRelease(pDispatchInterface);
_JumpError(hr, error, "DispatchGetIds");
}
}
error:
return(hr);
}
HRESULT
DispatchSetup2(
IN DWORD Flags,
IN DWORD ClassContext,
IN WCHAR const *pwszClass, // wszRegKeyAdminClsid
IN CLSID const *pclsid,
IN DWORD cver,
IN IID const * const *ppiid, // cver elements
IN DWORD const *pcDispatch, // cver elements
IN OUT DISPATCHTABLE *pDispatchTable,
IN OUT DISPATCHINTERFACE *pDispatchInterface)
{
HRESULT hr = E_INVALIDARG;
CSASSERT(0 < cver);
for ( ; 0 < cver; cver--, ppiid++, pcDispatch++)
{
hr = DispatchSetup(
Flags,
ClassContext,
pwszClass,
pclsid,
*ppiid,
*pcDispatch,
pDispatchTable,
pDispatchInterface);
if (S_OK == hr)
{
pDispatchInterface->m_dwVersion = cver;
pDispatchInterface->pDispatchTable = pDispatchTable;
break;
}
if (1 == cver || (E_NOINTERFACE != hr && DISP_E_UNKNOWNNAME != hr))
{
_JumpErrorStr(hr, error, "DispatchSetup", pwszClass);
}
_PrintErrorStr2(hr, "DispatchSetup", pwszClass, hr);
}
error:
return(hr);
}
VOID
DispatchRelease(
IN OUT DISPATCHINTERFACE *pDispatchInterface)
{
if (NULL != pDispatchInterface->pDispatch)
{
pDispatchInterface->pDispatch->Release();
pDispatchInterface->pDispatch = NULL;
}
if (NULL != pDispatchInterface->pUnknown)
{
pDispatchInterface->pUnknown->Release();
pDispatchInterface->pUnknown = NULL;
}
if (NULL != pDispatchInterface->m_adispid)
{
LocalFree(pDispatchInterface->m_adispid);
pDispatchInterface->m_adispid = NULL;
}
}
BOOL
myConvertWszToBstr(
OUT BSTR *pbstr,
IN WCHAR const *pwc,
IN LONG cb)
{
HRESULT hr;
BSTR bstr;
do
{
bstr = NULL;
if (NULL != pwc)
{
if (-1 == cb)
{
cb = wcslen(pwc) * sizeof(WCHAR);
}
bstr = SysAllocStringByteLen((char const *) pwc, cb);
if (NULL == bstr)
{
hr = E_OUTOFMEMORY;
break;
}
}
if (NULL != *pbstr)
{
SysFreeString(*pbstr);
}
*pbstr = bstr;
hr = S_OK;
} while (FALSE);
if (S_OK != hr)
{
SetLastError(hr);
}
return(S_OK == hr);
}
BOOL
myConvertSzToBstr(
OUT BSTR *pbstr,
IN CHAR const *pch,
IN LONG cch)
{
HRESULT hr;
BSTR bstr = NULL;
LONG cwc = 0;
if (-1 == cch)
{
cch = strlen(pch);
}
CSASSERT(0 != cch);
while (TRUE)
{
cwc = MultiByteToWideChar(GetACP(), 0, pch, cch, bstr, cwc);
if (0 >= cwc)
{
hr = myHLastError();
_PrintError(hr, "MultiByteToWideChar");
if (NULL != bstr)
{
SysFreeString(bstr);
}
break;
}
if (NULL != bstr)
{
bstr[cwc] = L'\0';
if (NULL != *pbstr)
{
SysFreeString(*pbstr);
}
*pbstr = bstr;
hr = S_OK;
break;
}
bstr = SysAllocStringLen(NULL, cwc);
if (NULL == bstr)
{
hr = E_OUTOFMEMORY;
break;
}
}
if (S_OK != hr)
{
SetLastError(hr);
}
return(S_OK == hr);
}
HRESULT
DecodeCertString(
IN BSTR const bstrIn,
IN DWORD Flags,
OUT BYTE **ppbOut,
OUT DWORD *pcbOut)
{
HRESULT hr;
DWORD dwSize;
*ppbOut = NULL;
CSASSERT(CR_IN_BASE64HEADER == CRYPT_STRING_BASE64HEADER);
CSASSERT(CR_IN_BASE64 == CRYPT_STRING_BASE64);
CSASSERT(CR_IN_BINARY == CRYPT_STRING_BINARY);
switch (Flags)
{
case CRYPT_STRING_BASE64HEADER:
case CRYPT_STRING_BASE64:
case CRYPT_STRING_BASE64REQUESTHEADER:
case CRYPT_STRING_HEX:
case CRYPT_STRING_HEXASCII:
case CRYPT_STRING_BASE64_ANY:
case CRYPT_STRING_HEX_ANY:
case CRYPT_STRING_BASE64X509CRLHEADER:
case CRYPT_STRING_HEXADDR:
case CRYPT_STRING_HEXASCIIADDR:
CSASSERT(sizeof(WCHAR) * wcslen(bstrIn) == SysStringByteLen(bstrIn));
// FALLTHROUGH
case CRYPT_STRING_ANY:
dwSize = (SysStringByteLen(bstrIn) + sizeof(WCHAR) - 1) / sizeof(WCHAR);
break;
case CRYPT_STRING_BINARY:
dwSize = SysStringByteLen(bstrIn);
break;
default:
hr = E_INVALIDARG;
_JumpError(hr, error, "Flags");
}
hr = myCryptStringToBinary(
bstrIn,
dwSize,
Flags,
ppbOut,
pcbOut,
NULL,
NULL);
_JumpIfError(hr, error, "myCryptStringToBinary");
if (CRYPT_STRING_ANY == Flags &&
(SysStringByteLen(bstrIn) & (sizeof(WCHAR) - 1)))
{
(*pcbOut)--;
CSASSERT(SysStringByteLen(bstrIn) == *pcbOut);
}
hr = S_OK;
error:
return(hr);
}
HRESULT
EncodeCertString(
IN BYTE const *pbIn,
IN DWORD cbIn,
IN DWORD Flags,
OUT BSTR *pbstrOut)
{
HRESULT hr = E_INVALIDARG;
WCHAR *pwcCert = NULL;
DWORD cbCert;
BSTR strCert = NULL;
CSASSERT(CR_OUT_BASE64HEADER == CRYPT_STRING_BASE64HEADER);
CSASSERT(CR_OUT_BASE64 == CRYPT_STRING_BASE64);
CSASSERT(CR_OUT_BINARY == CRYPT_STRING_BINARY);
//CSASSERT(CR_OUT_BASE64REQUESTHEADER == CRYPT_STRING_BASE64REQUESTHEADER);
//CSASSERT(CR_OUT_HEX == CRYPT_STRING_HEX);
CSASSERT(CV_OUT_BASE64HEADER == CRYPT_STRING_BASE64HEADER);
CSASSERT(CV_OUT_BASE64 == CRYPT_STRING_BASE64);
CSASSERT(CV_OUT_BINARY == CRYPT_STRING_BINARY);
CSASSERT(CV_OUT_BASE64REQUESTHEADER == CRYPT_STRING_BASE64REQUESTHEADER);
CSASSERT(CV_OUT_HEX == CRYPT_STRING_HEX);
CSASSERT(CV_OUT_HEXASCII == CRYPT_STRING_HEXASCII);
CSASSERT(CV_OUT_BASE64X509CRLHEADER == CRYPT_STRING_BASE64X509CRLHEADER);
CSASSERT(CV_OUT_HEXADDR == CRYPT_STRING_HEXADDR);
CSASSERT(CV_OUT_HEXASCIIADDR == CRYPT_STRING_HEXASCIIADDR);
if (NULL == pbIn || (~CR_OUT_ENCODEMASK & Flags))
{
goto error;
}
switch (CR_OUT_ENCODEMASK & Flags)
{
case CRYPT_STRING_BASE64HEADER:
case CRYPT_STRING_BASE64:
case CRYPT_STRING_BASE64REQUESTHEADER:
case CRYPT_STRING_HEX:
case CRYPT_STRING_HEXASCII:
case CRYPT_STRING_BASE64X509CRLHEADER:
case CRYPT_STRING_HEXADDR:
case CRYPT_STRING_HEXASCIIADDR:
hr = myCryptBinaryToString(
pbIn,
cbIn,
CR_OUT_ENCODEMASK & Flags,
&pwcCert);
_JumpIfError(hr, error, "myCryptBinaryToString");
cbCert = sizeof(WCHAR) * wcslen(pwcCert);
break;
case CRYPT_STRING_BINARY:
pwcCert = (WCHAR *) pbIn;
cbCert = cbIn;
hr = S_OK;
break;
default:
goto error;
}
if (!ConvertWszToBstr(pbstrOut, pwcCert, cbCert))
{
hr = E_OUTOFMEMORY;
}
hr = S_OK;
error:
if (NULL != pwcCert && pwcCert != (WCHAR *) pbIn)
{
LocalFree(pwcCert);
}
return(hr);
}
HRESULT
DispatchSetErrorInfo(
IN HRESULT hrError,
IN WCHAR const *pwszDescription,
OPTIONAL IN WCHAR const *pwszProgId,
OPTIONAL IN IID const *piid)
{
HRESULT hr;
WCHAR const *pwszError = NULL;
WCHAR *pwszText = NULL;
if (NULL == pwszDescription)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL pointer");
}
CSASSERT(FAILED(hrError));
pwszError = myGetErrorMessageText(hrError, TRUE);
if (NULL == pwszError)
{
_PrintError(E_OUTOFMEMORY, "myGetErrorMessageText");
}
else
{
pwszText = (WCHAR *) LocalAlloc(
LMEM_FIXED,
(wcslen(pwszDescription) + 1 + wcslen(pwszError) + 1) *
sizeof(WCHAR));
if (NULL == pwszText)
{
_PrintError(E_OUTOFMEMORY, "LocalAlloc");
}
else
{
wcscpy(pwszText, pwszDescription);
wcscat(pwszText, L" ");
wcscat(pwszText, pwszError);
}
}
hr = DispatchSetErrorInfoSub(
hrError,
NULL, // pwszIDispatchMethod
NULL != pwszText?
pwszText : const_cast<WCHAR *>(pwszDescription),
pwszProgId,
piid,
NULL, // pwszHelpFile
0); // dwHelpFileContext
_PrintIfError(hr, "DispatchSetErrorInfoSub");
error:
if (NULL != pwszText)
{
LocalFree(pwszText);
}
if (NULL != pwszError)
{
LocalFree(const_cast<WCHAR *>(pwszError));
}
return(hrError); // return input error!
}