629 lines
19 KiB
C++
629 lines
19 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1997.
|
|
//
|
|
// File: U P N P R E G . C P P
|
|
//
|
|
// Contents: Device host registration command line tool
|
|
//
|
|
// Notes:
|
|
//
|
|
// Author: danielwe 30 Jun 2000
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
#include "pch.h"
|
|
#pragma hdrstop
|
|
|
|
#include "stdio.h"
|
|
#include "hostp.h"
|
|
#include "hostp_i.c"
|
|
#include "ncstring.h"
|
|
#include "ncbase.h"
|
|
#include "upnphost.h"
|
|
|
|
// These are defined in registrar.cpp as well. Make sure they are in sync
|
|
//
|
|
static const DWORD c_csecDefaultLifetime = 1800;
|
|
static const DWORD c_csecMinLifetime = 900;
|
|
|
|
enum COMMAND
|
|
{
|
|
CMD_NONE,
|
|
CMD_REGISTER,
|
|
CMD_REREGISTER,
|
|
CMD_UNREGISTER,
|
|
};
|
|
|
|
struct PARAMS
|
|
{
|
|
LPWSTR szXmlDescFile;
|
|
BSTR bstrProgId;
|
|
BSTR bstrInitString;
|
|
LPWSTR szInitStringFile;
|
|
BSTR bstrContainerId;
|
|
BSTR bstrResourceDir;
|
|
DWORD csecLifetime;
|
|
LPWSTR szOutputFile;
|
|
BSTR bstrDeviceId;
|
|
BOOL fPermanent;
|
|
};
|
|
|
|
VOID Usage()
|
|
{
|
|
|
|
fprintf(stderr, "UPNPREG: A command line tool used to register, unregister and re-register static UPnP devices.\n");
|
|
fprintf(stderr, "\n");
|
|
fprintf(stderr, "The syntax of this command is:\n");
|
|
fprintf(stderr, "\n");
|
|
fprintf(stderr, "UPNPREG register /F device-description /P ProgID [/I init-string | /T init-string] /C container-id /R resource-path /L lifetime [/O device-identifier-out]\n");
|
|
fprintf(stderr, "UPNPREG unregister /D device-identifier /K permanent\n");
|
|
fprintf(stderr, "UPNPREG reregister /D device-identifier /F device-description /P ProgID [/I init-string | /T init-string] /C container-id /R resource-path /L lifetime\n");
|
|
fprintf(stderr, "\n");
|
|
fprintf(stderr, "/F File containing the XML device description.\n");
|
|
fprintf(stderr, "/P ProgID of the device object that implements IUPnPDeviceControl. This must be an in-proc COM server.\n");
|
|
fprintf(stderr, "/I File containing device specific initialization string [Optional]\n");
|
|
fprintf(stderr, "/T Device specific initialization string [Optional]\n");
|
|
fprintf(stderr, "/C String identifying the process group in which the device belongs.\n");
|
|
fprintf(stderr, "/R Location of the resource directory of the device that contains the icons and the service descriptions\n");
|
|
fprintf(stderr, "/L Lifetime, in seconds, of the device (minimum = 15, default = 30).\n");
|
|
fprintf(stderr, "/O File that the tool will write the device identifier to (if unspecified, it will write to stdout)\n");
|
|
fprintf(stderr, "/D Device identifier returned from a call to UPNPREG register, or a call to IUPnPRegistrar::RegisterDevice()\n");
|
|
fprintf(stderr, "/K Flag to determine if the device should be deleted permanently (TRUE if present)\n");
|
|
|
|
exit(0);
|
|
}
|
|
|
|
VOID WriteIdentifierToFile(BSTR bstrId, LPCWSTR szFile)
|
|
{
|
|
HANDLE hFile;
|
|
LPSTR szaId;
|
|
DWORD cbWritten = 0;
|
|
|
|
CharLowerBuff(bstrId, SysStringLen(bstrId));
|
|
|
|
hFile = CreateFile(szFile, GENERIC_WRITE,
|
|
FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
fprintf(stderr, "Failed to open the output file: '%S'. Error = %d\n",
|
|
szFile, GetLastError());
|
|
|
|
fprintf(stdout, "%S\n", bstrId);
|
|
|
|
return;
|
|
}
|
|
|
|
szaId = SzFromWsz(bstrId);
|
|
|
|
if (!WriteFile(hFile, (LPVOID)szaId, lstrlenA(szaId), &cbWritten, NULL))
|
|
{
|
|
fprintf(stderr, "Failed to write the output file: '%S'. Error = %d\n",
|
|
szFile, GetLastError());
|
|
}
|
|
|
|
delete [] szaId;
|
|
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
BSTR BstrLoadXmlFromFile(LPCWSTR szFile)
|
|
{
|
|
HANDLE hFile;
|
|
HANDLE hMap;
|
|
LPWSTR szData;
|
|
DWORD cbFile;
|
|
LPVOID pvData;
|
|
BSTR bstrRet = NULL;
|
|
|
|
hFile = CreateFile(szFile, GENERIC_READ,
|
|
FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
fprintf(stderr, "Failed to open the file: '%S'. Error = %d\n",
|
|
szFile, GetLastError());
|
|
exit(0);
|
|
}
|
|
|
|
cbFile = GetFileSize(hFile, NULL);
|
|
|
|
hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
fprintf(stderr, "Failed to create file mapping for file: '%S'. Error = %d\n",
|
|
szFile, GetLastError());
|
|
exit(0);
|
|
}
|
|
|
|
szData = new WCHAR[cbFile + 1];
|
|
if (!szData)
|
|
{
|
|
fprintf(stderr, "Out of memory!\n");
|
|
exit(0);
|
|
}
|
|
|
|
pvData = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
|
|
if (!pvData)
|
|
{
|
|
fprintf(stderr, "Failed to map the file: '%S'. Error = %d\n",
|
|
szFile, GetLastError());
|
|
exit(0);
|
|
}
|
|
|
|
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, reinterpret_cast<char*>(pvData),
|
|
cbFile, szData, cbFile);
|
|
szData[cbFile] = 0;
|
|
|
|
UnmapViewOfFile(pvData);
|
|
CloseHandle(hMap);
|
|
CloseHandle(hFile);
|
|
|
|
bstrRet = SysAllocString(szData);
|
|
|
|
delete [] szData;
|
|
|
|
return bstrRet;
|
|
}
|
|
|
|
VOID Execute(COMMAND cmd, PARAMS *pparams)
|
|
{
|
|
HRESULT hr;
|
|
|
|
switch (cmd)
|
|
{
|
|
case CMD_REGISTER:
|
|
IUPnPRegistrar * preg;
|
|
|
|
hr = CoCreateInstance(CLSID_UPnPRegistrar, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_IUPnPRegistrar, (LPVOID *)&preg);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
BSTR bstrId;
|
|
BSTR bstrData;
|
|
LPWSTR szData;
|
|
|
|
bstrData = BstrLoadXmlFromFile(pparams->szXmlDescFile);
|
|
if (bstrData)
|
|
{
|
|
hr = preg->RegisterDevice(bstrData, pparams->bstrProgId,
|
|
pparams->bstrInitString,
|
|
pparams->bstrContainerId,
|
|
pparams->bstrResourceDir,
|
|
pparams->csecLifetime, &bstrId);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
fprintf(stdout, "Successfully registered the device.\n");
|
|
if (!pparams->szOutputFile)
|
|
{
|
|
CharLowerBuff(bstrId, SysStringLen(bstrId));
|
|
fprintf(stdout, "Device identifier is: %S\n", bstrId);
|
|
}
|
|
else
|
|
{
|
|
WriteIdentifierToFile(bstrId, pparams->szOutputFile);
|
|
}
|
|
|
|
SysFreeString(bstrId);
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "Failed to register the device. "
|
|
"Error = %08X\n", hr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "Out of memory!\n");
|
|
exit(0);
|
|
}
|
|
|
|
preg->Release();
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "Failed to create the registrar object! Error = %08X\n",
|
|
hr);
|
|
}
|
|
|
|
break;
|
|
|
|
case CMD_REREGISTER:
|
|
IUPnPReregistrar * prereg;
|
|
|
|
hr = CoCreateInstance(CLSID_UPnPRegistrar, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_IUPnPReregistrar, (LPVOID *)&prereg);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
BSTR bstrData;
|
|
|
|
bstrData = BstrLoadXmlFromFile(pparams->szXmlDescFile);
|
|
if (bstrData)
|
|
{
|
|
hr = prereg->ReregisterDevice(pparams->bstrDeviceId,
|
|
bstrData,
|
|
pparams->bstrProgId,
|
|
pparams->bstrInitString,
|
|
pparams->bstrContainerId,
|
|
pparams->bstrResourceDir,
|
|
pparams->csecLifetime);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
fprintf(stdout, "Successfully re-registered the device.\n");
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "Failed to re-register the device with ID: %S. "
|
|
"Error = %08X\n", pparams->bstrDeviceId, hr);
|
|
}
|
|
}
|
|
|
|
prereg->Release();
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "Failed to create the re-registrar object! Error = %08X\n",
|
|
hr);
|
|
}
|
|
break;
|
|
|
|
case CMD_UNREGISTER:
|
|
IUPnPRegistrar * punreg;
|
|
|
|
hr = CoCreateInstance(CLSID_UPnPRegistrar, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_IUPnPRegistrar, (LPVOID *)&punreg);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = punreg->UnregisterDevice(pparams->bstrDeviceId,
|
|
pparams->fPermanent);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
fprintf(stdout, "Successfully unregistered the device %S.\n",
|
|
pparams->bstrDeviceId);
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "Failed to unregister the device %S. "
|
|
"Error = %08X\n", pparams->bstrDeviceId, hr);
|
|
}
|
|
|
|
punreg->Release();
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "Failed to create the unregistrar object! Error = %08X\n",
|
|
hr);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
AssertSz(FALSE, "Unknown command!");
|
|
break;
|
|
}
|
|
}
|
|
|
|
EXTERN_C
|
|
VOID
|
|
__cdecl
|
|
wmain (
|
|
IN INT argc,
|
|
IN PCWSTR argv[])
|
|
{
|
|
INT iarg;
|
|
COMMAND cmd = CMD_NONE;
|
|
PARAMS params = {0};
|
|
|
|
// Quick short-circuit. Any valid command must have at least 4 args
|
|
//
|
|
if (argc < 4)
|
|
{
|
|
Usage();
|
|
}
|
|
|
|
if (!lstrcmpi(argv[1], L"register"))
|
|
{
|
|
cmd = CMD_REGISTER;
|
|
}
|
|
else if (!lstrcmpi(argv[1], L"reregister"))
|
|
{
|
|
cmd = CMD_REREGISTER;
|
|
}
|
|
else if (!lstrcmpi(argv[1], L"unregister"))
|
|
{
|
|
cmd = CMD_UNREGISTER;
|
|
}
|
|
else
|
|
{
|
|
Usage();
|
|
}
|
|
|
|
Assert(cmd != CMD_NONE);
|
|
|
|
params.csecLifetime = c_csecDefaultLifetime;
|
|
|
|
for (iarg = 2; iarg < argc; )
|
|
{
|
|
if ((argv[iarg][0] != '-') && (argv[iarg][0] != '/'))
|
|
{
|
|
// Flag prefix is missing
|
|
//
|
|
Usage();
|
|
}
|
|
|
|
switch (argv[iarg][1])
|
|
{
|
|
case 'F':
|
|
case 'f':
|
|
if ((argc >= iarg + 2) && (cmd == CMD_REGISTER || cmd == CMD_REREGISTER))
|
|
{
|
|
params.szXmlDescFile = WszDupWsz(argv[iarg + 1]);
|
|
fprintf(stdout, "Got description file: %S\n", params.szXmlDescFile);
|
|
iarg += 2;
|
|
}
|
|
else
|
|
{
|
|
Usage();
|
|
}
|
|
break;
|
|
|
|
case 'P':
|
|
case 'p':
|
|
if ((argc >= iarg + 2) && (cmd == CMD_REGISTER || cmd == CMD_REREGISTER))
|
|
{
|
|
params.bstrProgId = SysAllocString(argv[iarg + 1]);
|
|
fprintf(stdout, "Got prog ID: %S\n", params.bstrProgId);
|
|
iarg += 2;
|
|
}
|
|
else
|
|
{
|
|
Usage();
|
|
}
|
|
break;
|
|
|
|
case 'I':
|
|
case 'i':
|
|
if ((argc >= iarg + 2) &&
|
|
(cmd == CMD_REGISTER || cmd == CMD_REREGISTER) &&
|
|
(!params.bstrInitString))
|
|
{
|
|
params.szInitStringFile = WszDupWsz(argv[iarg + 1]);
|
|
fprintf(stdout, "Got init string file: %S\n", params.szInitStringFile);
|
|
iarg += 2;
|
|
}
|
|
else
|
|
{
|
|
Usage();
|
|
}
|
|
break;
|
|
|
|
case 'T':
|
|
case 't':
|
|
if ((argc >= iarg + 2) &&
|
|
(cmd == CMD_REGISTER || cmd == CMD_REREGISTER) &&
|
|
(!params.szInitStringFile))
|
|
{
|
|
params.bstrInitString = SysAllocString(argv[iarg + 1]);
|
|
fprintf(stdout, "Got init string: %S\n", params.bstrInitString);
|
|
iarg += 2;
|
|
}
|
|
else
|
|
{
|
|
Usage();
|
|
}
|
|
break;
|
|
|
|
case 'C':
|
|
case 'c':
|
|
if ((argc >= iarg + 2) && (cmd == CMD_REGISTER || cmd == CMD_REREGISTER))
|
|
{
|
|
params.bstrContainerId = SysAllocString(argv[iarg + 1]);
|
|
fprintf(stdout, "Got container ID: %S\n", params.bstrContainerId);
|
|
iarg += 2;
|
|
}
|
|
else
|
|
{
|
|
Usage();
|
|
}
|
|
break;
|
|
|
|
case 'R':
|
|
case 'r':
|
|
if ((argc >= iarg + 2) && (cmd == CMD_REGISTER || cmd == CMD_REREGISTER))
|
|
{
|
|
params.bstrResourceDir = SysAllocString(argv[iarg + 1]);
|
|
fprintf(stdout, "Got resource dir: %S\n", params.bstrResourceDir);
|
|
iarg += 2;
|
|
}
|
|
else
|
|
{
|
|
Usage();
|
|
}
|
|
break;
|
|
|
|
case 'L':
|
|
case 'l':
|
|
if ((argc >= iarg + 2) && (cmd == CMD_REGISTER || cmd == CMD_REREGISTER))
|
|
{
|
|
params.csecLifetime = wcstoul(argv[iarg + 1], NULL, 10);
|
|
params.csecLifetime = max(params.csecLifetime, c_csecMinLifetime);
|
|
fprintf(stdout, "Got lifetime: %d\n", params.csecLifetime);
|
|
iarg += 2;
|
|
}
|
|
else
|
|
{
|
|
Usage();
|
|
}
|
|
break;
|
|
|
|
case 'O':
|
|
case 'o':
|
|
if ((argc >= iarg + 2) && (cmd == CMD_REGISTER))
|
|
{
|
|
params.szOutputFile = WszDupWsz(argv[iarg + 1]);
|
|
fprintf(stdout, "Got output file: %S\n", params.szOutputFile);
|
|
iarg += 2;
|
|
}
|
|
else
|
|
{
|
|
Usage();
|
|
}
|
|
break;
|
|
|
|
case 'D':
|
|
case 'd':
|
|
if ((argc >= iarg + 2) && (cmd == CMD_UNREGISTER || cmd == CMD_REREGISTER))
|
|
{
|
|
params.bstrDeviceId = SysAllocString(argv[iarg + 1]);
|
|
fprintf(stdout, "Got device ID: %S\n", params.bstrDeviceId);
|
|
iarg += 2;
|
|
}
|
|
else
|
|
{
|
|
Usage();
|
|
}
|
|
break;
|
|
|
|
case 'K':
|
|
case 'k':
|
|
if (cmd == CMD_UNREGISTER)
|
|
{
|
|
params.fPermanent = TRUE;
|
|
fprintf(stdout, "Got permanent = TRUE\n");
|
|
iarg++;
|
|
}
|
|
else
|
|
{
|
|
Usage();
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Usage();
|
|
break;
|
|
}
|
|
}
|
|
|
|
fprintf(stdout, "Got all params.. Now validating...\n");
|
|
|
|
// Now validate params
|
|
//
|
|
|
|
switch (cmd)
|
|
{
|
|
case CMD_REGISTER:
|
|
if ((!params.szXmlDescFile) ||
|
|
(!params.bstrProgId) ||
|
|
(!params.bstrContainerId) ||
|
|
((!params.szInitStringFile) && (!params.bstrInitString)) ||
|
|
(!params.bstrResourceDir))
|
|
{
|
|
Usage();
|
|
}
|
|
|
|
if (!FFileExists(params.szXmlDescFile, FALSE))
|
|
{
|
|
fprintf(stderr, "Description file '%S' does not exist!\n",
|
|
params.szXmlDescFile);
|
|
exit(0);
|
|
}
|
|
|
|
if (!FFileExists(params.bstrResourceDir, TRUE))
|
|
{
|
|
fprintf(stderr, "Resource directory '%S' does not exist!\n",
|
|
params.bstrResourceDir);
|
|
exit(0);
|
|
}
|
|
|
|
// Load the init string from a file if specified
|
|
//
|
|
if (params.szInitStringFile)
|
|
{
|
|
|
|
if (!FFileExists(params.szInitStringFile, TRUE))
|
|
{
|
|
fprintf(stderr, "Init string file '%S' does not exist!\n",
|
|
params.szInitStringFile);
|
|
exit(0);
|
|
}
|
|
|
|
params.bstrInitString = BstrLoadXmlFromFile(params.szInitStringFile);
|
|
if (!params.bstrInitString)
|
|
{
|
|
fprintf(stderr, "Out of memory!\n");
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case CMD_REREGISTER:
|
|
if ((!params.szXmlDescFile) ||
|
|
(!params.bstrDeviceId) ||
|
|
(!params.bstrProgId) ||
|
|
((!params.szInitStringFile) && (!params.bstrInitString)) ||
|
|
(!params.bstrContainerId) ||
|
|
(!params.bstrResourceDir))
|
|
{
|
|
Usage();
|
|
}
|
|
|
|
if (!FFileExists(params.szXmlDescFile, FALSE))
|
|
{
|
|
fprintf(stderr, "Description file '%S' does not exist!\n",
|
|
params.szXmlDescFile);
|
|
exit(0);
|
|
}
|
|
|
|
if (!FFileExists(params.bstrResourceDir, TRUE))
|
|
{
|
|
fprintf(stderr, "Resource directory '%S' does not exist!\n",
|
|
params.bstrResourceDir);
|
|
exit(0);
|
|
}
|
|
|
|
// Load the init string from a file if specified
|
|
//
|
|
if (params.szInitStringFile)
|
|
{
|
|
|
|
if (!FFileExists(params.szInitStringFile, TRUE))
|
|
{
|
|
fprintf(stderr, "Init string file '%S' does not exist!\n",
|
|
params.szInitStringFile);
|
|
exit(0);
|
|
}
|
|
|
|
params.bstrInitString = BstrLoadXmlFromFile(params.szInitStringFile);
|
|
if (!params.bstrInitString)
|
|
{
|
|
fprintf(stderr, "Out of memory!\n");
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case CMD_UNREGISTER:
|
|
if (!params.bstrDeviceId)
|
|
{
|
|
Usage();
|
|
}
|
|
break;
|
|
}
|
|
|
|
fprintf(stdout, "All params are valid.\n");
|
|
|
|
CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
|
CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL);
|
|
|
|
Execute(cmd, ¶ms);
|
|
|
|
CoUninitialize();
|
|
}
|
|
|