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.

350 lines
7.2 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. twain.c
  5. Abstract:
  6. Enumeration routines for TWAIN data sources.
  7. Author:
  8. Jim Schmidt (jimschm) 13-Aug-1998
  9. Revision History:
  10. --*/
  11. #include "pch.h"
  12. VOID
  13. pSplitDataIntoWords (
  14. IN PCTSTR Data,
  15. OUT PWORD LeftWord,
  16. OUT PWORD RightWord
  17. )
  18. {
  19. INT a, b;
  20. PCTSTR p;
  21. a = _ttoi (Data);
  22. p = _tcschr (Data, TEXT('.'));
  23. if (!p) {
  24. b = 0;
  25. } else {
  26. b = _ttoi (p + 1);
  27. }
  28. *LeftWord = (WORD) a;
  29. *RightWord = (WORD) b;
  30. }
  31. BOOL
  32. pGetDsInfo16 (
  33. IN PCTSTR DsPath,
  34. OUT TW_IDENTITY *Id
  35. )
  36. {
  37. CHAR CmdLine[MAX_CMDLINE];
  38. STARTUPINFO si;
  39. PROCESS_INFORMATION pi;
  40. BOOL ProcessResult;
  41. DWORD rc;
  42. PSTR Data;
  43. Data = CmdLine;
  44. //
  45. // Launch TWID.EXE
  46. //
  47. wsprintf (CmdLine, TEXT("\"%s\\TWID.EXE\" %s"), g_UpgradeSources, DsPath);
  48. ZeroMemory (&si, sizeof (si));
  49. si.cb = sizeof (si);
  50. si.dwFlags = STARTF_FORCEOFFFEEDBACK;
  51. ProcessResult = CreateProcessA (
  52. NULL,
  53. CmdLine,
  54. NULL,
  55. NULL,
  56. FALSE,
  57. CREATE_DEFAULT_ERROR_MODE,
  58. NULL,
  59. g_WinDir,
  60. &si,
  61. &pi
  62. );
  63. if (ProcessResult) {
  64. CloseHandle (pi.hThread);
  65. } else {
  66. LOG ((LOG_ERROR, "Cannot start %s", CmdLine));
  67. return FALSE;
  68. }
  69. rc = WaitForSingleObject (pi.hProcess, 10000);
  70. if (rc != WAIT_OBJECT_0) {
  71. TerminateProcess (pi.hProcess, 0);
  72. }
  73. CloseHandle (pi.hProcess);
  74. //
  75. // If process terminated, look for win.ini section
  76. //
  77. if (rc == WAIT_OBJECT_0) {
  78. ZeroMemory (Id, sizeof (TW_IDENTITY));
  79. GetProfileString (
  80. TEXT("$TWAINDSINFO$"),
  81. TEXT("Version"),
  82. TEXT("1.0"),
  83. Data,
  84. 32
  85. );
  86. pSplitDataIntoWords (Data, &Id->Version.MajorNum, &Id->Version.MinorNum);
  87. GetProfileString (
  88. TEXT("$TWAINDSINFO$"),
  89. TEXT("Locale"),
  90. TEXT(""),
  91. Data,
  92. 32
  93. );
  94. pSplitDataIntoWords (Data, &Id->Version.Language, &Id->Version.Country);
  95. GetProfileString (
  96. TEXT("$TWAINDSINFO$"),
  97. TEXT("VersionInfo"),
  98. TEXT(""),
  99. Id->Version.Info,
  100. sizeof (Id->Version.Info)
  101. );
  102. GetProfileString (
  103. TEXT("$TWAINDSINFO$"),
  104. TEXT("Mfg"),
  105. TEXT(""),
  106. Id->Manufacturer,
  107. sizeof (Id->Manufacturer)
  108. );
  109. GetProfileString (
  110. TEXT("$TWAINDSINFO$"),
  111. TEXT("Family"),
  112. TEXT(""),
  113. Id->ProductFamily,
  114. sizeof (Id->ProductFamily)
  115. );
  116. GetProfileString (
  117. TEXT("$TWAINDSINFO$"),
  118. TEXT("Name"),
  119. TEXT(""),
  120. Id->ProductName,
  121. sizeof (Id->ProductName)
  122. );
  123. //
  124. // Delete the INI data
  125. //
  126. WriteProfileString (
  127. TEXT("$TWAINDSINFO$"),
  128. NULL,
  129. NULL
  130. );
  131. return *(Id->ProductName) != 0;
  132. }
  133. return FALSE;
  134. }
  135. DWORD g_OrgEsp;
  136. DWORD g_OrgEbp;
  137. #if _MSC_FULL_VER >= 13008827 && defined(_M_IX86)
  138. #pragma warning(push)
  139. #pragma warning(disable:4731) // EBP modified with inline asm
  140. #endif
  141. BOOL
  142. pGetDsInfo32 (
  143. IN PCTSTR DsPath,
  144. OUT TW_IDENTITY *Id
  145. )
  146. {
  147. HINSTANCE DsLib = NULL;
  148. DSENTRYPROC DsEntry;
  149. TW_UINT16 TwainRc;
  150. __try {
  151. //
  152. // Open the DS as a 32-bit library
  153. //
  154. DsLib = LoadLibrary (DsPath);
  155. if (!DsLib) {
  156. return FALSE;
  157. }
  158. //
  159. // Get the DS entry point
  160. //
  161. DsEntry = (DSENTRYPROC) GetProcAddress (DsLib, "DS_Entry");
  162. if (!DsEntry) {
  163. FreeLibrary (DsLib);
  164. return FALSE;
  165. }
  166. //
  167. // Get the TW_IDENTITY struct, and preserve the stack for poorly
  168. // written DSes.
  169. //
  170. __asm {
  171. mov eax, esp
  172. mov [g_OrgEsp], eax
  173. mov [g_OrgEbp], ebp
  174. }
  175. TwainRc = DsEntry (NULL, DG_CONTROL, DAT_IDENTITY, MSG_GET, Id);
  176. __asm {
  177. mov eax, [g_OrgEsp]
  178. mov esp, eax
  179. mov ebp, [g_OrgEbp]
  180. }
  181. }
  182. __except (TRUE) {
  183. TwainRc = ERROR_NOACCESS;
  184. }
  185. if (DsLib) {
  186. FreeLibrary (DsLib);
  187. }
  188. return TwainRc == ERROR_SUCCESS;
  189. }
  190. #if _MSC_FULL_VER >= 13008827
  191. #pragma warning(pop)
  192. #endif
  193. BOOL
  194. EnumFirstTwainDataSource (
  195. OUT PTWAINDATASOURCE_ENUM EnumPtr
  196. )
  197. {
  198. ZeroMemory (EnumPtr, sizeof (EnumPtr));
  199. EnumPtr->State = TE_INIT;
  200. return EnumNextTwainDataSource (EnumPtr);
  201. }
  202. BOOL
  203. EnumNextTwainDataSource (
  204. IN OUT PTWAINDATASOURCE_ENUM EnumPtr
  205. )
  206. {
  207. TCHAR Path[MAX_TCHAR_PATH];
  208. TW_IDENTITY Id;
  209. while (EnumPtr->State != TE_DONE) {
  210. switch (EnumPtr->State) {
  211. case TE_INIT:
  212. EnumPtr->State = TE_BEGIN_ENUM;
  213. EnumPtr->Dir = TEXT("TWAIN\0TWAIN_32\0TWAIN32\0");
  214. break;
  215. case TE_BEGIN_ENUM:
  216. wsprintf (Path, TEXT("%s\\%s"), g_WinDir, EnumPtr->Dir);
  217. if (!EnumFirstFileInTree (&EnumPtr->Enum, Path, TEXT("*.DS"), TRUE)) {
  218. EnumPtr->State = TE_END_ENUM;
  219. } else {
  220. EnumPtr->State = TE_EVALUATE;
  221. }
  222. break;
  223. case TE_EVALUATE:
  224. if (EnumPtr->Enum.Directory) {
  225. EnumPtr->State = TE_NEXT;
  226. } else if (pGetDsInfo16 (EnumPtr->Enum.FullPath, &Id)) {
  227. EnumPtr->State = TE_RETURN;
  228. } else if (pGetDsInfo32 (EnumPtr->Enum.FullPath, &Id)) {
  229. EnumPtr->State = TE_RETURN;
  230. } else {
  231. EnumPtr->State = TE_NEXT;
  232. }
  233. break;
  234. case TE_RETURN:
  235. EnumPtr->State = TE_NEXT;
  236. __try {
  237. StackStringCopy (EnumPtr->Manufacturer, Id.Manufacturer);
  238. StackStringCopy (EnumPtr->ProductFamily, Id.ProductFamily);
  239. StackStringCopy (EnumPtr->DisplayName, Id.ProductName);
  240. StackStringCopy (EnumPtr->DataSourceModule, EnumPtr->Enum.FullPath);
  241. }
  242. __except (TRUE) {
  243. break;
  244. }
  245. return TRUE;
  246. case TE_NEXT:
  247. if (!EnumNextFileInTree (&EnumPtr->Enum)) {
  248. EnumPtr->State = TE_END_ENUM;
  249. } else {
  250. EnumPtr->State = TE_EVALUATE;
  251. }
  252. break;
  253. case TE_END_ENUM:
  254. EnumPtr->Dir = GetEndOfString (EnumPtr->Dir) + 1;
  255. if (*EnumPtr->Dir) {
  256. EnumPtr->State = TE_BEGIN_ENUM;
  257. } else {
  258. EnumPtr->State = TE_DONE;
  259. }
  260. break;
  261. }
  262. }
  263. return FALSE;
  264. }
  265. VOID
  266. AbortTwainDataSourceEnum (
  267. IN OUT PTWAINDATASOURCE_ENUM EnumPtr
  268. )
  269. {
  270. if (EnumPtr->State != TE_DONE) {
  271. AbortEnumFileInTree (&EnumPtr->Enum);
  272. EnumPtr->State = TE_DONE;
  273. }
  274. }