📄 automationproxy.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
//+---------------------------------------------------------------------------
//
// Microsoft Windows
//
// File: A U T O M A T I O N P R O X Y . C P P
//
// Contents: Implementation of the Automation Proxy class
//
// Notes:
//
// Author: spather 2000/09/25
//
//----------------------------------------------------------------------------
#include <windows.h>
#include <upnpdevapi.h>
#include <ncbase.h>
#include <ncdebug.h>
#include "trace.h"
#include "upnphost.h"
#include "AutomationProxy.h"
#include "DataType.hxx"
#include "variant.h"
#include "host_i.c"
/*
* Enum SST_DATA_TYPE
*
* Possible types of state variables
*/
enum SST_DATA_TYPE
{ // ----------------------
SDT_STRING = 0, // VT_BSTR
SDT_NUMBER, // VT_BSTR
SDT_INT, // VT_I4
SDT_FIXED_14_4, // VT_CY
SDT_BOOLEAN, // VT_BOOL
SDT_DATETIME_ISO8601, // VT_DATE
SDT_DATETIME_ISO8601TZ, // VT_DATE
SDT_DATE_ISO8601, // VT_DATE
SDT_TIME_ISO8601, // VT_DATE
SDT_TIME_ISO8601TZ, // VT_DATE
SDT_I1, // VT_I1
SDT_I2, // VT_I2
SDT_I4, // VT_I4
SDT_UI1, // VT_UI1
SDT_UI2, // VT_UI2
SDT_UI4, // VT_UI4
SDT_R4, // VT_FLOAT
SDT_R8, // VT_DOUBLE
SDT_FLOAT, // VT_DOUBLE
SDT_UUID, // VT_BSTR
SDT_BIN_BASE64, // VT_ARRAY
SDT_BIN_HEX, // VT_ARRAY
SDT_CHAR, // VT_UI2 (a wchar)
SDT_URI, // VT_BSTR
//
// note(cmr): ADD NEW VALUES IMMEDIATELY BEFORE THIS COMMENT
//
SDT_INVALID
};
struct DTNAME
{
LPCWSTR m_pszType;
SST_DATA_TYPE m_sdt;
};
// Lookup table, sorted by string
// Note: if you add strings here, you also have to add a
// corresponding entry to SST_DATA_TYPE
//
static CONST DTNAME g_rgdtTypeStrings[] =
{
{L"bin.base64", SDT_BIN_BASE64}, // base64 as defined in the MIME IETF spec
{L"bin.hex", SDT_BIN_HEX}, // Hexadecimal digits representing octets VT_ARRAY safearray or stream
{L"boolean", SDT_BOOLEAN}, // boolean, "1" or "0" VT_BOOL int
{L"char", SDT_CHAR}, // char, string VT_UI2 wchar
{L"date", SDT_DATE_ISO8601}, // date.iso8601, A date in ISO 8601 format. (no time) VT_DATE long
{L"dateTime", SDT_DATETIME_ISO8601}, // dateTime.iso8601, A date in ISO 8601 format, with optional time and no optional zone. Fractional seconds may be as precise as nanoseconds. VT_DATE long
{L"dateTime.tz", SDT_DATETIME_ISO8601TZ},// dateTime.iso8601tz, A date in ISO 8601 format, with optional time and optional zone. Fractional seconds may be as precise as nanoseconds. VT_DATE long
{L"fixed.14.4", SDT_FIXED_14_4}, // fixed.14.4, Same as "number" but no more than 14 digits to the left of the decimal point, and no more than 4 to the right. VT_CY large_integer
{L"float", SDT_FLOAT}, // float, Same as for "number." VT_R8 double
{L"i1", SDT_I1}, // i1, A number, with optional sign, no fractions, no exponent. VT_I1 char
{L"i2", SDT_I2}, // i2, " VT_I2 short
{L"i4", SDT_I4}, // i4, " VT_I4 long
{L"int", SDT_INT}, // int, A number, with optional sign, no fractions, no exponent. VT_I4 long
{L"number", SDT_NUMBER}, // number, A number, with no limit on digits, may potentially have a leading sign, fractional digits, and optionally an exponent. Punctuation as in US English. VT_R8 double
{L"r4", SDT_R4}, // r4, Same as "number." VT_FLOAT float
{L"r8", SDT_R8}, // r8, " VT_DOUBLE double
{L"string", SDT_STRING}, // string, pcdata VT_BSTR BSTR
{L"time", SDT_TIME_ISO8601}, // time.iso8601, A time in ISO 8601 format, with no date and no time zone. VT_DATE long
{L"time.tz", SDT_TIME_ISO8601TZ}, // time.iso8601.tz, A time in ISO 8601 format, with no date but optional time zone. VT_DATE. long
{L"ui1", SDT_UI1}, // ui1, A number, unsigned, no fractions, no exponent. VT_UI1 unsigned char
{L"ui2", SDT_UI2}, // ui2, " VT_UI2 unsigned short
{L"ui4", SDT_UI4}, // ui4, " VT_UI4 unsigned long
{L"uri", SDT_URI}, // uri, Universal Resource Identifier VT_BSTR BSTR
{L"uuid", SDT_UUID}, // uuid, Hexadecimal digits representing octets, optional embedded hyphens which should be ignored. VT_BSTR GUID
//
// note(cmr): ADD NEW VALUES IN ALPHABETICAL ORDER
//
};
// NOTE: the order of elements in this array must correspond to the order of
// elements in the SST_DATA_TYPE enum.
static CONST VARTYPE g_rgvtTypes[] =
{
VT_BSTR,
VT_BSTR,
VT_I4,
VT_CY,
VT_BOOL,
VT_DATE,
VT_DATE,
VT_DATE,
VT_DATE,
VT_DATE,
VT_I1,
VT_I2,
VT_I4,
VT_UI1,
VT_UI2,
VT_UI4,
VT_R4,
VT_R8,
VT_R8,
VT_BSTR,
VT_ARRAY | VT_UI1,
VT_ARRAY | VT_UI1,
VT_UI2,
VT_BSTR,
//
// note(cmr): ADD NEW VALUES IMMEDIATELY BEFORE THIS COMMENT.
// If adding new values, see comment above.
//
VT_EMPTY
};
PWSTR COMSzFromWsz(PCWSTR pszSource);
SST_DATA_TYPE GetTypeFromString(LPCWSTR pszTypeString);
VARTYPE GetVarTypeFromString(LPCWSTR pszTypeString);
////////////////////////////////////////////////////////////////////////////
// CUPnPAutomationProxy
CUPnPAutomationProxy::CUPnPAutomationProxy()
: m_rgVariables(m_StateVars),
m_rgActions(m_Actions),
m_fInitialized(FALSE),
m_pdispService(NULL),
m_cVariables(0),
m_cActions(0),
m_strType(NULL),
m_bRetval(false),
m_bSendEvents(false),
m_pCurrentAction(NULL)
{
}
CUPnPAutomationProxy::~CUPnPAutomationProxy()
{
if (m_pdispService)
m_pdispService->Release();
}
STDMETHODIMP
CUPnPAutomationProxy::Initialize(
/*[in]*/ IUnknown * punkSvcObject,
/*[in]*/ LPWSTR pszSvcDescription)
{
HRESULT hr = S_OK;
Assert(!m_fInitialized);
hr = punkSvcObject->QueryInterface(IID_IDispatch,
(void **) &m_pdispService);
if (SUCCEEDED(hr))
{
TraceTag(ttidAutomationProxy,
"CUPnPAutomationProxy::Initialize(): "
"Successfully obtained IDispatch pointer on service");
hr = Parse(pszSvcDescription);
}
if (SUCCEEDED(hr))
{
m_fInitialized = TRUE;
}
TraceError("CUPnPAutomationProxy::Initialize(): "
"Exiting",
hr);
return hr;
}
STDMETHODIMP
CUPnPAutomationProxy::QueryStateVariablesByDispIds(
/*[in]*/ DWORD cDispIds,
/*[in]*/ DISPID * rgDispIds,
/*[out]*/ DWORD * pcVariables,
/*[out]*/ LPWSTR ** prgszVariableNames,
/*[out]*/ VARIANT ** prgvarVariableValues,
/*[out]*/ LPWSTR ** prgszVariableDataTypes)
{
HRESULT hr = S_OK;
DWORD cDispIdsToLookUp;
DISPID * rgDispIdsToLookUp;
DISPID * rgDispIdsToLookUpMem = NULL;
LPWSTR * rgszVariableNames = NULL;
VARIANT * rgvarVariableValues = NULL;
LPWSTR * rgszVariableDataTypes = NULL;
DWORD cVariables = 0;
Assert(m_fInitialized);
if (0 == cDispIds)
{
// This means return all variables. Make an array of all our dispids.
cDispIdsToLookUp = 0;
rgDispIdsToLookUp = rgDispIdsToLookUpMem = new DISPID[m_cVariables];
if (rgDispIdsToLookUp)
{
for (DWORD i = 0; i < m_cVariables; i++)
{
if(m_rgVariables[i].bEvented)
rgDispIdsToLookUp[cDispIdsToLookUp++] = m_rgVariables[i].dispid;
}
}
else
{
hr = E_OUTOFMEMORY;
TraceError("CUPnPAutomationProxy::"
"QueryStateVariablesByDispIds(): "
"Could not allocate array of dispids",
hr);
}
}
else
{
cDispIdsToLookUp = cDispIds;
rgDispIdsToLookUp = rgDispIds;
}
if (SUCCEEDED(hr))
{
// Allocate output arrays of size cDispIds.
rgszVariableNames = (LPWSTR *)CoTaskMemAlloc(
cDispIdsToLookUp * sizeof(LPWSTR));
rgvarVariableValues = (VARIANT *)CoTaskMemAlloc(
cDispIdsToLookUp * sizeof(VARIANT));
rgszVariableDataTypes = (LPWSTR *)CoTaskMemAlloc(
cDispIdsToLookUp * sizeof(LPWSTR));
// Fill in values.
if (rgszVariableNames && rgvarVariableValues && rgszVariableDataTypes)
{
ZeroMemory(rgszVariableNames, cDispIdsToLookUp * sizeof(LPWSTR));
ZeroMemory(rgvarVariableValues, cDispIdsToLookUp * sizeof(VARIANT));
ZeroMemory(rgszVariableDataTypes, cDispIdsToLookUp * sizeof(LPWSTR));
for (DWORD i = 0; SUCCEEDED(hr) && (i < cDispIdsToLookUp); i++)
{
UPNP_STATE_VARIABLE * pVariable = NULL;
cVariables++;
pVariable = LookupVariableByDispID(rgDispIdsToLookUp[i]);
if (pVariable)
{
rgszVariableNames[i] = COMSzFromWsz(pVariable->strName);
rgszVariableDataTypes[i] = COMSzFromWsz(pVariable->strDataType);
if (rgszVariableNames[i] && rgszVariableDataTypes[i])
{
UINT uArgErr = 0;
DISPPARAMS dispparamsEmpty = {NULL, NULL, 0, 0};
hr = m_pdispService->Invoke(rgDispIdsToLookUp[i],
IID_NULL,
LOCALE_SYSTEM_DEFAULT,
DISPATCH_PROPERTYGET,
&dispparamsEmpty,
&rgvarVariableValues[i],
NULL,
&uArgErr);
if (SUCCEEDED(hr))
{
hr = StringizeVariant(&rgvarVariableValues[i], pVariable->strDataType);
}
if (SUCCEEDED(hr))
{
TraceTag(ttidAutomationProxy,
"CUPnPAutomationProxy::"
"QueryStateVariablesByDispIds(): "
"Successfully obtained value %S for "
"dispid %d",
V_BSTR(&rgvarVariableValues[i]),
rgDispIdsToLookUp[i]);
}
else
{
TraceError("CUPnPAutomationProxy::"
"QueryStateVariablesByDispIds(): "
"IDispatch::Invoke failed",
hr);
}
}
else
{
hr = E_OUTOFMEMORY;
TraceError("CUPnPAutomationProxy::"
"QueryStateVariablesByDispIds(): "
"Could not allocate name/data type strings",
hr);
}
}
else
{
hr = DISP_E_MEMBERNOTFOUND;
}
}
}
else
{
hr = E_OUTOFMEMORY;
TraceError("CUPnPAutomationProxy::"
"QueryStateVariablesByDispIds(): "
"Could not allocate output arrays",
hr);
}
}
// Copy the output arrays to the out parameters.
if (SUCCEEDED(hr))
{
*pcVariables = cVariables;
*prgszVariableNames = rgszVariableNames;
*prgvarVariableValues = rgvarVariableValues;
*prgszVariableDataTypes = rgszVariableDataTypes;
}
else
{
// Clean up. Assume cVariables accurately describes the number
// of initialized items in the arrays.
if (rgszVariableNames)
{
for (DWORD i = 0; i < cVariables; i++)
{
if (rgszVariableNames[i])
{
CoTaskMemFree(rgszVariableNames[i]);
rgszVariableNames[i] = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -