Take the 2-minute tour ×

I have downloaded opensource delphi twain component (TDelphiTwain). The interesting thing is, that when placed and saved on the form it creates bad dfm entry for itself.

  object DelphiTwain: TDelphiTwain
    OnSourceDisable = DelphiTwainSourceDisable
    OnSourceSetupFileXfer = DelphiTwainSourceSetupFileXfer
    TransferMode = ttmMemory
    SourceCount = 0
    Info.MajorVersion = 1
    Info.MinorVersion = 0
    Info.Language = tlDanish
    Info.CountryCode = 1
    Info.Groups = [tgControl, tgImage, tgAudio, MinorVersion]
    Info.VersionInfo = 'Application name'
    Info.Manufacturer = 'Application manufacturer'
    Info.ProductFamily = 'App product family'
    Info.ProductName = 'App product name'
    LibraryLoaded = False
    SourceManagerLoaded = False
    Left = 520
    Top = 136

The problem is with the line:

   Info.Groups = [tgControl, tgImage, tgAudio, MinorVersion]

There are only three possible elements:

tgControl, tgImage and tgAudio

It adds MinorVersion everytime I Save the form. When the app is run I get the error that there is invalid property for Info.Groups. When i rmeove the bad part manually and without leaving dfm file the app starts ok.

I looked in the internet and there was one inquire regarding these strange issue, unfortunately it hasn't been resolved.

I think that there is some sort of memory corruption. In the post in teh internet, strange signs were displayed ...

Has anyone worked with that component or could give me some hint how this could be fixed?

share|improve this question
Have you got a link to that other inquiry? –  GolezTrol Dec 27 '12 at 15:30

2 Answers 2

up vote 5 down vote accepted

The error seems to be in TTwainIdentity.GetGroups where result is not initialized. You can try to change the code by replacing

Include(Result, tgControl);


Result := [tgControl]; 

You have to recompile the package to make this change work inside the IDE.

share|improve this answer
Or better yet, Result := []; if DG_CONTROL AND Structure.SupportedGroups <> 0 then Include(Result, tgControl); (and similarly for SetGroups) –  hvd Dec 27 '12 at 15:34
It solves the problem. I tick your answer because you were first. Thank You –  John Dec 28 '12 at 7:26

I don't know the component, but I think the problem lies in the TTwainIdentity.GetGroups method. It starts like this:

  Include(Result, tgControl);

This means that it assumes that Result is initialized to an empty set. However, Result may contain garbage, and not necessarily an empty set. Change this method to look like this:

function TTwainIdentity.GetGroups(): TTwainGroups;
  {Convert from Structure.SupportedGroups to TTwainGroups}
  Result := [tgControl];
  if DG_IMAGE AND Structure.SupportedGroups <> 0 then
    Include(Result, tgImage);
  if DG_AUDIO AND Structure.SupportedGroups <> 0 then
    Include(Result, tgAudio);

Some result types will not throw a compiler warning about not being initialized, but that doesn't mean they are empty. Same goes, for instance, for strings. See also: http://qc.embarcadero.com/wc/qcmain.aspx?d=894

But still, it is odd that this happens. Apparently, Delphi tries to find the name of the given item in the set and accidentally finds the name of another property. It seems to me that quite some checks in writing the dfm are missing if this happens. :)

share|improve this answer
"It seems to me that quite some checks in writing the dfm are missing if this happens. :)" -- Delphi assumes but does not check that the value of the property is a valid value of the property's type, probably because in the general case, it cannot check. It would not surprise you to see an access violation on saving if reading a string property gives you string(-1), would it? :) –  hvd Dec 27 '12 at 15:47
You can easily set items in a set that don't exist in the enumeration on which the set is based. A set is just an ordinal after all. I don't know if Delphi can check this properly when writing the dfm file, and maybe it isn't the right place to check it. But then again, it is odd that a Result variable for a set isn't initialized and can by default contain an invalid value without the compiler complaining. It's not an error per se, but there are some loose ends which apparently create an easy trap. A string won't be -1 unless you try really hard. :) –  GolezTrol Dec 27 '12 at 16:01
Result is a local variable, and local variables are not initialized. This means that Result is initially pointing to random memory content, which is apparently what's causing the problem here. The quoted line of code basically says "take the random memory at wherever Result is pointing, treat it like it's a TTwainGroups set, and include the tgControl value in it". –  Ken White Dec 27 '12 at 16:08
+1, BTW. Your answer would solve the problem completely, because it properly initializes Result. :-) –  Ken White Dec 27 '12 at 16:13
@KenWhite Thanks! The reason mistakes like this are made, is that some types are initialized, for instance arrays and interfaces. Other types are not, but usually generate compiler warnings. And there's the third kind that isn't intialized and doesn't generate a warning either. Strings are the most common example of this type. Many people think that Delphi initializes a Result to '', but it doesn't. –  GolezTrol Dec 27 '12 at 16:17

Your Answer


