/3rdparty/DelphiTwain/DelphiTwain.pas

https://bitbucket.org/reiniero/papertiger · Pascal · 2927 lines · 1889 code · 288 blank · 750 comment · 184 complexity · 571be27bc8bfc481a395d7a5b2dda35e MD5 · raw file

Large files are truncated click here to view the full file

  1. {DELPHI IMPLEMENTATION OF TWAIN INTERFACE}
  2. {Initially created by Gustavo Daud December 2003}
  3. {This is my newest contribution for Delphi comunity, a powerfull}
  4. {implementation of latest Twain features. As you know, twain is }
  5. {the most common library to acquire images from most acquisition}
  6. {devices such as Scanners and Web-Cameras.}
  7. {Twain library is a bit different from other libraries, because}
  8. {most of the hard work can be done by a a single method. Also it}
  9. {automatically changes in the application message loop, which is}
  10. {not a simple task, at least in delphi VCL.}
  11. {It is not 100% sure to to Twain not to be installed in Windows,}
  12. {as it ships with Windows and later and with most of the }
  13. {acquisition device drivers (automatically with their installation)}
  14. {This library dynamically calls the library, avoiding the application}
  15. {hang when it is not present.}
  16. {Also, as in most of my other components, I included a trigger}
  17. {to allow the component to work without the heavy delphi VCL}
  18. {for small final executables. To enable, edit DelphiTwain.inc}
  19. {
  20. CHANGE LOG:
  21. 2014/04/29 - Fix for unloading library cancelling acquire window on Lazarus
  22. Typo fixes in language constants; cosmetic fixes.
  23. 2013/12/18 - FireMonkey support, color bug fix.
  24. 2013/08/18 - New method OnTransferComplete: fired when all documents are
  25. scanned or the scan is canceled. Thanks to Andrei Galatyn.
  26. 2013/07/26 - Color problems solved (thanks to Marco & Christian).
  27. TWAIN drivers did not respond - now both WIA and TWAIN can be used.
  28. 2012/11/01 - Ondrej Pokorny: small changes for Lazarus and 64bit compiler
  29. 2009/11/10 - Some changes to make it work in Delphi 2009, and above
  30. 2004/01/20 - Some updates and bug fixes by Nemeth Peter
  31. }
  32. unit DelphiTwain;
  33. {$I DelphiTwain.inc}
  34. interface
  35. {$IFDEF FPC}
  36. {$MODE delphi}
  37. {$ENDIF}
  38. {Used units}
  39. uses
  40. SysUtils, Windows, Messages,
  41. {$IFDEF FPC}Classes, {$ENDIF}
  42. Twain, DelphiTwainUtils;
  43. const
  44. {Name of the Twain library for 32 bits enviroment}
  45. {$IFDEF WIN64}
  46. TWAINLIBRARY: String = 'TWAINDSM.DLL';
  47. {$ELSE}
  48. TWAINLIBRARY: String = 'TWAIN_32.DLL';
  49. {$ENDIF}
  50. const
  51. {Error codes}
  52. ERROR_BASE = 300;
  53. ERROR_INT16: TW_INT16 = HIGH(TW_INT16);
  54. type
  55. {From twain}
  56. TW_STR255 = Twain.TW_STR255;
  57. {Forward declaration}
  58. TCustomDelphiTwain = class;
  59. {Component kinds}
  60. TTwainComponent = TObject;
  61. {File formats}
  62. TTwainFormat = (tfTIFF, tfPict, tfBMP, tfXBM, tfJPEG, tfFPX,
  63. tfTIFFMulti, tfPNG, tfSPIFF, tfEXIF, tfUnknown);
  64. {Twain units}
  65. TTwainUnit = (tuInches, tuCentimeters, tuPicas, tuPoints, tuTwips,
  66. tuPixels, tuUnknown);
  67. TTwainUnitSet = set of TTwainUnit;
  68. {Twain pixel flavor}
  69. TTwainPixelFlavor = (tpfChocolate, tpfVanilla, tpfUnknown);
  70. TTwainPixelFlavorSet = set of TTwainPixelFlavor;
  71. {Orientation}
  72. TTwainOrientation = (torPortrait, torLandscape);
  73. {Paper size}
  74. TTwainPaperSize = (tpsA4, tpsA5, tpsB4, tpsB5, tpsB6, tpsUSLetter, tpsUSLegal);
  75. {Twain pixel type}
  76. TTwainPixelType = (tbdBw, tbdGray, tbdRgb, tbdPalette, tbdCmy, tbdCmyk,
  77. tbdYuv, tbdYuvk, tbdCieXYZ, tbdUnknown, tbdUnknown1, tbdUnknown2, tbdBgr);
  78. TTwainPixelTypeSet = set of TTwainPixelType;
  79. {Twain bit depth}
  80. TTwainBitDepth = array of TW_UINT16;
  81. {Twain resolutions}
  82. TTwainResolution = array of Extended;
  83. {Events}
  84. TOnTwainError = procedure(Sender: TObject; const Index: Integer; ErrorCode,
  85. Additional: Integer) of object;
  86. TOnSourceNotify = procedure(Sender: TObject; const Index: Integer) of object;
  87. TOnTransferComplete = procedure(Sender: TObject; const Index: Integer; const Canceled: Boolean) of object;
  88. TOnSourceFileTransfer = procedure(Sender: TObject; const Index: Integer;
  89. Filename: TW_STR255; Format: TTwainFormat; var Cancel: Boolean) of object;
  90. {Available twain languages}
  91. TTwainLanguage = ({-1}tlUserLocale=-1, tlDanish, tlDutch, tlInternationalEnglish,
  92. tlFrenchCanadian, tlFinnish, tlFrench, tlGerman, tlIcelandic, tlItalian,
  93. tlNorwegian, tlPortuguese, tlSpanish, tlSwedish, tlUsEnglish,
  94. tlAfrikaans, tlAlbania, tlArabic, tlArabicAlgeria, tlArabicBahrain, {18}
  95. tlArabicEgypt, tlArabicIraq, tlArabJordan, tlArabicKuwait,
  96. tlArabicLebanon, tlArabicLibya, tlArabicMorocco, tlArabicOman,
  97. tlArabicQatar, tlArabicSaudiarabia, tlArabicSyria, tlArabicTunisia,
  98. tlArabicUae, tlArabicYemen, tlBasque, tlByelorussian, tlBulgarian, {35}
  99. tlCatalan, tlChinese, tlChineseHongkong, tlChinesePeoplesRepublic,
  100. tlChineseSingapore, tlChineseSimplified, tlChineseTwain, {42}
  101. tlChineseTraditional, tlCroatia, tlCzech, tlDutchBelgian, {46}
  102. tlEnglishAustralian, tlEnglishCanadian, tlEnglishIreland,
  103. tlEnglishNewZealand, tlEnglishSouthAfrica, tlEnglishUk, {52}
  104. tlEstonian, tlFaeroese, tlFarsi, tlFrenchBelgian, tlFrenchLuxembourg, {57}
  105. tlFrenchSwiss, tlGermanAustrian, tlGermanLuxembourg, tlGermanLiechtenstein,
  106. tlGermanSwiss, tlGreek, tlHebrew, tlHungarian, tlIndonesian, {66}
  107. tlItalianSwiss, tlJapanese, tlKorean, tlKoreanJohab, tlLatvian, {71}
  108. tlLithuanian, tlNorewgianBokmal, tlNorwegianNynorsk, tlPolish, {75}
  109. tlPortugueseBrazil, tlRomanian, tlRussian, tlSerbianLatin,
  110. tlSlovak, tlSlovenian, tlSpanishMexican, tlSpanishModern, tlThai,
  111. tlTurkish, tlUkranian, tlAssamese, tlBengali, tlBihari, tlBodo,
  112. tlDogri, tlGujarati {92}, tlHarayanvi, tlHindi, tlKannada, tlKashmiri,
  113. tlMalayalam, tlMarathi, tlMarwari, tlMeghalayan, tlMizo, tlNaga {102},
  114. tlOrissi, tlPunjabi, tlPushtu, tlSerbianCyrillic, tlSikkimi,
  115. tlSwedishFinland, tlTamil, tlTelugu, tlTripuri, tlUrdu, tlVietnamese);
  116. {Twain supported groups}
  117. TTwainGroups = set of (tgControl, tgImage, tgAudio);
  118. {Transfer mode for twain}
  119. TTwainTransferMode = (ttmFile, ttmNative, ttmMemory);
  120. {rect for LAYOUT; npeter 2004.01.12.}
  121. TTwainRect =
  122. record
  123. Left: double;
  124. Top: double;
  125. Right: double;
  126. Bottom: double;
  127. end;
  128. {Object to handle TW_IDENTITY}
  129. TTwainIdentity = class(TObject)
  130. private
  131. {Sets application language property}
  132. procedure SetLanguage(const Value: TTwainLanguage);
  133. {Sets text values}
  134. procedure SetString(const Index: Integer; const Value: String);
  135. {Sets avaliable groups}
  136. procedure SetGroups(const Value: TTwainGroups);
  137. protected
  138. {Structure which should be filled}
  139. Structure: TW_IDENTITY;
  140. {Returns application language property}
  141. function GetLanguage(): TTwainLanguage;
  142. {Returns text values}
  143. function GetString(const Index: integer): String;
  144. {Returns avaliable groups}
  145. function GetGroups(): TTwainGroups;
  146. public
  147. {Object being created}
  148. constructor Create;
  149. {Copy properties from another TTwainIdentity}
  150. procedure Assign(Source: TObject);
  151. public
  152. {Application major version}
  153. property MajorVersion: TW_UINT16 read Structure.Version.MajorNum
  154. write Structure.Version.MajorNum;
  155. {Application minor version}
  156. property MinorVersion: TW_UINT16 read Structure.Version.MinorNum
  157. write Structure.Version.MinorNum;
  158. {Language}
  159. property Language: TTwainLanguage read GetLanguage write SetLanguage;
  160. {Country code}
  161. property CountryCode: word read Structure.Version.Country write
  162. Structure.Version.Country;
  163. {Supported groups}
  164. property Groups: TTwainGroups read GetGroups write SetGroups;
  165. {Text values}
  166. property VersionInfo: String index 0 read GetString write
  167. SetString;
  168. {Scanner manufacturer}
  169. property Manufacturer: String index 1 read GetString write
  170. SetString;
  171. {Scanner product family}
  172. property ProductFamily: String index 2 read GetString write
  173. SetString;
  174. {Scanner product name}
  175. property ProductName: String index 3 read GetString write
  176. SetString;
  177. end;
  178. {Return set for capability retrieving/setting}
  179. TCapabilityRet = (crSuccess, crUnsupported, crBadOperation, crDependencyError,
  180. crLowMemory, crInvalidState, crInvalidContainer);
  181. {Kinds of capability retrieving}
  182. TRetrieveCap = (rcGet, rcGetCurrent, rcGetDefault, rcReset);
  183. {Capability list type}
  184. TGetCapabilityList = array of string;
  185. TSetCapabilityList = array of pointer;
  186. {Source object}
  187. TTwainSource = class(TTwainIdentity)
  188. private
  189. {Holds the item index}
  190. fIndex: Integer;
  191. {Transfer mode for the images}
  192. fTransferMode: TTwainTransferMode;
  193. {Stores if user interface should be shown}
  194. fShowUI: Boolean;
  195. {Stores if the source window is modal}
  196. fModal: Boolean;
  197. {Stores if the source is enabled}
  198. fEnabled: Boolean;
  199. {Stores if the source is loaded}
  200. fLoaded: Boolean;
  201. {Stores the owner}
  202. fOwner: TCustomDelphiTwain;
  203. {Used with property SourceManagerLoaded to test if the source manager}
  204. {is loaded or not.}
  205. function GetSourceManagerLoaded(): Boolean;
  206. {Returns a pointer to the application}
  207. function GetAppInfo(): pTW_IDENTITY;
  208. {Sets if the source is loaded}
  209. procedure SetLoaded(const Value: Boolean);
  210. {Sets if the source is enabled}
  211. procedure SetEnabled(const Value: Boolean);
  212. {Returns a pointer to the source pTW_IDENTITY}
  213. function GetStructure: pTW_IDENTITY;
  214. {Returns a resolution}
  215. function GetResolution(Capability: TW_UINT16; var Return: Extended;
  216. var Values: TTwainResolution; Mode: TRetrieveCap): TCapabilityRet;
  217. protected
  218. {Reads a native image}
  219. procedure ReadNative(Handle: TW_UINT32; var Cancel: Boolean);
  220. {Reads the file image}
  221. procedure ReadFile(Name: TW_STR255; Format: TW_UINT16; var Cancel: Boolean);
  222. {Call event for memory image}
  223. procedure ReadMemory(Image: HBitmap; var Cancel: Boolean);
  224. protected
  225. {Prepare image memory transference}
  226. function PrepareMemXfer(var BitmapHandle: HBitmap;
  227. var PixelType: TW_INT16): TW_UINT16;
  228. {Transfer image memory}
  229. function TransferImageMemory(var ImageHandle: HBitmap;
  230. {%H-}PixelType: TW_INT16): TW_UINT16;
  231. {Returns a pointer to the TW_IDENTITY for the application}
  232. property AppInfo: pTW_IDENTITY read GetAppInfo;
  233. {Method to transfer the images}
  234. procedure TransferImages();
  235. {Returns if the source manager is loaded}
  236. property SourceManagerLoaded: Boolean read GetSourceManagerLoaded;
  237. {Source configuration methods}
  238. {************************}
  239. protected
  240. {Gets an item and returns it in a string}
  241. procedure GetItem(var Return: String; ItemType: TW_UINT16; Data: Pointer);
  242. {Converts from a result to a TCapabilityRec}
  243. function ResultToCapabilityRec(const Value: TW_UINT16): TCapabilityRet;
  244. {Sets a capability}
  245. function SetCapabilityRec(const Capability, ConType: TW_UINT16;
  246. Data: HGLOBAL): TCapabilityRet;
  247. public
  248. {Message received in the event loop}
  249. function ProcessMessage(const Msg: TMsg): Boolean;
  250. {Returns a capability strucutre}
  251. function GetCapabilityRec(const Capability: TW_UINT16;
  252. var Handle: HGLOBAL; Mode: TRetrieveCap;
  253. var Container: TW_UINT16): TCapabilityRet;
  254. {************************}
  255. {Returns an one value capability}
  256. function GetOneValue(Capability: TW_UINT16;
  257. var ItemType: TW_UINT16; var Value: string;
  258. Mode: TRetrieveCap{$IFDEF DEFAULTPARAM}=rcGet{$ENDIF};
  259. MemHandle: HGLOBAL{$IFDEF DEFAULTPARAM}=0{$ENDIF}): TCapabilityRet;
  260. {Returns an range capability}
  261. function GetRangeValue(Capability: TW_UINT16; var ItemType: TW_UINT16;
  262. var Min, Max, Step, Default, Current: String;
  263. MemHandle: HGLOBAL{$IFDEF DEFAULTPARAM}=0{$ENDIF}): TCapabilityRet;
  264. {Returns an enumeration capability}
  265. function GetEnumerationValue(Capability: TW_UINT16;
  266. var ItemType: TW_UINT16; var List: TGetCapabilityList; var Current,
  267. Default: Integer; Mode: TRetrieveCap{$IFDEF DEFAULTPARAM}=rcGet{$ENDIF};
  268. MemHandle: HGLOBAL{$IFDEF DEFAULTPARAM}=0{$ENDIF}): TCapabilityRet;
  269. {Returns an array capability}
  270. function GetArrayValue(Capability: TW_UINT16; var ItemType: TW_UINT16;
  271. var List: TGetCapabilityList; MemHandle: HGLOBAL
  272. {$IFDEF DEFAULTPARAM}=0{$ENDIF}): TCapabilityRet;
  273. {************************}
  274. {Sets an one value capability}
  275. function SetOneValue(Capability: TW_UINT16; ItemType: TW_UINT16;
  276. Value: Pointer): TCapabilityRet;
  277. {Sets a range capability}
  278. function SetRangeValue(Capability, ItemType: TW_UINT16; Min, Max, Step,
  279. Current: TW_UINT32): TCapabilityRet;
  280. {Sets an enumeration capability}
  281. function SetEnumerationValue(Capability, ItemType: TW_UINT16;
  282. CurrentIndex: TW_UINT32; List: TSetCapabilityList): TCapabilityRet;
  283. {Sets an array capability}
  284. function SetArrayValue(Capability, ItemType: TW_UINT16;
  285. List: TSetCapabilityList): TCapabilityRet;
  286. public
  287. {Setup file transfer}
  288. function SetupFileTransfer(Filename: String; Format: TTwainFormat): Boolean;
  289. protected
  290. {Used with property PendingXfers}
  291. function GetPendingXfers(): TW_INT16;
  292. public
  293. {Set source transfer mode}
  294. //function ChangeTransferMode(NewMode: TTwainTransferMode): TCapabilityRet;
  295. {Transfer mode for transfering images from the source to}
  296. {the component and finally to the application}
  297. property TransferMode: TTwainTransferMode read fTransferMode write fTransferMode;
  298. public
  299. {Returns return status information}
  300. function GetReturnStatus(): TW_UINT16;
  301. {Capability setting}
  302. {Set the number of images that the application wants to receive}
  303. function SetCapXferCount(Value: SmallInt): TCapabilityRet;
  304. {Returns the number of images that the source will return}
  305. function GetCapXferCount(var Return: SmallInt;
  306. Mode: TRetrieveCap{$IFDEF DEFAULTPARAM}=rcGet{$ENDIF}): TCapabilityRet;
  307. {Retrieve the unit measure for all quantities}
  308. function GetICapUnits(var Return: TTwainUnit;
  309. var Supported: TTwainUnitSet; Mode: TRetrieveCap
  310. {$IFDEF DEFAULTPARAM}=rcGet{$ENDIF}): TCapabilityRet;
  311. {Set the unit measure}
  312. function SetICapUnits(Value: TTwainUnit): TCapabilityRet;
  313. {npeter 2004.01.12 begin}
  314. function SetImagelayoutFrame(const fLeft,fTop,fRight,
  315. fBottom: double): TCapabilityRet;
  316. function SetIndicators(Value: boolean): TCapabilityRet;
  317. {npeter 2004.01.12 end}
  318. {Retrieve the pixel flavor values}
  319. function GetIPixelFlavor(var Return: TTwainPixelFlavor;
  320. var Supported: TTwainPixelFlavorSet; Mode: TRetrieveCap
  321. {$IFDEF DEFAULTPARAM}=rcGet{$ENDIF}): TCapabilityRet;
  322. {Set the pixel flavor values}
  323. function SetIPixelFlavor(Value: TTwainPixelFlavor): TCapabilityRet;
  324. {Set orientation}
  325. function SetOrientation(Value: TTwainOrientation): TCapabilityRet;
  326. {Set paper size}
  327. function SetPaperSize(Value: TTwainPaperSize): TCapabilityRet;
  328. {Returns bitdepth values}
  329. function GetIBitDepth(var Return: Word;
  330. var Supported: TTwainBitDepth; Mode: TRetrieveCap
  331. {$IFDEF DEFAULTPARAM}=rcGet{$ENDIF}): TCapabilityRet;
  332. {Set current bitdepth value}
  333. function SetIBitDepth(Value: Word): TCapabilityRet;
  334. {Returns pixel type values}
  335. function GetIPixelType(var Return: TTwainPixelType;
  336. var Supported: TTwainPixelTypeSet; Mode: TRetrieveCap
  337. {$IFDEF DEFAULTPARAM}=rcGet{$ENDIF}): TCapabilityRet;
  338. {Set the pixel type value}
  339. function SetIPixelType(Value: TTwainPixelType): TCapabilityRet;
  340. {Returns X and Y resolutions}
  341. function GetIXResolution(var Return: Extended; var Values: TTwainResolution;
  342. Mode: TRetrieveCap {$IFDEF DEFAULTPARAM}=rcGet{$ENDIF}): TCapabilityRet;
  343. function GetIYResolution(var Return: Extended; var Values: TTwainResolution;
  344. Mode: TRetrieveCap {$IFDEF DEFAULTPARAM}=rcGet{$ENDIF}): TCapabilityRet;
  345. {Sets X and X resolutions}
  346. function SetIXResolution(Value: Extended): TCapabilityRet;
  347. function SetIYResolution(Value: Extended): TCapabilityRet;
  348. {Returns physical width and height}
  349. function GetIPhysicalWidth(var Return: Extended; Mode: TRetrieveCap
  350. {$IFDEF DEFAULTPARAM}=rcGet{$ENDIF}): TCapabilityRet;
  351. function GetIPhysicalHeight(var Return: Extended; Mode: TRetrieveCap
  352. {$IFDEF DEFAULTPARAM}=rcGet{$ENDIF}): TCapabilityRet;
  353. {Returns if user interface is controllable}
  354. function GetUIControllable(var Return: Boolean): TCapabilityRet;
  355. {Returns feeder is loaded or not}
  356. function GetFeederLoaded(var Return: Boolean): TCapabilityRet;
  357. {Returns/sets if feeder is enabled}
  358. function GetFeederEnabled(var Return: Boolean): TCapabilityRet;
  359. function SetFeederEnabled(Value: WordBool): TCapabilityRet;
  360. {Returns/sets if auto feed is enabled}
  361. function GetAutofeed(var Return: Boolean): TCapabilityRet;
  362. function SetAutoFeed(Value: WordBool): TCapabilityRet;
  363. {Returns number of pending transfer}
  364. property PendingXfers: TW_INT16 read GetPendingXfers;
  365. public
  366. {Enables the source}
  367. function EnableSource(ShowUI, Modal: Boolean): Boolean;
  368. {Disables the source}
  369. function DisableSource: Boolean;
  370. {Loads the source}
  371. function LoadSource(): Boolean;
  372. {Unloads the source}
  373. function UnloadSource(): Boolean;
  374. {Returns a pointer to the source identity}
  375. property SourceIdentity: pTW_IDENTITY read GetStructure;
  376. {Returns/sets if the source is enabled}
  377. property Enabled: Boolean read fEnabled write SetEnabled;
  378. {Returns/sets if this source is loaded}
  379. property Loaded: Boolean read fLoaded write SetLoaded;
  380. {Object being created/destroyed}
  381. constructor Create(AOwner: TCustomDelphiTwain);
  382. destructor Destroy; override;
  383. {Returns owner}
  384. property Owner: TCustomDelphiTwain read fOwner;
  385. {Source window is modal}
  386. property Modal: Boolean read fModal write fModal;
  387. {Sets if user interface should be shown}
  388. property ShowUI: Boolean read fShowUI write fShowUI;
  389. {Returns the item index}
  390. property Index: Integer read fIndex;
  391. {Convert properties from write/read to read only}
  392. {(read description on TTwainIdentity source)}
  393. property MajorVersion: TW_UINT16 read Structure.Version.MajorNum;
  394. property MinorVersion: TW_UINT16 read Structure.Version.MinorNum;
  395. property Language: TTwainLanguage read GetLanguage;
  396. property CountryCode: word read Structure.Version.Country;
  397. property Groups: TTwainGroups read GetGroups;
  398. property VersionInfo: String index 0 read GetString;
  399. property Manufacturer: String index 1 read GetString;
  400. property ProductFamily: String index 2 read GetString;
  401. property ProductName: String index 3 read GetString;
  402. end;
  403. {Component part}
  404. TCustomDelphiTwain = class(TTwainComponent)
  405. private
  406. {Should contain the number of Twain sources loaded}
  407. fSourcesLoaded: Integer;
  408. private
  409. {Event pointer holders}
  410. fOnSourceDisable: TOnSourceNotify;
  411. fOnAcquireCancel: TOnSourceNotify;
  412. fOnSourceSetupFileXfer: TOnSourceNotify;
  413. fOnSourceFileTransfer: TOnSourceFileTransfer;
  414. fOnAcquireError: TOnTwainError;
  415. fOnTransferComplete: TOnTransferComplete;
  416. private
  417. fSelectedSourceIndex: Integer;
  418. {Temp variable to allow SourceCount to be displayed in delphi}
  419. {property editor}
  420. fDummySourceCount: Integer;
  421. {Contains list of source devices}
  422. DeviceList: TPointerList;
  423. {Contains a pointer to the structure with the application}
  424. {information}
  425. AppInfo: pTW_IDENTITY;
  426. {Holds the object to allow the user to set the application information}
  427. fInfo: TTwainIdentity;
  428. {Holds the handle for the virtual window which will receive}
  429. {twain message notifications}
  430. {Will hold Twain library handle}
  431. fHandle: HInst;
  432. {Holds if the component has enumerated the devices}
  433. fHasEnumerated: Boolean;
  434. {Holds twain dll procedure handle}
  435. fTwainProc: TDSMEntryProc;
  436. {Holds the transfer mode to be used}
  437. fTransferMode: TTwainTransferMode;
  438. {Contains if the library is loaded}
  439. fLibraryLoaded: Boolean;
  440. {Contains if the source manager was loaded}
  441. fSourceManagerLoaded: Boolean;
  442. {Set to true if the host application does not create any windows}
  443. fIsConsoleApplication: Boolean;
  444. {Procedure to load and unload twain library and update property}
  445. procedure SetLibraryLoaded(const Value: Boolean);
  446. {Procedure to load or unloaded the twain source manager}
  447. procedure SetSourceManagerLoaded(const Value: Boolean);
  448. {Updates the application information object}
  449. procedure SetInfo(const Value: TTwainIdentity);
  450. {Returns the number of sources}
  451. function GetSourceCount(): Integer;
  452. {Returns a source from the list}
  453. function GetSource(Index: Integer): TTwainSource;
  454. {Finds a matching source index}
  455. function FindSource(Value: pTW_IDENTITY): Integer;
  456. //Gets selected source
  457. function GetSelectedSource: TTwainSource;
  458. //Gets selected source index
  459. function GetSelectedSourceIndex: Integer;
  460. //Sets selected source index
  461. procedure SetSelectedSourceIndex(const Value: Integer);
  462. //Refresh the VirtualWindow - usually needed when transfer was completed
  463. procedure RefreshVirtualWindow;
  464. protected
  465. fVirtualWindow: THandle;
  466. {Returns the default source}
  467. function GetDefaultSource: Integer;
  468. procedure DoCreate; virtual;
  469. procedure DoDestroy; virtual;
  470. procedure MessageTimer_Enable; virtual; abstract;
  471. procedure MessageTimer_Disable; virtual; abstract;
  472. function CustomSelectSource: Integer; virtual; abstract;
  473. function CustomGetParentWindow: TW_HANDLE; virtual; abstract;
  474. procedure DoTwainAcquire(Sender: TObject; const Index: Integer; Image:
  475. HBitmap; var Cancel: Boolean); virtual; abstract;
  476. procedure DoAcquireProgress(Sender: TObject; const Index: Integer;
  477. const Image: HBitmap; const Current, Total: Integer); virtual; abstract;
  478. public
  479. {Clears the list of sources}
  480. procedure ClearDeviceList();
  481. public
  482. {Allows Twain to display a dialog to let the user choose any source}
  483. {and returns the source index in the list}
  484. function SelectSource(): Integer;
  485. {Returns the number of loaded sources}
  486. property SourcesLoaded: Integer read fSourcesLoaded;
  487. {Enumerate the avaliable devices after Source Manager is loaded}
  488. function EnumerateDevices(): Boolean;
  489. {Object being created}
  490. constructor Create; virtual;
  491. {Object being destroyed}
  492. destructor Destroy; override;
  493. {Loads twain library and returns if it loaded sucessfully}
  494. function LoadLibrary(): Boolean;
  495. {Unloads twain and returns if it unloaded sucessfully}
  496. function UnloadLibrary(): Boolean;
  497. {Loads twain source manager}
  498. function LoadSourceManager(): Boolean;
  499. {Unloads the source manager}
  500. function UnloadSourceManager(forced: boolean): Boolean;
  501. {Returns the application TW_IDENTITY}
  502. property AppIdentity: pTW_IDENTITY read AppInfo;
  503. {Returns Twain library handle}
  504. property Handle: HInst read fHandle;
  505. {Returns virtual window that receives messages}
  506. property VirtualWindow: THandle read fVirtualWindow;
  507. {Returns a pointer to Twain only procedure}
  508. property TwainProc: TDSMEntryProc read fTwainProc;
  509. {Holds if the component has enumerated the devices}
  510. property HasEnumerated: Boolean read fHasEnumerated;
  511. {Returns a source}
  512. property Source[Index: Integer]: TTwainSource read GetSource;
  513. {Set to true if the host application does not create any windows}
  514. property IsConsoleApplication: Boolean read fIsConsoleApplication write fIsConsoleApplication default False;
  515. public
  516. {Events}
  517. {Source being disabled}
  518. property OnSourceDisable: TOnSourceNotify read fOnSourceDisable
  519. write fOnSourceDisable;
  520. {Acquire cancelled}
  521. property OnAcquireCancel: TOnSourceNotify read fOnAcquireCancel
  522. write fOnAcquireCancel;
  523. {User should set information to prepare for the file transfer}
  524. property OnSourceSetupFileXfer: TOnSourceNotify read fOnSourceSetupFileXfer
  525. write fOnSourceSetupFileXfer;
  526. {File transfered}
  527. property OnSourceFileTransfer: TOnSourceFileTransfer read
  528. fOnSourceFileTransfer write fOnSourceFileTransfer;
  529. {Acquire error}
  530. property OnAcquireError: TOnTwainError read fOnAcquireError
  531. write fOnAcquireError;
  532. {All images transfered}
  533. property OnTransferComplete: TOnTransferComplete read fOnTransferComplete
  534. write fOnTransferComplete;
  535. public
  536. {Default transfer mode to be used with sources}
  537. property TransferMode: TTwainTransferMode read fTransferMode
  538. write fTransferMode;
  539. {Returns the number of sources, after Library and Source Manager}
  540. {has being loaded}
  541. property SourceCount: Integer read GetSourceCount write fDummySourceCount;
  542. //Selected source in a dialog
  543. property SelectedSourceIndex: Integer read GetSelectedSourceIndex write SetSelectedSourceIndex;
  544. //Selected source in a dialog
  545. property SelectedSource: TTwainSource read GetSelectedSource;
  546. {User should fill the application information}
  547. property Info: TTwainIdentity read fInfo write SetInfo;
  548. {Loads or unload Twain library}
  549. property LibraryLoaded: Boolean read fLibraryLoaded write SetLibraryLoaded;
  550. {Loads or unloads the source manager}
  551. property SourceManagerLoaded: Boolean read fSourceManagerLoaded write
  552. SetSourceManagerLoaded;
  553. end;
  554. {Puts a string inside a TW_STR255}
  555. {$IFDEF UNICODE}
  556. function StrToStr255(Value: RawByteString): TW_STR255;
  557. {$ELSE}
  558. function StrToStr255(Value: String): TW_STR255;
  559. {$ENDIF}
  560. {This method returns if Twain is installed in the current machine}
  561. function IsTwainInstalled(): Boolean;
  562. {Called by Delphi to register the component}
  563. {Returns the size of a twain type}
  564. function TWTypeSize(TypeName: TW_UINT16): Integer;
  565. function MakeMsg(const Handle: THandle; uMsg: UINT; wParam: WPARAM;
  566. lParam: LPARAM): TMsg;
  567. implementation
  568. {Returns the size of a twain type}
  569. function TWTypeSize(TypeName: TW_UINT16): Integer;
  570. begin
  571. {Test the type to return the size}
  572. case TypeName of
  573. TWTY_INT8 : Result := sizeof(TW_INT8);
  574. TWTY_UINT8 : Result := sizeof(TW_UINT8);
  575. TWTY_INT16 : Result := sizeof(TW_INT16);
  576. TWTY_UINT16: Result := sizeof(TW_UINT16);
  577. TWTY_INT32 : Result := sizeof(TW_INT32);
  578. TWTY_UINT32: Result := sizeof(TW_UINT32);
  579. TWTY_FIX32 : Result := sizeof(TW_FIX32);
  580. TWTY_FRAME : Result := sizeof(TW_FRAME);
  581. TWTY_STR32 : Result := sizeof(TW_STR32);
  582. TWTY_STR64 : Result := sizeof(TW_STR64);
  583. TWTY_STR128: Result := sizeof(TW_STR128);
  584. TWTY_STR255: Result := sizeof(TW_STR255);
  585. //npeter: the following types were not implemented
  586. //especially the bool caused problems
  587. TWTY_BOOL: Result := sizeof(TW_BOOL);
  588. TWTY_UNI512: Result := sizeof(TW_UNI512);
  589. TWTY_STR1024: Result := sizeof(TW_STR1024);
  590. else Result := 0;
  591. end {case}
  592. end;
  593. {Puts a string inside a TW_STR255}
  594. {$IFDEF UNICODE}
  595. function StrToStr255(Value: RawByteString): TW_STR255;
  596. {$ELSE}
  597. function StrToStr255(Value: String): TW_STR255;
  598. {$ENDIF}
  599. begin
  600. {Clean result}
  601. Fillchar({%H-}Result, sizeof(TW_STR255), #0);
  602. {If value fits inside the TW_STR255, copy memory}
  603. if Length(Value) <= sizeof(TW_STR255) then
  604. CopyMemory(@Result[0], @Value[1], Length(Value))
  605. else CopyMemory(@Result[0], @Value[1], sizeof(TW_STR255));
  606. end;
  607. {Returns full Twain directory (usually in Windows directory)}
  608. function GetTwainDirectory(): String;
  609. var
  610. i: TDirectoryKind;
  611. Dir: String;
  612. begin
  613. {Searches in all the directories}
  614. FOR i := LOW(TDirectoryKind) TO HIGH(TDirectoryKind) DO
  615. begin
  616. {Directory to search}
  617. Dir := GetCustomDirectory(i);
  618. {Tests if the file exists in this directory}
  619. if FileExists(Dir + String(TWAINLIBRARY)) then
  620. begin
  621. {In case it exists, returns this directory and exit}
  622. {the for loop}
  623. Result := Dir;
  624. Break;
  625. end {if FileExists}
  626. end {FOR i}
  627. end;
  628. {This method returns if Twain is installed in the current machine}
  629. function IsTwainInstalled(): Boolean;
  630. begin
  631. {If GetTwainDirectory function returns an empty string, it means}
  632. {that Twain was not found}
  633. Result := (GetTwainDirectory() <> '');
  634. end;
  635. { TTwainIdentity object implementation }
  636. {Object being created}
  637. constructor TTwainIdentity.Create;
  638. begin
  639. {Allows ancestor to work}
  640. inherited Create;
  641. {Set initial properties}
  642. FillChar(Structure, sizeof(Structure), #0);
  643. Language := tlUserLocale;
  644. CountryCode := 1;
  645. MajorVersion := 1;
  646. VersionInfo := 'Application name';
  647. Structure.ProtocolMajor := TWON_PROTOCOLMAJOR;
  648. Structure.ProtocolMinor := TWON_PROTOCOLMINOR;
  649. Groups := [tgImage, tgControl];
  650. Manufacturer := 'Application manufacturer';
  651. ProductFamily := 'App product family';
  652. ProductName := 'App product name';
  653. end;
  654. {Sets a text value}
  655. procedure TTwainIdentity.SetString(const Index: Integer;
  656. const Value: String);
  657. var
  658. PropStr: PAnsiChar;
  659. begin
  660. {Select and copy pointer}
  661. case Index of
  662. 0: PropStr := @Structure.Version.Info[0];
  663. 1: PropStr := @Structure.Manufacturer[0];
  664. 2: PropStr := @Structure.ProductFamily[0];
  665. else PropStr := @Structure.ProductName[0];
  666. end {case};
  667. {Set value}
  668. Fillchar(PropStr^, sizeof(TW_STR32), #0);
  669. if Length(Value) > sizeof(TW_STR32) then
  670. CopyMemory(PropStr, @Value[1], sizeof(TW_STR32))
  671. else
  672. CopyMemory(PropStr, @Value[1], Length(Value));
  673. end;
  674. {Returns a text value}
  675. function TTwainIdentity.GetString(const Index: Integer): String;
  676. begin
  677. {Test for the required property}
  678. case Index of
  679. 0: Result := string(Structure.Version.Info);
  680. 1: Result := string(Structure.Manufacturer);
  681. 2: Result := string(Structure.ProductFamily);
  682. else Result := string(Structure.ProductName);
  683. end {case}
  684. end;
  685. {Returns application language property}
  686. function TTwainIdentity.GetLanguage(): TTwainLanguage;
  687. begin
  688. Result := TTwainLanguage(Structure.Version.Language + 1);
  689. end;
  690. {Sets application language property}
  691. procedure TTwainIdentity.SetLanguage(const Value: TTwainLanguage);
  692. begin
  693. Structure.Version.Language := Word(Value) - 1;
  694. end;
  695. {Copy properties from another TTwainIdentity}
  696. procedure TTwainIdentity.Assign(Source: TObject);
  697. begin
  698. {The source should also be a TTwainIdentity}
  699. if Source is TTwainIdentity then begin
  700. {Copy properties}
  701. Structure := TTwainIdentity(Source).Structure
  702. end;
  703. end;
  704. {Returns avaliable groups}
  705. function TTwainIdentity.GetGroups(): TTwainGroups;
  706. begin
  707. {Convert from Structure.SupportedGroups to TTwainGroups}
  708. Result := [];
  709. Include(Result, tgControl);
  710. if DG_IMAGE AND Structure.SupportedGroups <> 0 then
  711. Include(Result, tgImage);
  712. if DG_AUDIO AND Structure.SupportedGroups <> 0 then
  713. Include(Result, tgAudio);
  714. end;
  715. {Sets avaliable groups}
  716. procedure TTwainIdentity.SetGroups(const Value: TTwainGroups);
  717. begin
  718. {Convert from TTwainGroups to Structure.SupportedGroups}
  719. Structure.SupportedGroups := DG_CONTROL;
  720. if tgImage in Value then
  721. Structure.SupportedGroups := Structure.SupportedGroups or DG_IMAGE;
  722. if tgAudio in Value then
  723. Structure.SupportedGroups := Structure.SupportedGroups or DG_AUDIO;
  724. end;
  725. { TCustomDelphiTwain component implementation }
  726. {Loads twain library and returns if it loaded sucessfully}
  727. function TCustomDelphiTwain.LoadLibrary(): Boolean;
  728. var
  729. TwainDirectory: String;
  730. begin
  731. {The library must not be already loaded}
  732. if (not LibraryLoaded) then
  733. begin
  734. Result := FALSE; {Initially returns FALSE}
  735. {Searches for Twain directory}
  736. TwainDirectory := GetTwainDirectory();
  737. {Continue only if twain is installed in an known directory}
  738. if TwainDirectory <> '' then
  739. begin
  740. fHandle := Windows.LoadLibrary(PChar(TwainDirectory + TWAINLIBRARY));
  741. {If the library was sucessfully loaded}
  742. if (fHandle <> INVALID_HANDLE_VALUE) then
  743. begin
  744. {Obtains method handle}
  745. @fTwainProc := GetProcAddress(fHandle, MAKEINTRESOURCE(1));
  746. {Returns TRUE/FALSE if the method was obtained}
  747. Result := (@fTwainProc <> nil);
  748. {If the method was not obtained, also free the library}
  749. if not Result then
  750. begin
  751. {Free the handle and clears the variable}
  752. Windows.FreeLibrary(fHandle);
  753. fHandle := 0;
  754. end {if not Result}
  755. end
  756. else
  757. {If it was not loaded, clears handle value}
  758. fHandle := 0;
  759. end {if TwainDirectory <> ''};
  760. end
  761. else
  762. {If it was already loaded, returns true, since that is}
  763. {what was supposed to happen}
  764. Result := TRUE;
  765. {In case the method was sucessful, updates property}
  766. if Result then fLibraryLoaded := TRUE;
  767. end;
  768. {Unloads twain and returns if it unloaded sucessfully}
  769. function TCustomDelphiTwain.UnloadLibrary(): Boolean;
  770. begin
  771. {The library must not be already unloaded}
  772. if (LibraryLoaded) then
  773. begin
  774. {Unloads the source manager}
  775. SourceManagerLoaded := FALSE;
  776. {Just call windows method to unload}
  777. Result := Windows.FreeLibrary(Handle);
  778. {If it was sucessfull, also clears handle value}
  779. if Result then fHandle := 0;
  780. {Updates property}
  781. fLibraryLoaded := not Result;
  782. end
  783. else
  784. {If it was already unloaded, returns true, since that is}
  785. {what was supposed to happen}
  786. Result := TRUE;
  787. {In case the method was sucessful, updates property}
  788. {if Result then }fLibraryLoaded := FALSE;
  789. MessageTimer_Disable;
  790. end;
  791. {Enumerate the avaliable devices after Source Manager is loaded}
  792. function TCustomDelphiTwain.EnumerateDevices(): Boolean;
  793. var
  794. NewSource: TTwainSource;
  795. CallRes : TW_UINT16;
  796. begin
  797. {Booth library and source manager must be loaded}
  798. if (LibraryLoaded and SourceManagerLoaded) then
  799. begin
  800. {Clears the preview list of sources}
  801. ClearDeviceList();
  802. {Allocate new identity and tries to enumerate}
  803. NewSource := TTwainSource.Create(Self);
  804. CallRes := TwainProc(AppInfo, nil, DG_CONTROL, DAT_IDENTITY,
  805. MSG_GETFIRST, @NewSource.Structure);
  806. if CallRes = TWRC_SUCCESS then
  807. repeat
  808. {Add this item to the list}
  809. DeviceList.Add(NewSource);
  810. {Allocate memory for the next}
  811. NewSource := TTwainSource.Create(Self);
  812. NewSource.TransferMode := Self.TransferMode;
  813. NewSource.fIndex := DeviceList.Count;
  814. {Try to get the next item}
  815. until TwainProc(AppInfo, nil, DG_CONTROL, DAT_IDENTITY,
  816. MSG_GETNEXT, @NewSource.Structure) <> TWRC_SUCCESS;
  817. {Set that the component has enumerated the devices}
  818. {if everything went correctly}
  819. Result := TRUE;
  820. fHasEnumerated := Result;
  821. {Dispose un-needed source object}
  822. NewSource.Free;
  823. end
  824. else Result := FALSE; {If library and source manager aren't loaded}
  825. end;
  826. {Procedure to load and unload twain library and update property}
  827. procedure TCustomDelphiTwain.SetLibraryLoaded(const Value: Boolean);
  828. begin
  829. {The value must be changing to activate}
  830. if (Value <> fLibraryLoaded) then
  831. begin
  832. {Depending on the parameter load/unload the library and updates}
  833. {property whenever it loaded or unloaded sucessfully}
  834. if Value then LoadLibrary()
  835. else {if not Value then} UnloadLibrary();
  836. end {if (Value <> fLibraryLoaded)}
  837. end;
  838. {Loads twain source manager}
  839. function TCustomDelphiTwain.LoadSourceManager(): Boolean;
  840. begin
  841. {The library must be loaded}
  842. if LibraryLoaded and not SourceManagerLoaded then begin
  843. {Loads source manager}
  844. Result := (fTwainProc(AppInfo, nil, DG_CONTROL, DAT_PARENT,
  845. MSG_OPENDSM, @VirtualWindow) = TWRC_SUCCESS);
  846. end else begin
  847. {The library is not loaded, thus the source manager could}
  848. {not be loaded}
  849. Result := FALSE or SourceManagerLoaded;
  850. end;
  851. {In case the method was sucessful, updates property}
  852. if Result then fSourceManagerLoaded := TRUE;
  853. end;
  854. procedure TCustomDelphiTwain.RefreshVirtualWindow;
  855. begin
  856. //BUG WORKAROUND
  857. DoDestroy;
  858. DoCreate;
  859. if LoadLibrary then
  860. SourceManagerLoaded := True;
  861. end;
  862. {UnLoads twain source manager}
  863. function TCustomDelphiTwain.UnloadSourceManager(forced: boolean): Boolean;
  864. begin
  865. {The library must be loaded}
  866. if LibraryLoaded and SourceManagerLoaded then
  867. begin
  868. {Clears the list of sources}
  869. ClearDeviceList();
  870. {Unload source manager}
  871. if not forced then
  872. Result := (TwainProc(AppInfo, nil, DG_CONTROL, DAT_PARENT, MSG_CLOSEDSM, @VirtualWindow) = TWRC_SUCCESS)
  873. else result:=true;
  874. end
  875. else
  876. {The library is not loaded, meaning that the Source Manager isn't either}
  877. Result := TRUE;
  878. {In case the method was sucessful, updates property}
  879. if Result then fSourceManagerLoaded := FALSE;
  880. end;
  881. procedure TCustomDelphiTwain.DoCreate;
  882. begin
  883. {Create source list}
  884. DeviceList := TPointerList.Create;
  885. {Clear variables}
  886. fSourcesLoaded := 0;
  887. fHandle := 0;
  888. @fTwainProc := nil;
  889. fSourceManagerLoaded := FALSE;
  890. fHasEnumerated := FALSE;
  891. fTransferMode := ttmNative;
  892. {Creates the object to allow the user to set the application}
  893. {information to inform twain source manager and sources}
  894. fInfo := TTwainIdentity.Create;
  895. AppInfo := @fInfo.Structure;
  896. end;
  897. procedure TCustomDelphiTwain.DoDestroy;
  898. begin
  899. {Completely unload the library}
  900. LibraryLoaded := FALSE;
  901. {Free the object}
  902. fInfo.Free;
  903. {Clears and free source list}
  904. ClearDeviceList();
  905. DeviceList.Free();
  906. end;
  907. {Returns a TMsg structure}
  908. function MakeMsg(const Handle: THandle; uMsg: UINT; wParam: WPARAM;
  909. lParam: LPARAM): TMsg;
  910. begin
  911. {Fill structure with the parameters}
  912. Result.hwnd := Handle;
  913. Result.message := uMsg;
  914. Result.wParam := wParam;
  915. Result.lParam := lParam;
  916. GetCursorPos(Result.pt);
  917. end;
  918. {Procedure to load or unloaded the twain source manager}
  919. procedure TCustomDelphiTwain.SetSelectedSourceIndex(const Value: Integer);
  920. begin
  921. fSelectedSourceIndex := Value;
  922. end;
  923. procedure TCustomDelphiTwain.SetSourceManagerLoaded(const Value: Boolean);
  924. begin
  925. {The library must be loaded to have access to the method}
  926. if LibraryLoaded and (Value <> fSourceManagerLoaded) then
  927. begin
  928. {Load/unload the source manager}
  929. if Value then LoadSourceManager()
  930. else {if not Value then} UnloadSourceManager(false);
  931. end {if LibraryLoaded}
  932. end;
  933. {Clears the list of sources}
  934. procedure TCustomDelphiTwain.ClearDeviceList();
  935. var
  936. i: Integer;
  937. begin
  938. {Deallocate pTW_IDENTITY}
  939. FOR i := 0 TO DeviceList.Count - 1 DO
  940. TTwainSource(DeviceList.Item[i]).Free;
  941. {Clears the list}
  942. DeviceList.Clear;
  943. {Set trigger to tell that it has not enumerated again yet}
  944. fHasEnumerated := FALSE;
  945. end;
  946. {Finds a matching source index}
  947. function TCustomDelphiTwain.FindSource(Value: pTW_IDENTITY): Integer;
  948. var
  949. i : Integer;
  950. begin
  951. Result := -1; {Default result}
  952. {Search for this source in the list}
  953. for i := 0 TO SourceCount - 1 DO
  954. if CompareMem(@Source[i].Structure, PAnsiChar(Value), SizeOf(TW_IDENTITY)) then
  955. begin
  956. {Return index and exit}
  957. Result := i;
  958. break;
  959. end; {if CompareMem, for i}
  960. end;
  961. {Allows Twain to display a dialog to let the user choose any source}
  962. {and returns the source index in the list}
  963. function TCustomDelphiTwain.SelectSource: Integer;
  964. begin
  965. Result := -1; {Default result}
  966. {Booth library and source manager must be loaded}
  967. if (LibraryLoaded and SourceManagerLoaded) then
  968. begin
  969. Result := CustomSelectSource;
  970. SelectedSourceIndex := Result;
  971. end {(LibraryLoaded and SourceManagerLoaded)}
  972. end;
  973. {Returns the number of sources}
  974. function TCustomDelphiTwain.GetSourceCount(): Integer;
  975. begin
  976. {Library and source manager must be loaded}
  977. if (LibraryLoaded and SourceManagerLoaded) then
  978. begin
  979. {Enumerate devices, if needed}
  980. if not HasEnumerated then EnumerateDevices();
  981. {Returns}
  982. Result := DeviceList.Count;
  983. end
  984. {In case library and source manager aren't loaded, returns 0}
  985. else Result := 0
  986. end;
  987. {Returns the default source}
  988. function TCustomDelphiTwain.GetDefaultSource: Integer;
  989. var
  990. Identity: TW_IDENTITY;
  991. begin
  992. {Call twain to display the dialog}
  993. if SourceManagerLoaded and (TwainProc(AppInfo, nil, DG_CONTROL, DAT_IDENTITY,
  994. MSG_GETDEFAULT, @Identity) = TWRC_SUCCESS) then
  995. Result := FindSource(@Identity)
  996. else Result := 0 {Returns}
  997. end;
  998. {Returns a source from the list}
  999. function TCustomDelphiTwain.GetSelectedSource: TTwainSource;
  1000. begin
  1001. if SourceCount = 0 then begin
  1002. Result := nil;
  1003. end else begin
  1004. if (fSelectedSourceIndex >= 0) and (fSelectedSourceIndex < SourceCount) then
  1005. Result := Source[fSelectedSourceIndex]
  1006. else
  1007. Result := nil;
  1008. end;
  1009. end;
  1010. function TCustomDelphiTwain.GetSelectedSourceIndex: Integer;
  1011. begin
  1012. Result := fSelectedSourceIndex;
  1013. end;
  1014. function TCustomDelphiTwain.GetSource(Index: Integer): TTwainSource;
  1015. begin
  1016. {Both library and source manager must be loaded}
  1017. if (LibraryLoaded and SourceManagerLoaded) then
  1018. begin
  1019. {If index is in range, returns}
  1020. {(Call to SourceCount property enumerates the devices, if needed)}
  1021. if Index in [0..SourceCount - 1] then
  1022. Result := DeviceList.Item[Index]
  1023. else if (Index = -1) and (SourceCount > 0) then
  1024. Result := DeviceList.Item[GetDefaultSource]
  1025. {Unknown object, returns nil}
  1026. else Result := nil;
  1027. end
  1028. {In case either the library or the source manager aren't}
  1029. {loaded, it returns nil}
  1030. else Result := nil
  1031. end;
  1032. {Object being created}
  1033. constructor TCustomDelphiTwain.Create;
  1034. begin
  1035. inherited Create;
  1036. fLibraryLoaded:=false;
  1037. fSelectedSourceIndex := -1;
  1038. DoCreate;
  1039. end;
  1040. {Object being destroyed}
  1041. destructor TCustomDelphiTwain.Destroy;
  1042. begin
  1043. DoDestroy;
  1044. {Let ancestor class handle}
  1045. inherited Destroy;
  1046. end;
  1047. {Updates the application information object}
  1048. procedure TCustomDelphiTwain.SetInfo(const Value: TTwainIdentity);
  1049. begin
  1050. {Assign one object to another}
  1051. fInfo.Assign(Value);
  1052. end;
  1053. { TTwainSource object implementation }
  1054. {Used with property SourceManagerLoaded to test if the source manager}
  1055. {is loaded or not.}
  1056. function TTwainSource.GetSourceManagerLoaded: Boolean;
  1057. begin
  1058. {Obtain information from owner TCustomDelphiTwain}
  1059. Result := Owner.SourceManagerLoaded;
  1060. end;
  1061. {Sets if the source is loaded}
  1062. procedure TTwainSource.SetLoaded(const Value: Boolean);
  1063. begin
  1064. {Value should be changing}
  1065. if (Value <> fLoaded) then
  1066. begin
  1067. {Loads or unloads the source}
  1068. if Value then LoadSource()
  1069. else {if not Value then} UnloadSource();
  1070. end {if (Value <> fLoaded)}
  1071. end;
  1072. {Sets if the source is enabled}
  1073. procedure TTwainSource.SetEnabled(const Value: Boolean);
  1074. begin
  1075. {Source must be already enabled and value changing}
  1076. if (Loaded) and (Value <> fEnabled) then
  1077. begin
  1078. {Enables/disables}
  1079. if Value then EnableSource(ShowUI, Modal)
  1080. else {if not Value then} DisableSource();
  1081. end {if (Loaded) and (Value <> fEnabled)}
  1082. end;
  1083. {Enables the source}
  1084. function TTwainSource.EnableSource(ShowUI, Modal: Boolean): Boolean;
  1085. var
  1086. twUserInterface: TW_USERINTERFACE;
  1087. begin
  1088. {Source must be loaded and the value changing}
  1089. if (Loaded) and (not Enabled) then
  1090. begin
  1091. {Builds UserInterface structure}
  1092. twUserInterface.ShowUI := ShowUI;
  1093. twUserInterface.ModalUI := Modal;
  1094. twUserInterface.hParent := Owner.CustomGetParentWindow;
  1095. //npeter may be it is better to send messages to VirtualWindow
  1096. //I am not sure, but it seems more stable with a HP TWAIN driver
  1097. //it was: := GetActiveWindow;
  1098. //fEnabled := TRUE;
  1099. Owner.MessageTimer_Enable;
  1100. {Call method}
  1101. Result := (Owner.TwainProc(AppInfo, @Structure, DG_CONTROL,
  1102. DAT_USERINTERFACE, MSG_ENABLEDS, @twUserInterface) in
  1103. [TWRC_SUCCESS, TWRC_CHECKSTATUS]);
  1104. end
  1105. else {If it's either not loaded or already enabled}
  1106. {If it is not loaded}
  1107. Result := FALSE or Enabled;
  1108. {Updates property}
  1109. if (Result = TRUE) then fEnabled := TRUE;
  1110. end;
  1111. {Disables the source}
  1112. function TTwainSource.DisableSource(): Boolean;
  1113. var
  1114. twUserInterface: TW_USERINTERFACE;
  1115. begin
  1116. {Source must be loaded and the value changing}
  1117. if (Loaded) and (Enabled) then
  1118. begin
  1119. {Call method}
  1120. Result := (Owner.TwainProc(AppInfo, @Structure, DG_CONTROL,
  1121. DAT_USERINTERFACE, MSG_DISABLEDS, @twUserInterface) = TWRC_SUCCESS);
  1122. {Call notification event if being used}
  1123. if (Result) and (Assigned(Owner.OnSourceDisable)) then
  1124. Owner.OnSourceDisable(Owner, Index);
  1125. end
  1126. else {If it's either not loaded or already disabled}
  1127. {If it is not loaded}
  1128. Result := TRUE;
  1129. {Updates property}
  1130. //if (Result = TRUE) then fEnabled := FALSE;
  1131. fEnabled := False;
  1132. Owner.MessageTimer_Disable;
  1133. end;
  1134. {Loads the source}
  1135. function TTwainSource.LoadSource: Boolean;
  1136. begin
  1137. {Only loads if it is not already loaded}
  1138. if Not Loaded then
  1139. begin
  1140. Result := (Owner.TwainProc(AppInfo, nil, DG_CONTROL, DAT_IDENTITY,
  1141. MSG_OPENDS, @Structure) = TWRC_SUCCESS);
  1142. {Increase the loaded sources count variable}
  1143. if Result then inc(Owner.fSourcesLoaded);
  1144. end
  1145. else
  1146. {If it was already loaded, returns true}
  1147. Result := TRUE;
  1148. {In case the method was sucessful, updates property}
  1149. if Result then
  1150. fLoaded := TRUE;
  1151. end;
  1152. {Unloads the source}
  1153. function TTwainSource.UnloadSource: Boolean;
  1154. begin
  1155. {Only unloads if it is loaded}
  1156. if Loaded then
  1157. begin
  1158. {If the source was enabled, disable it}
  1159. DisableSource();
  1160. {Call method to load}
  1161. Result := (Owner.TwainProc(AppInfo, nil, DG_CONTROL, DAT_IDENTITY,
  1162. MSG_CLOSEDS, @Structure) = TWRC_SUCCESS);
  1163. {Decrease the loaded sources count variable}
  1164. if Result then dec(Owner.fSourcesLoaded);
  1165. end
  1166. else
  1167. {If it was already unloaded, returns true}
  1168. Result := TRUE;
  1169. {In case the method was sucessful, updates property}
  1170. fLoaded := FALSE;
  1171. end;
  1172. {Object being destroyed}
  1173. destructor TTwainSource.Destroy;
  1174. begin
  1175. {If loaded, unloads source}
  1176. UnloadSource();
  1177. {Let ancestor class process}
  1178. inherited Destroy;
  1179. end;
  1180. {Returns a pointer to the application}
  1181. function TTwainSource.GetAppInfo: pTW_IDENTITY;
  1182. begin
  1183. Result := Owner.AppInfo;
  1184. end;
  1185. {Returns a pointer to the source identity}
  1186. function TTwainSource.GetStructure: pTW_IDENTITY;
  1187. begin
  1188. Result := @Structure;
  1189. end;
  1190. {Object being created}
  1191. constructor TTwainSource.Create(AOwner: TCustomDelphiTwain);
  1192. begin
  1193. {Allows ancestor class to process}
  1194. inherited Create;
  1195. {Initial values}
  1196. fTransferMode := AOwner.TransferMode;
  1197. fLoaded := FALSE;
  1198. fShowUI := TRUE;
  1199. fEnabled := FALSE;
  1200. fModal := TRUE;
  1201. {Stores owner}
  1202. fOwner := AOwner;
  1203. end;
  1204. {Set source transfer mode}
  1205. {function TTwainSource.ChangeTransferMode(
  1206. NewMode: TTwainTransferMode): TCapabilityRet;
  1207. const
  1208. TransferModeToTwain: Array[TTwainTransferMode] of TW_UINT16 =
  1209. (TWSX_FILE, TWSX_NATIVE, TWSX_MEMORY);
  1210. var
  1211. Value: TW_UINT16;
  1212. begin
  1213. //Set transfer mode method
  1214. Value := TransferModeToTwain[NewMode];
  1215. Result := SetOneValue(ICAP_XFERMECH, TWTY_UINT16, @Value);
  1216. TransferMode := NewMode;
  1217. end;}
  1218. {Message received in the event loop}
  1219. function TTwainSource.ProcessMessage(const Msg: TMsg): Boolean;
  1220. var
  1221. twEvent: TW_EVENT;
  1222. begin
  1223. {Make twEvent structure}
  1224. twEvent.TWMessage := MSG_NULL;
  1225. twEvent.pEvent := TW_MEMREF(@Msg);
  1226. {Call Twain procedure to handle message}
  1227. Result := (Owner.TwainProc(AppInfo, @Structure, DG_CONTROL, DAT_EVENT,
  1228. MSG_PROCESSEVENT, @twEvent) = TWRC_DSEVENT);
  1229. {If it is a message from the source, process}
  1230. if Result then
  1231. case twEvent.TWMessage of
  1232. {No message from the source}
  1233. MSG_NULL: exit;
  1234. {Requested to close the source}
  1235. MSG_CLOSEDSREQ:
  1236. begin
  1237. {Call notification event}
  1238. if (Assigned(Owner.OnAcquireCancel)) then
  1239. Owner.OnAcquireCancel(Owner, Index);
  1240. if Assigned(Owner.OnTransferComplete) then
  1241. Owner.OnTransferComplete(Owner, Index, True);
  1242. {Disable the source}
  1243. DisableSource();
  1244. Owner.RefreshVirtualWindow;
  1245. end;
  1246. {Ready to transfer the images}
  1247. MSG_XFERREADY:
  1248. {Call method to transfer}
  1249. TransferImages();
  1250. MSG_CLOSEDSOK:
  1251. result:=true;
  1252. MSG_DEVICEEVENT:
  1253. result:=true;
  1254. end {case twEvent.TWMessage}
  1255. end;
  1256. {Returns return status information}
  1257. function TTwainSource.GetReturnStatus: TW_UINT16;
  1258. var
  1259. StatusInfo: TW_STATUS;
  1260. begin
  1261. {The source must be loaded in order to get the status}
  1262. if Loaded then
  1263. begin
  1264. {Call method to get the information}
  1265. Owner.TwainProc(AppInfo, @Structure, DG_CONTROL, DAT_STATUS, MSG_GET,
  1266. @StatusInfo);
  1267. Result := StatusInfo.ConditionCode;
  1268. end else Result := 0 {In case it was called while the source was not loaded}
  1269. end;
  1270. {Converts from a result to a TCapabilityRec}
  1271. function TTwainSource.ResultToCapabilityRec(
  1272. const Value: TW_UINT16): TCapabilityRet;
  1273. begin
  1274. {Test result code to return}
  1275. case Value of
  1276. {Successull, copy handle and return a success value}
  1277. TWRC_SUCCESS: Result := crSuccess;
  1278. {Error, get more on the error, and return result}
  1279. {case} else
  1280. case GetReturnStatus() of
  1281. TWCC_CAPUNSUPPORTED: Result := crUnsupported;