Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

628 lines
19 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: U P N P R E G . C P P
  7. //
  8. // Contents: Device host registration command line tool
  9. //
  10. // Notes:
  11. //
  12. // Author: danielwe 30 Jun 2000
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include "stdio.h"
  18. #include "hostp.h"
  19. #include "hostp_i.c"
  20. #include "ncstring.h"
  21. #include "ncbase.h"
  22. #include "upnphost.h"
  23. // These are defined in registrar.cpp as well. Make sure they are in sync
  24. //
  25. static const DWORD c_csecDefaultLifetime = 1800;
  26. static const DWORD c_csecMinLifetime = 900;
  27. enum COMMAND
  28. {
  29. CMD_NONE,
  30. CMD_REGISTER,
  31. CMD_REREGISTER,
  32. CMD_UNREGISTER,
  33. };
  34. struct PARAMS
  35. {
  36. LPWSTR szXmlDescFile;
  37. BSTR bstrProgId;
  38. BSTR bstrInitString;
  39. LPWSTR szInitStringFile;
  40. BSTR bstrContainerId;
  41. BSTR bstrResourceDir;
  42. DWORD csecLifetime;
  43. LPWSTR szOutputFile;
  44. BSTR bstrDeviceId;
  45. BOOL fPermanent;
  46. };
  47. VOID Usage()
  48. {
  49. fprintf(stderr, "UPNPREG: A command line tool used to register, unregister and re-register static UPnP devices.\n");
  50. fprintf(stderr, "\n");
  51. fprintf(stderr, "The syntax of this command is:\n");
  52. fprintf(stderr, "\n");
  53. 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");
  54. fprintf(stderr, "UPNPREG unregister /D device-identifier /K permanent\n");
  55. 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");
  56. fprintf(stderr, "\n");
  57. fprintf(stderr, "/F File containing the XML device description.\n");
  58. fprintf(stderr, "/P ProgID of the device object that implements IUPnPDeviceControl. This must be an in-proc COM server.\n");
  59. fprintf(stderr, "/I File containing device specific initialization string [Optional]\n");
  60. fprintf(stderr, "/T Device specific initialization string [Optional]\n");
  61. fprintf(stderr, "/C String identifying the process group in which the device belongs.\n");
  62. fprintf(stderr, "/R Location of the resource directory of the device that contains the icons and the service descriptions\n");
  63. fprintf(stderr, "/L Lifetime, in seconds, of the device (minimum = 15, default = 30).\n");
  64. fprintf(stderr, "/O File that the tool will write the device identifier to (if unspecified, it will write to stdout)\n");
  65. fprintf(stderr, "/D Device identifier returned from a call to UPNPREG register, or a call to IUPnPRegistrar::RegisterDevice()\n");
  66. fprintf(stderr, "/K Flag to determine if the device should be deleted permanently (TRUE if present)\n");
  67. exit(0);
  68. }
  69. VOID WriteIdentifierToFile(BSTR bstrId, LPCWSTR szFile)
  70. {
  71. HANDLE hFile;
  72. LPSTR szaId;
  73. DWORD cbWritten = 0;
  74. CharLowerBuff(bstrId, SysStringLen(bstrId));
  75. hFile = CreateFile(szFile, GENERIC_WRITE,
  76. FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
  77. FILE_ATTRIBUTE_NORMAL, NULL);
  78. if (hFile == INVALID_HANDLE_VALUE)
  79. {
  80. fprintf(stderr, "Failed to open the output file: '%S'. Error = %d\n",
  81. szFile, GetLastError());
  82. fprintf(stdout, "%S\n", bstrId);
  83. return;
  84. }
  85. szaId = SzFromWsz(bstrId);
  86. if (!WriteFile(hFile, (LPVOID)szaId, lstrlenA(szaId), &cbWritten, NULL))
  87. {
  88. fprintf(stderr, "Failed to write the output file: '%S'. Error = %d\n",
  89. szFile, GetLastError());
  90. }
  91. delete [] szaId;
  92. CloseHandle(hFile);
  93. }
  94. BSTR BstrLoadXmlFromFile(LPCWSTR szFile)
  95. {
  96. HANDLE hFile;
  97. HANDLE hMap;
  98. LPWSTR szData;
  99. DWORD cbFile;
  100. LPVOID pvData;
  101. BSTR bstrRet = NULL;
  102. hFile = CreateFile(szFile, GENERIC_READ,
  103. FILE_SHARE_READ, NULL, OPEN_EXISTING,
  104. FILE_ATTRIBUTE_NORMAL, NULL);
  105. if (hFile == INVALID_HANDLE_VALUE)
  106. {
  107. fprintf(stderr, "Failed to open the file: '%S'. Error = %d\n",
  108. szFile, GetLastError());
  109. exit(0);
  110. }
  111. cbFile = GetFileSize(hFile, NULL);
  112. hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
  113. if (hFile == INVALID_HANDLE_VALUE)
  114. {
  115. fprintf(stderr, "Failed to create file mapping for file: '%S'. Error = %d\n",
  116. szFile, GetLastError());
  117. exit(0);
  118. }
  119. szData = new WCHAR[cbFile + 1];
  120. if (!szData)
  121. {
  122. fprintf(stderr, "Out of memory!\n");
  123. exit(0);
  124. }
  125. pvData = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
  126. if (!pvData)
  127. {
  128. fprintf(stderr, "Failed to map the file: '%S'. Error = %d\n",
  129. szFile, GetLastError());
  130. exit(0);
  131. }
  132. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, reinterpret_cast<char*>(pvData),
  133. cbFile, szData, cbFile);
  134. szData[cbFile] = 0;
  135. UnmapViewOfFile(pvData);
  136. CloseHandle(hMap);
  137. CloseHandle(hFile);
  138. bstrRet = SysAllocString(szData);
  139. delete [] szData;
  140. return bstrRet;
  141. }
  142. VOID Execute(COMMAND cmd, PARAMS *pparams)
  143. {
  144. HRESULT hr;
  145. switch (cmd)
  146. {
  147. case CMD_REGISTER:
  148. IUPnPRegistrar * preg;
  149. hr = CoCreateInstance(CLSID_UPnPRegistrar, NULL, CLSCTX_LOCAL_SERVER,
  150. IID_IUPnPRegistrar, (LPVOID *)&preg);
  151. if (SUCCEEDED(hr))
  152. {
  153. BSTR bstrId;
  154. BSTR bstrData;
  155. LPWSTR szData;
  156. bstrData = BstrLoadXmlFromFile(pparams->szXmlDescFile);
  157. if (bstrData)
  158. {
  159. hr = preg->RegisterDevice(bstrData, pparams->bstrProgId,
  160. pparams->bstrInitString,
  161. pparams->bstrContainerId,
  162. pparams->bstrResourceDir,
  163. pparams->csecLifetime, &bstrId);
  164. if (SUCCEEDED(hr))
  165. {
  166. fprintf(stdout, "Successfully registered the device.\n");
  167. if (!pparams->szOutputFile)
  168. {
  169. CharLowerBuff(bstrId, SysStringLen(bstrId));
  170. fprintf(stdout, "Device identifier is: %S\n", bstrId);
  171. }
  172. else
  173. {
  174. WriteIdentifierToFile(bstrId, pparams->szOutputFile);
  175. }
  176. SysFreeString(bstrId);
  177. }
  178. else
  179. {
  180. fprintf(stderr, "Failed to register the device. "
  181. "Error = %08X\n", hr);
  182. }
  183. }
  184. else
  185. {
  186. fprintf(stderr, "Out of memory!\n");
  187. exit(0);
  188. }
  189. preg->Release();
  190. }
  191. else
  192. {
  193. fprintf(stderr, "Failed to create the registrar object! Error = %08X\n",
  194. hr);
  195. }
  196. break;
  197. case CMD_REREGISTER:
  198. IUPnPReregistrar * prereg;
  199. hr = CoCreateInstance(CLSID_UPnPRegistrar, NULL, CLSCTX_LOCAL_SERVER,
  200. IID_IUPnPReregistrar, (LPVOID *)&prereg);
  201. if (SUCCEEDED(hr))
  202. {
  203. BSTR bstrData;
  204. bstrData = BstrLoadXmlFromFile(pparams->szXmlDescFile);
  205. if (bstrData)
  206. {
  207. hr = prereg->ReregisterDevice(pparams->bstrDeviceId,
  208. bstrData,
  209. pparams->bstrProgId,
  210. pparams->bstrInitString,
  211. pparams->bstrContainerId,
  212. pparams->bstrResourceDir,
  213. pparams->csecLifetime);
  214. if (SUCCEEDED(hr))
  215. {
  216. fprintf(stdout, "Successfully re-registered the device.\n");
  217. }
  218. else
  219. {
  220. fprintf(stderr, "Failed to re-register the device with ID: %S. "
  221. "Error = %08X\n", pparams->bstrDeviceId, hr);
  222. }
  223. }
  224. prereg->Release();
  225. }
  226. else
  227. {
  228. fprintf(stderr, "Failed to create the re-registrar object! Error = %08X\n",
  229. hr);
  230. }
  231. break;
  232. case CMD_UNREGISTER:
  233. IUPnPRegistrar * punreg;
  234. hr = CoCreateInstance(CLSID_UPnPRegistrar, NULL, CLSCTX_LOCAL_SERVER,
  235. IID_IUPnPRegistrar, (LPVOID *)&punreg);
  236. if (SUCCEEDED(hr))
  237. {
  238. hr = punreg->UnregisterDevice(pparams->bstrDeviceId,
  239. pparams->fPermanent);
  240. if (SUCCEEDED(hr))
  241. {
  242. fprintf(stdout, "Successfully unregistered the device %S.\n",
  243. pparams->bstrDeviceId);
  244. }
  245. else
  246. {
  247. fprintf(stderr, "Failed to unregister the device %S. "
  248. "Error = %08X\n", pparams->bstrDeviceId, hr);
  249. }
  250. punreg->Release();
  251. }
  252. else
  253. {
  254. fprintf(stderr, "Failed to create the unregistrar object! Error = %08X\n",
  255. hr);
  256. }
  257. break;
  258. default:
  259. AssertSz(FALSE, "Unknown command!");
  260. break;
  261. }
  262. }
  263. EXTERN_C
  264. VOID
  265. __cdecl
  266. wmain (
  267. IN INT argc,
  268. IN PCWSTR argv[])
  269. {
  270. INT iarg;
  271. COMMAND cmd = CMD_NONE;
  272. PARAMS params = {0};
  273. // Quick short-circuit. Any valid command must have at least 4 args
  274. //
  275. if (argc < 4)
  276. {
  277. Usage();
  278. }
  279. if (!lstrcmpi(argv[1], L"register"))
  280. {
  281. cmd = CMD_REGISTER;
  282. }
  283. else if (!lstrcmpi(argv[1], L"reregister"))
  284. {
  285. cmd = CMD_REREGISTER;
  286. }
  287. else if (!lstrcmpi(argv[1], L"unregister"))
  288. {
  289. cmd = CMD_UNREGISTER;
  290. }
  291. else
  292. {
  293. Usage();
  294. }
  295. Assert(cmd != CMD_NONE);
  296. params.csecLifetime = c_csecDefaultLifetime;
  297. for (iarg = 2; iarg < argc; )
  298. {
  299. if ((argv[iarg][0] != '-') && (argv[iarg][0] != '/'))
  300. {
  301. // Flag prefix is missing
  302. //
  303. Usage();
  304. }
  305. switch (argv[iarg][1])
  306. {
  307. case 'F':
  308. case 'f':
  309. if ((argc >= iarg + 2) && (cmd == CMD_REGISTER || cmd == CMD_REREGISTER))
  310. {
  311. params.szXmlDescFile = WszDupWsz(argv[iarg + 1]);
  312. fprintf(stdout, "Got description file: %S\n", params.szXmlDescFile);
  313. iarg += 2;
  314. }
  315. else
  316. {
  317. Usage();
  318. }
  319. break;
  320. case 'P':
  321. case 'p':
  322. if ((argc >= iarg + 2) && (cmd == CMD_REGISTER || cmd == CMD_REREGISTER))
  323. {
  324. params.bstrProgId = SysAllocString(argv[iarg + 1]);
  325. fprintf(stdout, "Got prog ID: %S\n", params.bstrProgId);
  326. iarg += 2;
  327. }
  328. else
  329. {
  330. Usage();
  331. }
  332. break;
  333. case 'I':
  334. case 'i':
  335. if ((argc >= iarg + 2) &&
  336. (cmd == CMD_REGISTER || cmd == CMD_REREGISTER) &&
  337. (!params.bstrInitString))
  338. {
  339. params.szInitStringFile = WszDupWsz(argv[iarg + 1]);
  340. fprintf(stdout, "Got init string file: %S\n", params.szInitStringFile);
  341. iarg += 2;
  342. }
  343. else
  344. {
  345. Usage();
  346. }
  347. break;
  348. case 'T':
  349. case 't':
  350. if ((argc >= iarg + 2) &&
  351. (cmd == CMD_REGISTER || cmd == CMD_REREGISTER) &&
  352. (!params.szInitStringFile))
  353. {
  354. params.bstrInitString = SysAllocString(argv[iarg + 1]);
  355. fprintf(stdout, "Got init string: %S\n", params.bstrInitString);
  356. iarg += 2;
  357. }
  358. else
  359. {
  360. Usage();
  361. }
  362. break;
  363. case 'C':
  364. case 'c':
  365. if ((argc >= iarg + 2) && (cmd == CMD_REGISTER || cmd == CMD_REREGISTER))
  366. {
  367. params.bstrContainerId = SysAllocString(argv[iarg + 1]);
  368. fprintf(stdout, "Got container ID: %S\n", params.bstrContainerId);
  369. iarg += 2;
  370. }
  371. else
  372. {
  373. Usage();
  374. }
  375. break;
  376. case 'R':
  377. case 'r':
  378. if ((argc >= iarg + 2) && (cmd == CMD_REGISTER || cmd == CMD_REREGISTER))
  379. {
  380. params.bstrResourceDir = SysAllocString(argv[iarg + 1]);
  381. fprintf(stdout, "Got resource dir: %S\n", params.bstrResourceDir);
  382. iarg += 2;
  383. }
  384. else
  385. {
  386. Usage();
  387. }
  388. break;
  389. case 'L':
  390. case 'l':
  391. if ((argc >= iarg + 2) && (cmd == CMD_REGISTER || cmd == CMD_REREGISTER))
  392. {
  393. params.csecLifetime = wcstoul(argv[iarg + 1], NULL, 10);
  394. params.csecLifetime = max(params.csecLifetime, c_csecMinLifetime);
  395. fprintf(stdout, "Got lifetime: %d\n", params.csecLifetime);
  396. iarg += 2;
  397. }
  398. else
  399. {
  400. Usage();
  401. }
  402. break;
  403. case 'O':
  404. case 'o':
  405. if ((argc >= iarg + 2) && (cmd == CMD_REGISTER))
  406. {
  407. params.szOutputFile = WszDupWsz(argv[iarg + 1]);
  408. fprintf(stdout, "Got output file: %S\n", params.szOutputFile);
  409. iarg += 2;
  410. }
  411. else
  412. {
  413. Usage();
  414. }
  415. break;
  416. case 'D':
  417. case 'd':
  418. if ((argc >= iarg + 2) && (cmd == CMD_UNREGISTER || cmd == CMD_REREGISTER))
  419. {
  420. params.bstrDeviceId = SysAllocString(argv[iarg + 1]);
  421. fprintf(stdout, "Got device ID: %S\n", params.bstrDeviceId);
  422. iarg += 2;
  423. }
  424. else
  425. {
  426. Usage();
  427. }
  428. break;
  429. case 'K':
  430. case 'k':
  431. if (cmd == CMD_UNREGISTER)
  432. {
  433. params.fPermanent = TRUE;
  434. fprintf(stdout, "Got permanent = TRUE\n");
  435. iarg++;
  436. }
  437. else
  438. {
  439. Usage();
  440. }
  441. break;
  442. default:
  443. Usage();
  444. break;
  445. }
  446. }
  447. fprintf(stdout, "Got all params.. Now validating...\n");
  448. // Now validate params
  449. //
  450. switch (cmd)
  451. {
  452. case CMD_REGISTER:
  453. if ((!params.szXmlDescFile) ||
  454. (!params.bstrProgId) ||
  455. (!params.bstrContainerId) ||
  456. ((!params.szInitStringFile) && (!params.bstrInitString)) ||
  457. (!params.bstrResourceDir))
  458. {
  459. Usage();
  460. }
  461. if (!FFileExists(params.szXmlDescFile, FALSE))
  462. {
  463. fprintf(stderr, "Description file '%S' does not exist!\n",
  464. params.szXmlDescFile);
  465. exit(0);
  466. }
  467. if (!FFileExists(params.bstrResourceDir, TRUE))
  468. {
  469. fprintf(stderr, "Resource directory '%S' does not exist!\n",
  470. params.bstrResourceDir);
  471. exit(0);
  472. }
  473. // Load the init string from a file if specified
  474. //
  475. if (params.szInitStringFile)
  476. {
  477. if (!FFileExists(params.szInitStringFile, TRUE))
  478. {
  479. fprintf(stderr, "Init string file '%S' does not exist!\n",
  480. params.szInitStringFile);
  481. exit(0);
  482. }
  483. params.bstrInitString = BstrLoadXmlFromFile(params.szInitStringFile);
  484. if (!params.bstrInitString)
  485. {
  486. fprintf(stderr, "Out of memory!\n");
  487. exit(0);
  488. }
  489. }
  490. break;
  491. case CMD_REREGISTER:
  492. if ((!params.szXmlDescFile) ||
  493. (!params.bstrDeviceId) ||
  494. (!params.bstrProgId) ||
  495. ((!params.szInitStringFile) && (!params.bstrInitString)) ||
  496. (!params.bstrContainerId) ||
  497. (!params.bstrResourceDir))
  498. {
  499. Usage();
  500. }
  501. if (!FFileExists(params.szXmlDescFile, FALSE))
  502. {
  503. fprintf(stderr, "Description file '%S' does not exist!\n",
  504. params.szXmlDescFile);
  505. exit(0);
  506. }
  507. if (!FFileExists(params.bstrResourceDir, TRUE))
  508. {
  509. fprintf(stderr, "Resource directory '%S' does not exist!\n",
  510. params.bstrResourceDir);
  511. exit(0);
  512. }
  513. // Load the init string from a file if specified
  514. //
  515. if (params.szInitStringFile)
  516. {
  517. if (!FFileExists(params.szInitStringFile, TRUE))
  518. {
  519. fprintf(stderr, "Init string file '%S' does not exist!\n",
  520. params.szInitStringFile);
  521. exit(0);
  522. }
  523. params.bstrInitString = BstrLoadXmlFromFile(params.szInitStringFile);
  524. if (!params.bstrInitString)
  525. {
  526. fprintf(stderr, "Out of memory!\n");
  527. exit(0);
  528. }
  529. }
  530. break;
  531. case CMD_UNREGISTER:
  532. if (!params.bstrDeviceId)
  533. {
  534. Usage();
  535. }
  536. break;
  537. }
  538. fprintf(stdout, "All params are valid.\n");
  539. CoInitializeEx(NULL, COINIT_MULTITHREADED);
  540. CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE,
  541. RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL);
  542. Execute(cmd, &params);
  543. CoUninitialize();
  544. }