|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997.
//
// File: D E V I C E . C P P
//
// Contents: Functions dealing with UPnP controlled devices
//
// Notes:
//
// Author: danielwe 28 Oct 1999
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include "ncbase.h"
#include <oleauto.h>
#include <wininet.h>
#include "updiagp.h"
#include "ncinet.h"
#include "setupapi.h"
#include "util.h"
extern const STANDARD_OPERATION_LIST c_Ops;
UPNPDEV *PDevCur() { return g_ctx.pdevCur[g_ctx.idevStackIndex - 1]; }
VOID PushDev(UPNPDEV *pdev) { g_ctx.pdevCur[g_ctx.idevStackIndex++] = pdev; g_ctx.ectx = CTX_CD; }
UPNPDEV *PopDev() { UPNPDEV * pdev;
pdev = PDevCur(); g_ctx.idevStackIndex--;
return pdev; }
VOID RgPropsFromSst(SST *psst, UPNP_PROPERTY **prgProps) { DWORD iProp; UPNP_PROPERTY * rgProps;
rgProps = new UPNP_PROPERTY[psst->cRows];
for (iProp = 0; iProp < psst->cRows; iProp++) { rgProps[iProp].szName = SzFromTsz(psst->rgRows[iProp].szPropName);
VARIANT varDest; VariantInit(&varDest); VariantChangeType(&varDest, &psst->rgRows[iProp].varValue, 0, VT_BSTR);
//$ BUGBUG (danielwe) 25 Oct 1999: Remove this when SSDP is built
// Unicode.
//
LPWSTR wszVal = varDest.bstrVal; rgProps[iProp].szValue = SzFromWsz(wszVal); rgProps[iProp].dwFlags = 0; }
*prgProps = rgProps; }
BOOL FRegisterDeviceAsUpnpService(LPSTR szDescDocUrl, UPNPDEV *pdev) { SSDP_MESSAGE msg = {0}; CHAR szBuffer[256]; CHAR szUdn[256]; CHAR szType[256];
msg.iLifeTime = 15000; msg.szLocHeader = szDescDocUrl;
Assert(pdev->szUdn); Assert(pdev->szDeviceType);
TszToSzBuf(szUdn, pdev->szUdn, celems(szUdn)); TszToSzBuf(szType, pdev->szDeviceType, celems(szType));
// Only register this type if this is a root device
//
if (pdev->fRoot) { wsprintfA(szBuffer, "%s::upnp:rootdevice", szUdn); msg.szType = "upnp:rootdevice"; msg.szUSN = szBuffer;
pdev->hSvc[0] = RegisterService(&msg, 0); if (pdev->hSvc[0] != INVALID_HANDLE_VALUE) { TraceTag(ttidUpdiag, "Registered %s as an SSDP Service.", msg.szType); } else { TraceTag(ttidUpdiag, "Failed to register %s as an SSDP Service! Error = %d.", msg.szType, GetLastError()); return FALSE; } }
msg.szUSN = szUdn; msg.szType = szUdn;
pdev->hSvc[1] = RegisterService(&msg, 0); if (pdev->hSvc[1] != INVALID_HANDLE_VALUE) { TraceTag(ttidUpdiag, "Registered %s as an SSDP Service.", msg.szType); } else { TraceTag(ttidUpdiag, "Failed to register %s as an SSDP Service! Error = %d.", msg.szType, GetLastError()); return FALSE; }
wsprintfA(szBuffer, "%s::%s", szUdn, szType); msg.szUSN = szBuffer; msg.szType = szType;
pdev->hSvc[2] = RegisterService(&msg, 0); if (pdev->hSvc[2] != INVALID_HANDLE_VALUE) { TraceTag(ttidUpdiag, "Registered %s as an SSDP Service.", msg.szType); } else { TraceTag(ttidUpdiag, "Failed to register %s as an SSDP Service! Error = %d.", msg.szType, GetLastError()); return FALSE; }
return TRUE; }
VOID GetServiceConfigFile(UPNPDEV * pdev, UPNPSVC * psvc, LPCTSTR szDevConfigFile) { HRESULT hr; HINF hinf; INFCONTEXT ctx; UINT unErrorLine;
TCHAR szKey[LINE_LEN]; // LINE_LEN defined in setupapi.h as 256
TCHAR szDeviceType[LINE_LEN]; TCHAR szServiceType[LINE_LEN];
// full path to the inf file is %windir%\inf\szConfigFile
TCHAR szDevConfigFileWithPath[MAX_PATH]; GetWindowsDirectory (szDevConfigFileWithPath, MAX_PATH);
lstrcat (szDevConfigFileWithPath, TEXT("\\inf\\")); lstrcat(szDevConfigFileWithPath, szDevConfigFile);
hr = HrSetupOpenConfigFile(szDevConfigFileWithPath, &unErrorLine, &hinf); if (S_OK == hr) { Assert(IsValidHandle(hinf));
// Loop over the Devices section
hr = HrSetupFindFirstLine(hinf, TEXT("Devices"), NULL, &ctx); if (S_OK == hr) { do { // Retrieve a line from the Devices section
hr = HrSetupGetStringField(ctx,0,szKey,celems(szKey),NULL); if(S_OK == hr) { // varify this is an "Device"
szKey[celems(szKey)-1] = L'\0'; if (lstrcmpi(szKey, TEXT("Device"))) { TraceTag(ttidUpdiag, "Wrong key in the Devices section: %s", szKey); continue; }
// Query the DeviceType
hr = HrSetupGetStringField(ctx, 1, szDeviceType, celems(szDeviceType), NULL); if (S_OK == hr) { if (!lstrcmpi(szDeviceType, pdev->szDeviceType)) { break; } else { continue; } } } } while (S_OK == (hr = HrSetupFindNextLine(ctx, &ctx))); }
if (hr == S_FALSE) { // we didn't find the device !
TraceTag(ttidUpdiag, "Error!! Config section for device %s is not found.", pdev->szDeviceType); } else { // Loop over section for this device
hr = HrSetupFindFirstLine(hinf, szDeviceType, NULL, &ctx); if (S_OK == hr) { do { // Retrieve a line from the Devices section
hr = HrSetupGetStringField(ctx,0,szKey,celems(szKey),NULL); if(S_OK == hr) { // varify this is an "Device"
szKey[celems(szKey)-1] = L'\0'; if (lstrcmpi(szKey, TEXT("Service"))) { TraceTag(ttidUpdiag, "Wrong key in the Device's section: %s", szKey); continue; }
// Query the Service Type
hr = HrSetupGetStringField(ctx, 1, szServiceType, celems(szServiceType), NULL); if (S_OK == hr) { if (!lstrcmpi(szServiceType, psvc->szServiceType)) { break; } else { continue; } } } } while (S_OK == (hr = HrSetupFindNextLine(ctx, &ctx)));
if (hr == S_FALSE) { // we didn't find the service !
TraceTag(ttidUpdiag, "Error!! Config section for service %s is not found.", psvc->szServiceType); } else { hr = HrSetupFindFirstLine(hinf, szServiceType, NULL, &ctx); if (S_OK == hr) { // Retrieve a line from the Devices section
hr = HrSetupGetStringField(ctx,0,szKey,celems(szKey),NULL); if(S_OK == hr) { // varify this is an "Device"
szKey[celems(szKey)-1] = L'\0'; if (lstrcmpi(szKey, TEXT("ServiceInf"))) { TraceTag(ttidUpdiag, "Wrong key in the Service's section: %s", szKey); } else { // Query the Service config file
TCHAR szConfigFile[MAX_PATH]; hr = HrSetupGetStringField(ctx, 1, szConfigFile, celems(szConfigFile), NULL); if (S_OK ==hr) { // full path to the inf file is %windir%\inf\szConfigFile
TCHAR szDevConfigFileWithPath[MAX_PATH]; GetWindowsDirectory (psvc->szConfigFile, MAX_PATH);
lstrcat (psvc->szConfigFile, TEXT("\\inf\\")); lstrcat(psvc->szConfigFile, szConfigFile); } } } } } } }
SetupCloseInfFileSafe(hinf); } }
HRESULT HrAddAllowedValue(SST_ROW * pRow, TCHAR * szValueRange) { HRESULT hr = S_OK;
if(*szValueRange == '(') { szValueRange++;
IXMLDOMElement * pAllowedValueNode = NULL; BSTR bstrElementName;
// we assume that ".." specifies a range, otherwise it's a comma
// separated list of allowed values
TCHAR * pChar = _tcsstr(szValueRange, TEXT("..")); if (pChar) { // we have a range
TCHAR * pNextItem = szValueRange;
// BUGBUG: we should check if data type of the min, max & step
// matches the variable type
*pChar = '\0'; lstrcpy(pRow->szMin, pNextItem); pNextItem = pChar+2;
pChar = _tcschr(pNextItem, TEXT(',')); if (pChar) { *pChar = '\0'; lstrcpy(pRow->szMax, pNextItem); pNextItem = ++pChar;
pChar = _tcschr(pNextItem, TEXT(')')); if (pChar) { *pChar = '\0'; lstrcpy(pRow->szStep, pNextItem); } else { TraceTag(ttidUpdiag, "HrAddAllowedValue: missing closing )"); hr = E_INVALIDARG; } } else { TraceTag(ttidUpdiag, "HrAddAllowedValue: step not specified"); hr = E_INVALIDARG; } } else { // we have a list of allowed values
pChar = _tcschr(szValueRange, TEXT(')')); if (pChar) { *pChar = '\0'; if (lstrlen(szValueRange)) { lstrcpy(pRow->mszAllowedValueList, szValueRange); TCHAR * pNextItem = pRow->mszAllowedValueList;
while ((S_OK ==hr) && (pChar = _tcschr(pNextItem, TEXT(',')))) { *pChar = '\0'; pNextItem = ++pChar; }
// add the last one
if (*pNextItem) { pNextItem += lstrlen(pNextItem); pNextItem ++;
*pNextItem = '\0'; } else { TraceTag(ttidUpdiag, "HrAddAllowedValue: invalid syntax"); hr = E_INVALIDARG; } } } else { TraceTag(ttidUpdiag, "HrAddAllowedValue: missing closing )"); hr = E_INVALIDARG; } } } else { TraceTag(ttidUpdiag, "HrAddAllowedValue: missing begining ("); hr = E_INVALIDARG; }
TraceError("HrAddAllowedValue", hr); return hr; }
HRESULT HrAddVariable(UPNPSVC * psvc, LPTSTR szVariableLine) { HRESULT hr = S_OK;
DWORD iRow = psvc->sst.cRows; if (iRow < MAX_SST_ROWS) { SST_ROW * pRow = &psvc->sst.rgRows[iRow];
// fill in variable name
TCHAR szName[MAX_PATH]; if (fGetNextField(&szVariableLine, szName)) { lstrcpy(pRow->szPropName, szName);
TCHAR szType[MAX_PATH]; fGetNextField(&szVariableLine, szType);
TCHAR szValueRange[MAX_PATH]; fGetNextField(&szVariableLine, szValueRange);
TCHAR szDefaultValue[MAX_PATH]; fGetNextField(&szVariableLine, szDefaultValue);
// fill in variable type and default value
if (*szType && *szDefaultValue) { VariantInit(&pRow->varValue); pRow->varValue.vt = VT_BSTR;
WCHAR * wszDefaultValue = WszFromTsz(szDefaultValue); V_BSTR(&pRow->varValue) = SysAllocString(wszDefaultValue); delete wszDefaultValue;
VARTYPE vt = VT_EMPTY;
if (lstrcmpi(szType, TEXT("number")) == 0) { vt = VT_I4; } else if (lstrcmpi(szType, TEXT("string")) == 0) { vt = VT_BSTR; } else if (lstrcmpi(szType, TEXT("dateTime")) == 0) { vt = VT_DATE; } else if (lstrcmpi(szType, TEXT("boolean")) == 0) { vt = VT_BOOL; } else if (lstrcmpi(szType, TEXT("ByteBlock")) == 0) { vt = VT_UI1 | VT_ARRAY; }
if (vt != VT_EMPTY) { hr = VariantChangeType(&pRow->varValue, &pRow->varValue, 0, vt); } else { hr = E_INVALIDARG; TraceTag(ttidUpdiag, "HrAddVariable: invalid data type %s.", szType); }
if (S_OK == hr) { // fill in value range or list of allowed values if specified
*pRow->mszAllowedValueList = '\0'; *pRow->szMin = '\0'; *pRow->szMax = '\0'; *pRow->szStep = '\0';
if (*szValueRange) { hr = HrAddAllowedValue(pRow, szValueRange); }
// successfully added a new row
if (S_OK == hr) { psvc->sst.cRows++; } } } else { hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); TraceTag(ttidUpdiag, "HrAddVariable: data type or default value missing for variable %s.", szName); } } else { hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); TraceTag(ttidUpdiag, "HrAddVariable: variable name not found"); } } else { hr = E_FAIL; TraceTag(ttidUpdiag, "HrAddVariable: max number of rows in state table exceeded"); }
TraceError("HrAddVariable", hr); return hr; }
// input: the state table and variable name
// output: if the variable exists in the state table
// NYI
BOOL IsValidVariable(SST * pSST, TCHAR * szVarName) { return TRUE; }
// parses a line and fill in a new operation of an action
HRESULT HrAddOperation(UPNPSVC * psvc, ACTION * pAction, TCHAR * szLine) { HRESULT hr = S_OK;
DWORD iOperation = pAction->cOperations; if (iOperation < MAX_OPERATIONS) { OPERATION_DATA * pOperation = &pAction->rgOperations[iOperation];
// get the operations's name
TCHAR * pChar = _tcschr(szLine, TEXT('(')); if (pChar) { *pChar ='\0'; lstrcpy(pOperation->szOpName, szLine); szLine = ++pChar;
DWORD nArgs; DWORD nConsts; if (IsStandardOperation(pOperation->szOpName, &nArgs, &nConsts)) { TraceTag(ttidUpdiag, "=== Operation %s ===", pOperation->szOpName); // get the Variable name
if (nArgs+nConsts ==0) { pChar = _tcschr(szLine, TEXT(')')); } else { pChar = _tcschr(szLine, TEXT(',')); }
if (pChar) { *pChar = TEXT('\0'); lstrcpy(pOperation->szVariableName, szLine); szLine = ++pChar;
if(IsValidVariable(&psvc->sst, pOperation->szVariableName)) { TraceTag(ttidUpdiag, "Variable: %s", pOperation->szVariableName);
BOOL fError = FALSE;
// skip the arguments
while (nArgs > 0) { if (nArgs + nConsts == 1) { pChar = _tcschr(szLine, TEXT(')')); } else { pChar = _tcschr(szLine, TEXT(',')); }
if (pChar) { *pChar = TEXT('\0'); TraceTag(ttidUpdiag, "Argument: %s", szLine); szLine = ++pChar; } else { fError = TRUE; TraceTag(ttidUpdiag, "ERROR! HrAddOperation: Syntax error: missing arguments"); break; } nArgs--; }
if (!fError) { TCHAR * pNextConst = pOperation->mszConstantList;
// now get the constants, all in string form
while (nConsts >0) { if (nConsts == 1) { pChar = _tcschr(szLine, TEXT(')')); } else { pChar = _tcschr(szLine, TEXT(',')); }
if (pChar) { *pChar = TEXT('\0'); TraceTag(ttidUpdiag, "Constant: %s", szLine); lstrcpy(pNextConst, szLine);
pNextConst+=lstrlen(pNextConst); pNextConst++;
szLine = ++pChar; } else { fError = TRUE; TraceTag(ttidUpdiag, "ERROR! HrAddOperation: Syntax error: missing constants"); break; }
nConsts--; } *pNextConst = TEXT('\0'); }
if (!fError) { // all is well, increment the count of operations
pAction->cOperations++; } } else { hr = E_INVALIDARG; TraceTag(ttidUpdiag, "ERROR! HrAddOperation: variable %s not in state table", pOperation->szVariableName); } } else { hr = E_INVALIDARG; TraceTag(ttidUpdiag, "ERROR! HrAddOperation: Invalid syntax for operation: %s, affected state variable not found", pOperation->szOpName); } } else { hr = E_INVALIDARG; TraceTag(ttidUpdiag, "ERROR! HrAddOperation: Invalid operation: %s", pOperation->szOpName); } } }
TraceError("HrAddOperation", hr); return hr; }
HRESULT HrAddAction(UPNPSVC * psvc, HINF hinf, TCHAR * szActionName) { HRESULT hr = S_OK; INFCONTEXT ctx;
DWORD iAction = psvc->action_set.cActions; ACTION * pAction = &(psvc->action_set.rgActions[iAction]);
// initialize the new action
lstrcpy(pAction->szActionName, szActionName); pAction->cOperations = 0;
// Loop over the list of operations for this action
hr = HrSetupFindFirstLine(hinf, szActionName, NULL, &ctx); if (S_OK == hr) { do { TCHAR szKey[LINE_LEN]; // LINE_LEN defined in setupapi.h as 256
TCHAR szOpLine[LINE_LEN];
// Retrieve a line from the Action
hr = HrSetupGetStringField(ctx, 0, szKey, celems(szKey), NULL); if(S_OK == hr) { // varify this is an "Operation"
szKey[celems(szKey)-1] = L'\0'; if (lstrcmpi(szKey, TEXT("Operation"))) { TraceTag(ttidUpdiag, "ERROR! HrAddAction: Wrong key in the Operation section: %s", szKey); continue; }
// Query the OperationLine
// get the line text
hr = HrSetupGetLineText(ctx, szOpLine, celems(szOpLine), NULL); if (S_OK == hr) { // Add operations in this action
hr = HrAddOperation(psvc, pAction, szOpLine); } } } while (S_OK == (hr = HrSetupFindNextLine(ctx, &ctx))); }
if (hr == S_FALSE) { // S_FALSE will terminate the loop successfully, so convert it to S_OK
// here.
hr = S_OK; }
// we just successfully added a new action
if (S_OK == hr) psvc->action_set.cActions++;
return hr; }
HRESULT HrLoadSSTAndActionSet(UPNPSVC * psvc) { HRESULT hr = S_OK; HINF hinf = NULL; INFCONTEXT ctx; TCHAR szKey[LINE_LEN]; // LINE_LEN defined in setupapi.h as 256
UINT unErrorLine; hr = HrSetupOpenConfigFile(psvc->szConfigFile, &unErrorLine, &hinf); if (S_OK == hr) { Assert(IsValidHandle(hinf));
// Process [StateTable] section
TraceTag(ttidUpdiag, "Reading StateTable for service %s", psvc->szId);
TCHAR szVariableLine[LINE_LEN]; hr = HrSetupFindFirstLine(hinf, TEXT("StateTable"), NULL, &ctx); if (S_OK == hr) { do { // Retrieve a line from the StateTable section
hr = HrSetupGetStringField(ctx,0,szKey,celems(szKey),NULL); if(S_OK == hr) { // varify this is a "Variable"
szKey[celems(szKey)-1] = L'\0'; if (lstrcmpi(szKey, TEXT("Variable"))) { TraceTag(ttidUpdiag, "Wrong key in the StateTable section: %s", szKey); continue; }
// get the line text
hr = HrSetupGetLineText(ctx, szVariableLine, celems(szVariableLine), NULL); if (S_OK == hr) { // Add variable in this line
hr = HrAddVariable(psvc, szVariableLine); } } } while (S_OK == (hr = HrSetupFindNextLine(ctx, &ctx)));
if (hr == S_FALSE) { // S_FALSE will terminate the loop successfully, so convert it to S_OK
// here.
hr = S_OK; } }
// Process [ActionSet] section
TraceTag(ttidUpdiag, "Reading ActionSet for service %s", psvc->szId);
TCHAR szActionName[LINE_LEN]; hr = HrSetupFindFirstLine(hinf, TEXT("ActionSet"), NULL, &ctx); if (S_OK == hr) { do { // Retrieve a line from the ActionSet section
hr = HrSetupGetStringField(ctx,0,szKey,celems(szKey),NULL); if(S_OK == hr) { // varify this is an "Action"
szKey[celems(szKey)-1] = L'\0'; if (lstrcmpi(szKey, TEXT("Action"))) { TraceTag(ttidUpdiag, "Wrong key in the ActionList section: %s", szKey); continue; }
// Query the ActionName
hr = HrSetupGetLineText(ctx, szActionName, celems(szActionName), NULL); if (S_OK == hr) { // Remove argument list if specified
TCHAR * pChar = _tcschr(szActionName, TEXT('(')); if (pChar) *pChar = '\0';
// Add operations in this action
hr = HrAddAction(psvc, hinf, szActionName); } } } while (S_OK == (hr = HrSetupFindNextLine(ctx, &ctx))); }
if (hr == S_FALSE) { // S_FALSE will terminate the loop successfully, so convert it to S_OK
// here.
hr = S_OK; }
SetupCloseInfFileSafe(hinf); } else { TraceTag(ttidUpdiag, "Failed to open file %s, line = %d", psvc->szConfigFile, unErrorLine); }
TraceError("HrLoadSSTAndActionSet", hr); return hr; }
VOID AttachServiceControl(UPNPSVC *psvc) { // set the control ID for this service from the control url
TCHAR * pChar = _tcschr(psvc->szControlUrl, TEXT('?')); if (pChar) { pChar++; lstrcpy(psvc->szControlId, pChar);
// If it's a demo service then hook up the Demo control
for (DWORD isvc = 0; isvc < c_cDemoSvc; isvc++) { if (!_tcsicmp(c_rgSvc[isvc].szServiceId, psvc->szControlId)) { psvc->psvcDemoCtl = &c_rgSvc[isvc]; TraceTag(ttidUpdiag, "Attached service demo control '%s' to '%s'.", psvc->psvcDemoCtl->szServiceId, psvc->szServiceType); break; } }
if (isvc == c_cDemoSvc) { TraceTag(ttidUpdiag, "No demo service control handler found for id '%s'.", psvc->szControlId); } } else { TraceTag(ttidUpdiag, "Control URL for '%s' doesn't have proper " "format: %s.", psvc->szServiceType, psvc->szControlUrl); } }
void FreeServiceInfo(UPNP_SERVICE_PRIVATE * pusp) { Assert(pusp);
CoTaskMemFree(pusp->wszServiceType); CoTaskMemFree(pusp->wszServiceId); CoTaskMemFree(pusp->wszControlUrl); CoTaskMemFree(pusp->wszEventSubUrl); CoTaskMemFree(pusp->wszScpd); }
HRESULT HrReadServices(LPSTR szDescDocUrl, LPCTSTR szDevConfigFile, IUPnPDevice * pud, UPNPDEV *pdev) { HRESULT hr = S_OK; IUPnPDevicePrivate *pudp = NULL;
hr = pud->QueryInterface(IID_IUPnPDevicePrivate, (LPVOID *)&pudp); if (SUCCEEDED(hr)) { ULONG cServices; UPNP_SERVICE_PRIVATE * rgusp; hr = pudp->GetNumServices(&cServices); if (SUCCEEDED(hr)) { Assert(cServices > 0); }
rgusp = (UPNP_SERVICE_PRIVATE *) CoTaskMemAlloc(cServices * sizeof(UPNP_SERVICE_PRIVATE)); if (rgusp) { ULONG ulSvcs;
hr = pudp->GetServiceInfo(0, cServices, rgusp, &ulSvcs); if (SUCCEEDED(hr)) { DWORD isvc;
pdev->cSvcs = ulSvcs;
for (isvc = 0; isvc < ulSvcs; isvc++) { UPNPSVC * psvc = new UPNPSVC;
ZeroMemory(psvc, sizeof(UPNPSVC));
pdev->rgSvcs[isvc] = psvc;
WcharToTcharInPlace(psvc->szControlUrl, rgusp[isvc].wszControlUrl); WcharToTcharInPlace(psvc->szEvtUrl, rgusp[isvc].wszEventSubUrl); WcharToTcharInPlace(psvc->szScpdUrl, rgusp[isvc].wszScpd); WcharToTcharInPlace(psvc->szServiceType, rgusp[isvc].wszServiceType); WcharToTcharInPlace(psvc->szId, rgusp[isvc].wszServiceId);
// get the service's config file path and name
GetServiceConfigFile(pdev, psvc, szDevConfigFile);
// initialize the service state table and action list
// BUGBUG: allow services with no config file to be created
// (e.g. midi player)
HRESULT hr2; hr2 = HrLoadSSTAndActionSet(psvc);
SSDP_MESSAGE msg = {0}; CHAR szBuffer[256]; CHAR szUdn[256]; CHAR szType[256];
Assert(pdev->szUdn); Assert(psvc->szServiceType);
TszToSzBuf(szUdn, pdev->szUdn, celems(szUdn)); TszToSzBuf(szType, psvc->szServiceType, celems(szType));
msg.iLifeTime = 15000; msg.szLocHeader = szDescDocUrl;
wsprintfA(szBuffer, "%s::%s", szUdn, szType); msg.szType = szType; msg.szUSN = szBuffer;
psvc->hSvc = RegisterService(&msg, 0); if (psvc->hSvc && psvc->hSvc != INVALID_HANDLE_VALUE) { TraceTag(ttidUpdiag, "Successfully registered " "service %s.", psvc->szServiceType); } else { TraceTag(ttidUpdiag, "Failed to register %s as " "a service! Error = %d.", psvc->szServiceType, GetLastError()); }
AttachServiceControl(psvc);
{ CHAR szEvtUrl[INTERNET_MAX_URL_LENGTH]; LPSTR pszEvtUrl;
Assert(psvc->szEvtUrl); pszEvtUrl = SzFromTsz(psvc->szEvtUrl); if (pszEvtUrl) { hr = HrGetRequestUriA(pszEvtUrl, INTERNET_MAX_URL_LENGTH, szEvtUrl); if (SUCCEEDED(hr)) { // convert SST to UPNP_PROPERTY
UPNP_PROPERTY * rgProps; RgPropsFromSst(&psvc->sst, &rgProps);
if(RegisterUpnpEventSource(szEvtUrl, psvc->sst.cRows, rgProps)) { TraceTag(ttidUpdiag, "Successfully registered " "event source %s.", szEvtUrl); } else { TraceTag(ttidUpdiag, "Failed to register %s as " "an event source! Error = %d.", psvc->szEvtUrl, GetLastError()); }
for (DWORD iRow = 0; iRow < psvc->sst.cRows; iRow++) { #ifdef _UNICODE
delete(rgProps[iRow].szName); #else
free(rgProps[iRow].szName); #endif
delete(rgProps[iRow].szValue); } delete [] rgProps; } delete [] pszEvtUrl; } else { TraceTag(ttidUpdiag, "HrReadServices: SzFromTsz failed"); } }
// free the strings allocated by GetServiceInfo() above
FreeServiceInfo(&(rgusp[isvc])); } }
CoTaskMemFree((LPVOID)rgusp); }
ReleaseObj(pudp); }
TraceError("HrReadServices", hr); return hr; }
HRESULT HrReadDevice(BOOL fRoot, LPSTR szDescDocUrl, LPCTSTR szConfigFile, IUPnPDevice * pud) { HRESULT hr; BSTR bstr; BOOL fPop = FALSE;
hr = pud->get_FriendlyName(&bstr); if (SUCCEEDED(hr)) { UPNPDEV * pdev;
TraceTag(ttidUpdiag, "Loading device %S.", bstr);
pdev = new UPNPDEV; ZeroMemory(pdev, sizeof(UPNPDEV));
WcharToTcharInPlace(pdev->szFriendlyName, bstr); SysFreeString(bstr);
pdev->fRoot = fRoot;
pud->get_Type(&bstr); WcharToTcharInPlace(pdev->szDeviceType, bstr); SysFreeString(bstr);
pud->get_UniqueDeviceName(&bstr); WcharToTcharInPlace(pdev->szUdn, bstr); SysFreeString(bstr);
if (FRegisterDeviceAsUpnpService(szDescDocUrl, pdev)) { if (fRoot) { g_params.rgCd[g_params.cCd++] = pdev; } else { PDevCur()->rgDevs[PDevCur()->cDevs++] = pdev; }
PushDev(pdev); fPop = TRUE;
hr = HrReadServices(szDescDocUrl, szConfigFile, pud, pdev); } else { CleanupCd(pdev); } }
// read in the child devices
IUPnPDevices * puds;
puds = NULL; hr = pud->get_Children(&puds); if (SUCCEEDED(hr)) { Assert(puds);
IUnknown * punkEnum;
punkEnum = NULL; hr = puds->get__NewEnum(&punkEnum); if(SUCCEEDED(hr)) { IEnumUnknown * peu;
peu = NULL; hr = punkEnum->QueryInterface(IID_IEnumUnknown, (void**) &peu); if (SUCCEEDED(hr)) { while (S_OK == hr) { IUnknown * punkDevice;
punkDevice = NULL; hr = peu->Next(1, &punkDevice, NULL); if (S_FALSE == hr) { Assert(!punkDevice);
// we're done
} else if (SUCCEEDED(hr)) { Assert(punkDevice);
IUPnPDevice * pudChild;
pudChild = NULL; hr = punkDevice->QueryInterface(IID_IUPnPDevice, (void**) &pudChild); if (SUCCEEDED(hr)) { Assert(pudChild);
hr = HrReadDevice(FALSE, szDescDocUrl, szConfigFile, pudChild);
ReleaseObj(pudChild); }
ReleaseObj(punkDevice); } }
if (S_FALSE == hr) { hr = S_OK; }
ReleaseObj(peu); }
ReleaseObj(punkEnum); }
ReleaseObj(puds); }
if ((!fRoot) && (fPop)) { PopDev(); }
TraceError("HrReadDevice", hr); return hr; }
BOOL DoNewCd(DWORD iCmd, DWORD cArgs, LPTSTR *rgArgs) { UPNPDEV * pdev; UPNPSVC * psvc; HRESULT hr = S_OK;
if ((cArgs == 3) || (cArgs ==2)) { IUPnPDevice * pud = NULL; IUPnPDescriptionDocument * pudd = NULL;
// This is the file name
// Load device from description doc
_tprintf(TEXT("Loading device from doc: %s...\n"), rgArgs[1]);
hr = CoCreateInstance(CLSID_UPnPDescriptionDocument, NULL, CLSCTX_INPROC_SERVER, IID_IUPnPDescriptionDocument, (LPVOID *)&pudd); if (SUCCEEDED(hr)) { Assert(pudd);
LPWSTR pszUrl;
pszUrl = WszFromTsz(rgArgs[1]); if (pszUrl) { BSTR bstrUrl;
bstrUrl = ::SysAllocString(pszUrl); if (bstrUrl) { hr = pudd->Load(bstrUrl); if (SUCCEEDED(hr)) { _tprintf(TEXT("Loaded %s.\n"), rgArgs[1]);
hr = pudd->RootDevice(&pud); if (FAILED(hr)) { TraceTag(ttidUpdiag, "IUPnPDescriptionDocument::RootDevice (URL=%S) failed, hr=%x", pszUrl, hr); pud = NULL; } } else { TraceTag(ttidUpdiag, "Failed to load %S. hr=%x", pszUrl, hr); _tprintf(TEXT("Failed to load %s. hr=%d\n"), rgArgs[1], hr); }
::SysFreeString(bstrUrl); } else { // SysAllocString failed
hr = E_OUTOFMEMORY; } delete [] pszUrl; } else { // WszFromTsz failed
hr = E_OUTOFMEMORY; }
ReleaseObj(pudd); } else { _tprintf(TEXT("Could not create description doc. is upnp.dll registered?\n")); }
if (FAILED(hr)) { Assert(!pud); return FALSE; }
Assert(pud);
// read root device properties into structs
Assert(rgArgs[1]); LPSTR pszDescDocUrl = SzFromTsz(rgArgs[1]); if (pszDescDocUrl) { if (cArgs==2) { hr = HrReadDevice(TRUE, pszDescDocUrl, TEXT(""), pud); } else { hr = HrReadDevice(TRUE, pszDescDocUrl, rgArgs[2], pud); }
delete [] pszDescDocUrl; } else { hr = E_OUTOFMEMORY; } TraceError("DoNewCd", hr);
ReleaseObj(pud);
// Can the ISAPI DLL get more than one request at the same time? If
// so we need to queue control changes to SSTs.
#ifdef NEVER
UPNP_PROPERTY * rgProps;
RgPropsFromSst(&psvc->sst, &rgProps);
if (RegisterUpnpEventSource(psvc->szEvtUrl, psvc->sst.cRows, rgProps)) { } else { TraceTag(ttidUpdiag, "Failed to register %s as an event source! Error = %d.", psvc->szEvtUrl, GetLastError()); } #endif
} else { Usage(iCmd); }
return FALSE; }
BOOL DoSwitchCd(DWORD iCmd, DWORD cArgs, LPTSTR *rgArgs) { Assert(g_ctx.ectx == CTX_ROOT || g_ctx.ectx == CTX_CD);
if (cArgs == 2) { DWORD idev; UPNPDEV * pdev;
idev = _tcstoul(rgArgs[1], NULL, 10);
if (g_ctx.ectx == CTX_CD) { if (idev && idev <= PDevCur()->cDevs && PDevCur()->rgDevs[idev - 1]) { pdev = PDevCur()->rgDevs[idev - 1]; } } else { if (idev && idev <= g_params.cCd && g_params.rgCd[idev - 1]) { pdev = g_params.rgCd[idev - 1]; } }
if (pdev) { PushDev(pdev); } else { _tprintf(TEXT("%d is not a valid CD index!\n"), idev); } } else { Usage(iCmd); }
return FALSE; }
BOOL DoDelCd(DWORD iCmd, DWORD cArgs, LPTSTR *rgArgs) { Assert(g_ctx.ectx == CTX_ROOT);
if (cArgs == 2) { DWORD idev; UPNPDEV * pdev;
idev = _tcstoul(rgArgs[1], NULL, 10);
pdev = g_params.rgCd[idev - 1];
if (idev && idev <= g_params.cCd && pdev) { _tprintf(TEXT("Deleted device %s.\n"), pdev->szFriendlyName); // Move last item into gap and decrement the count
g_params.rgCd[idev - 1] = g_params.rgCd[g_params.cCd - 1]; CleanupCd(pdev); g_params.cCd--; } else { _tprintf(TEXT("%d is not a valid CD index!\n"), idev); } } else { Usage(iCmd); }
return FALSE; }
BOOL DoListDevices(DWORD iCmd, DWORD cArgs, LPTSTR *rgArgs) { DWORD idev;
if (g_ctx.ectx == CTX_ROOT) { _tprintf(TEXT("Listing all Controlled Devices\n")); _tprintf(TEXT("------------------------------\n")); for (idev = 0; idev < g_params.cCd; idev++) { _tprintf(TEXT("%d) %s\n"), idev + 1, g_params.rgCd[idev]->szFriendlyName); }
_tprintf(TEXT("------------------------------\n\n")); } else if (g_ctx.ectx == CTX_CD) { _tprintf(TEXT("Listing all sub-devices of %s\n"), PDevCur()->szFriendlyName); _tprintf(TEXT("------------------------------\n")); for (idev = 0; idev < PDevCur()->cDevs; idev++) { _tprintf(TEXT("%d) %s\n"), idev + 1, PDevCur()->rgDevs[idev]->szFriendlyName); }
_tprintf(TEXT("------------------------------\n\n")); }
return FALSE; }
VOID CleanupCd(UPNPDEV *pcd) { DWORD i;
for (i = 0; i < pcd->cDevs; i++) { CleanupCd(pcd->rgDevs[i]); }
for (i = 0; i < pcd->cSvcs; i++) { CleanupService(pcd->rgSvcs[i]); }
for (i = 0; i < 3; i++) { if (pcd->hSvc[i] && (pcd->hSvc[i] != INVALID_HANDLE_VALUE)) { DeregisterService(pcd->hSvc[i], TRUE); } }
delete pcd; }
|