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.

311 lines
8.5 KiB

  1. #include <tchar.h>
  2. #include <windows.h>
  3. #include <windowsx.h>
  4. #include <objbase.h>
  5. #include <stdlib.h>
  6. #include <stdarg.h>
  7. #include <wia.h>
  8. #include <stdio.h>
  9. #ifdef _DEBUG
  10. #define TRACE(x) Trace x
  11. #else
  12. #define TRACE(x) Trace x
  13. #endif
  14. #define RELEASE(x)\
  15. do {\
  16. if((x)) {\
  17. (x)->Release(); \
  18. (x) = NULL;\
  19. }\
  20. }while(0)
  21. #define REQUIRE(x)\
  22. do {\
  23. if(!(x)) {\
  24. TRACE((_T("%hs(%d): %hs failed with LastError() = %d\r\n"),\
  25. __FILE__, __LINE__, #x, GetLastError()));\
  26. goto Cleanup;\
  27. }\
  28. } while(0)
  29. #define REQUIRE_S_OK(x)\
  30. do {\
  31. hr = (x);\
  32. \
  33. if(hr != S_OK) {\
  34. TRACE((_T("%hs(%d): %hs failed with hr = %x\r\n"),\
  35. __FILE__, __LINE__, #x, hr));\
  36. goto Cleanup;\
  37. }\
  38. } while(0)
  39. #define REQUIRE_SUCCESS(x)\
  40. do {\
  41. DWORD dwResult = (x);\
  42. \
  43. if(dwResult != ERROR_SUCCESS) {\
  44. TRACE((_T("%hs(%d): %hs failed with status = %x\r\n"),\
  45. __FILE__, __LINE__, #x, dwResult));\
  46. goto Cleanup;\
  47. }\
  48. } while(0)
  49. void Trace(LPCTSTR fmt, ...)
  50. {
  51. TCHAR buffer[2048];
  52. va_list marker;
  53. va_start(marker, fmt);
  54. wvsprintf(buffer, fmt, marker);
  55. printf("\nError: %ws", buffer);
  56. }
  57. struct regVals_t {
  58. ULONG propId;
  59. LPWSTR propName;
  60. } regVals[] = {
  61. {WIA_DIP_DEV_ID, WIA_DIP_DEV_ID_STR},
  62. {WIA_DIP_VEND_DESC, WIA_DIP_VEND_DESC_STR},
  63. {WIA_DIP_DEV_DESC, WIA_DIP_DEV_DESC_STR},
  64. {WIA_DIP_DEV_TYPE, WIA_DIP_DEV_TYPE_STR},
  65. {WIA_DIP_PORT_NAME, WIA_DIP_PORT_NAME_STR},
  66. {WIA_DIP_DEV_NAME, WIA_DIP_DEV_NAME_STR},
  67. {WIA_DIP_SERVER_NAME, WIA_DIP_SERVER_NAME_STR},
  68. {WIA_DIP_REMOTE_DEV_ID, WIA_DIP_REMOTE_DEV_ID_STR},
  69. {WIA_DIP_UI_CLSID, WIA_DIP_UI_CLSID_STR}
  70. };
  71. #define NREGVALS (sizeof(regVals) / sizeof(regVals[0]))
  72. HRESULT RegisterRemoteScanners(LPCWSTR servername)
  73. {
  74. HRESULT hr;
  75. IWiaDevMgr *pDevMgr = NULL;
  76. IEnumWIA_DEV_INFO *pEnumInfo = NULL;
  77. IWiaPropertyStorage *pWiaPropStg = NULL;
  78. COSERVERINFO csi;
  79. HKEY hDevList = NULL;
  80. HKEY hKey = NULL;
  81. MULTI_QI mq[1];
  82. ZeroMemory(&csi, sizeof(csi));
  83. csi.pAuthInfo = NULL;
  84. csi.pwszName = SysAllocString(servername);
  85. mq[0].hr = S_OK;
  86. mq[0].pIID = &IID_IWiaDevMgr;
  87. mq[0].pItf = NULL;
  88. REQUIRE_S_OK(CoCreateInstanceEx(CLSID_WiaDevMgr, NULL, CLSCTX_REMOTE_SERVER,
  89. &csi, 1, mq));
  90. pDevMgr = (IWiaDevMgr *)mq[0].pItf;
  91. REQUIRE_SUCCESS(RegCreateKeyEx(
  92. HKEY_LOCAL_MACHINE,
  93. _T("SYSTEM\\CurrentControlSet\\Control\\StillImage\\DevList"),
  94. 0,
  95. NULL,
  96. REG_OPTION_NON_VOLATILE,
  97. KEY_ALL_ACCESS,
  98. NULL,
  99. &hDevList,
  100. NULL));
  101. //
  102. // Enumerate all devices scanner
  103. //
  104. REQUIRE_S_OK(pDevMgr->EnumDeviceInfo(0, &pEnumInfo));
  105. while(pEnumInfo->Next(1, &pWiaPropStg, NULL) == S_OK)
  106. {
  107. PROPSPEC ps[NREGVALS];
  108. PROPVARIANT pv[NREGVALS];
  109. WCHAR keyname[MAX_PATH];
  110. WCHAR *p;
  111. int i;
  112. ZeroMemory(pv, sizeof(pv));
  113. for(i = 0; i < NREGVALS; i++) {
  114. ps[i].ulKind = PRSPEC_PROPID;
  115. ps[i].propid = regVals[i].propId;
  116. }
  117. REQUIRE_S_OK(pWiaPropStg->ReadMultiple(
  118. sizeof(ps) / sizeof(ps[0]),
  119. ps,
  120. pv));
  121. //
  122. // Skip any remote devices (anything other than "local"
  123. // in server name field
  124. //
  125. for(i = 0; i < NREGVALS; i++) {
  126. if(regVals[i].propId == WIA_DIP_SERVER_NAME) {
  127. if(wcscmp(pv[i].bstrVal, L"local")) {
  128. goto SkipDevice;
  129. }
  130. }
  131. }
  132. //
  133. // pv[0] consists of device ID and "\NNN", replace "\" with ".", prepend target machine name
  134. //
  135. p = pv[0].bstrVal;
  136. wcscpy(keyname, servername);
  137. wcscat(keyname, L".");
  138. while(*p && *p != L'\\')
  139. {
  140. p++;
  141. }
  142. REQUIRE(*p == L'\\');
  143. REQUIRE(*(++p) != L'\0');
  144. wcscat(keyname, p);
  145. //
  146. // Create device key and populate values
  147. //
  148. REQUIRE_SUCCESS(RegCreateKeyExW(
  149. hDevList,
  150. keyname,
  151. 0,
  152. NULL,
  153. REG_OPTION_NON_VOLATILE,
  154. KEY_ALL_ACCESS,
  155. NULL,
  156. &hKey,
  157. NULL));
  158. for(i = 0; i < NREGVALS; i++) {
  159. switch(pv[i].vt) {
  160. case VT_BSTR:
  161. if(regVals[i].propId == WIA_DIP_SERVER_NAME) {
  162. //
  163. // Server name is reported as "local",
  164. // we need to set it to the actual server name
  165. //
  166. REQUIRE_SUCCESS(RegSetValueExW(
  167. hKey,
  168. regVals[i].propName,
  169. 0,
  170. REG_SZ,
  171. (CONST BYTE *)servername,
  172. wcslen(servername) * sizeof(WCHAR)));
  173. } else {
  174. //
  175. // All other values we simply copy
  176. //
  177. REQUIRE_SUCCESS(RegSetValueExW(
  178. hKey,
  179. regVals[i].propName,
  180. 0,
  181. REG_SZ,
  182. (CONST BYTE *)pv[i].bstrVal,
  183. wcslen(pv[i].bstrVal) * sizeof(WCHAR)));
  184. }
  185. break;
  186. case VT_I4:
  187. REQUIRE_SUCCESS(RegSetValueExW(
  188. hKey,
  189. regVals[i].propName,
  190. 0,
  191. REG_DWORD,
  192. (CONST BYTE *)&pv[i].lVal,
  193. sizeof(DWORD)));
  194. break;
  195. default:
  196. TRACE((_T("Unexpected property type: %d\n"), pv[i].vt));
  197. break;
  198. }
  199. PropVariantClear(pv + i);
  200. }
  201. RegCloseKey(hKey);
  202. SkipDevice:
  203. RELEASE(pWiaPropStg);
  204. }
  205. Cleanup:
  206. if(hDevList) RegCloseKey(hDevList);
  207. RELEASE(pEnumInfo);
  208. RELEASE(pDevMgr);
  209. if(csi.pwszName) SysFreeString(csi.pwszName);
  210. return hr;
  211. }
  212. int __cdecl main(int argc, char **argv)
  213. {
  214. HRESULT hr;
  215. WCHAR servername[MAX_PATH];
  216. HKEY hKey;
  217. if(argc < 2) {
  218. printf("usage: connect <server name>\n");
  219. exit(0);
  220. }
  221. MultiByteToWideChar(CP_ACP, 0, argv[1], -1, servername, sizeof(servername) / sizeof(servername[0]));
  222. printf("Registering scanners on %s...", argv[1]);
  223. REQUIRE_S_OK(CoInitializeEx(NULL, COINIT_MULTITHREADED));
  224. REQUIRE_S_OK(CoInitializeSecurity(NULL, -1, NULL, NULL,
  225. RPC_C_AUTHN_LEVEL_CONNECT,
  226. RPC_C_IMP_LEVEL_IMPERSONATE,
  227. NULL,
  228. 0,
  229. NULL));
  230. REQUIRE_S_OK(RegisterRemoteScanners(servername));
  231. REQUIRE_SUCCESS(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  232. _T("SYSTEM\\CurrentControlSet\\Control\\StillImage\\DevList"),
  233. 0,
  234. KEY_READ,
  235. &hKey));
  236. for(int i = 0;;i++) {
  237. TCHAR subkeyName[1024];
  238. DWORD subkeySize;
  239. HKEY hSubKey;
  240. TCHAR string[1024];
  241. DWORD cbString;
  242. DWORD dwType;
  243. subkeySize = sizeof(subkeyName) / sizeof(subkeyName[0]);
  244. if(RegEnumKeyEx(hKey, i, subkeyName, &subkeySize, 0, NULL, NULL, NULL) != ERROR_SUCCESS) {
  245. break;
  246. }
  247. REQUIRE_SUCCESS(RegOpenKeyEx(hKey, subkeyName, 0, KEY_READ, &hSubKey));
  248. cbString = sizeof(string);
  249. REQUIRE_SUCCESS(RegQueryValueEx(hSubKey, _T("Server"), NULL, &dwType, (BYTE *)string, &cbString));
  250. if(lstrcmpi(string, servername))
  251. continue;
  252. cbString = sizeof(string);
  253. REQUIRE_SUCCESS(RegQueryValueEx(hSubKey, _T("Name"), NULL, &dwType, (BYTE *)string, &cbString));
  254. printf("\nRegistered: %ws", string);
  255. RegCloseKey(hSubKey);
  256. }
  257. printf("\ndone.\n");
  258. Cleanup:
  259. CoUninitialize();
  260. return 0;
  261. }