Dave Nottage 557 Posted June 13, 2019 Has anyone managed to make DelphiTwain: http://www.kluug.net/delphitwain.php work on 64-bit? The code loads the Twain DLL OK (TWAINDSM.DLL), however for me it fails in the LoadSourceManager routine: FTwainProc(Info, nil, DG_CONTROL, DAT_PARENT, MSG_OPENDSM, @FVirtualWindow) Which returns a result of TWRC_FAILURE. The corresponding condition code is TWCC_BADVALUE Share this post Link to post
David Heffernan 2345 Posted June 13, 2019 You followed the instructions for 64 bit compilers, made the necessary change to the code outlined on the page you linked, obtained 64 bit drivers etc? Share this post Link to post
Dave Nottage 557 Posted June 13, 2019 16 hours ago, David Heffernan said: You followed the instructions for 64 bit compilers, made the necessary change to the code outlined on the page you linked, obtained 64 bit drivers etc? Yes, since as I said, it loads the driver OK. The problem comes after that Share this post Link to post
stijnsanders 35 Posted June 14, 2019 (edited) Even so, is TWINDSM.DLL you're using also 64-bits? (Is this the place to get current ones?) Edited June 14, 2019 by stijnsanders Share this post Link to post
Dave Nottage 557 Posted June 17, 2019 On 6/15/2019 at 6:38 AM, stijnsanders said: Even so, is TWINDSM.DLL you're using also 64-bits? Yes, TWAINDSM.DLL is 64 bits. On 6/15/2019 at 6:38 AM, stijnsanders said: (Is this the place to get current ones?) From here: https://github.com/twain/twain-dsm/tree/master/Releases/dsm_020402/windows/64 Though I've now tried those from the link you gave, with the same result. In case anyone asks: I have already also verified that the correct DLL is being loaded by using GetModuleName for the handle returned. Share this post Link to post
rvk 33 Posted June 17, 2019 On 6/13/2019 at 9:03 AM, Dave Nottage said: Which returns a result of TWRC_FAILURE. The corresponding condition code is TWCC_BADVALUE So you provided a "bad value" Here it works fine with VueScan as 64 bit scan-sourcedriver. What/which scannerdriver did you try/use? Share this post Link to post
Dave Nottage 557 Posted June 17, 2019 10 hours ago, rvk said: What/which scannerdriver did you try/use? It works for Win32, and reports the following sources: Brother DS-620 WIA-Apple iPhone (my iPhone) WIA-Galaxy Tab Active2 (an Android device connected to the computer) For Win64, it errors, as per my original post Share this post Link to post
rvk 33 Posted June 18, 2019 (edited) On 64 bit it worked for me but I did't have any scan-sources. WIA sources are 32-bit and not visible in 64 bit for me. Installing the VueScan gave me a 64 bit source. What Delphi version do you use? Are you using VLC of FMX? Did you try the DelphiTwain\examples\VCL2\DelphiTwainDemo2 example? (which worked for me on 64 bit) Edited June 18, 2019 by rvk Share this post Link to post
Dave Nottage 557 Posted July 11, 2019 Delphi Rio 10.3.1, VCL. I was having problems with refactored code based on the original. I went back to the very original code and managed to make it work, so something must have gone awry in the refactor. Next time it is refactored there'll be incremental testing 🙂 Next issue is: when it is used in a DLL, the app locks up after the scan has completed. Share this post Link to post
rvk 33 Posted July 11, 2019 4 hours ago, Dave Nottage said: Next issue is: when it is used in a DLL, the app locks up after the scan has completed. Hard to say what could be the cause without example-source of DLL and calling procedure. Share this post Link to post
Dave Nottage 557 Posted July 18, 2019 I discovered that it is throwing an AV at this part of TTwainSource.ReadNative: DibInfo := GlobalLock(Handle); ColorTableSize := (DibNumColors(DibInfo) * SizeOf(RGBQUAD)); // <---- AV here when it calls DibNumColors, as DibInfo is nil The code is inside a DLL written for Windows Terminal Services. The same code works fine in a DLL that is just loaded via a plain application, so perhaps it has something to with WTS? If I call SysErrorMessage(GetLastError) after the GlobalLock, the message is: The handle is invalid. The value for Handle is non-zero. Share this post Link to post
David Heffernan 2345 Posted July 18, 2019 (edited) Well, apparently GlobalLock failed with an invalid handle. Why is that? You need to work out where Handle came from and why it is not valid. Edited July 18, 2019 by David Heffernan Share this post Link to post
Dave Nottage 557 Posted July 18, 2019 31 minutes ago, David Heffernan said: You need to work out where Handle came from It came from this call in the TTwainSource.TransferImages method: rc := Owner.TwainProc(AppInfo, @Structure, DG_IMAGE, DAT_IMAGENATIVEXFER, MSG_GET, @hNative) (TwainProc is the method exported by the Twain DLL) 32 minutes ago, David Heffernan said: why it is not valid. The more pertinent question is: why does it return a valid handle in a DLL that is not loaded by WTS, and why is it apparently invalid in a DLL loaded by WTS? I figured there might be something else I need to do to ensure that it returns a valid handle in WTS. Share this post Link to post
rvk 33 Posted July 18, 2019 Are you using a redirected scanner in WTS? Or is the scanner-software (and 64bit driver) directly installed on the WTS machine? Does the DelphiTwainDemo2 example work in WTS? 1 hour ago, Dave Nottage said: The code is inside a DLL written for Windows Terminal Services. The same code works fine in a DLL that is just loaded via a plain application, so perhaps it has something to with WTS? Not sure what you mean by this? In Windows Terminal Services (now called Remote Desktop Services, RDS) you also just run plain applications, don't you? Or do you mean it's running under Windows Services? (which is hugely different) Share this post Link to post
David Heffernan 2345 Posted July 18, 2019 52 minutes ago, Dave Nottage said: The more pertinent question is: why does it return a valid handle in a DLL that is not loaded by WTS, and why is it apparently invalid in a DLL loaded by WTS? Given that you are the only one with any code, and any ability to debug, you are best placed to investigate. My advice is to stop guessing and do some old fashioned debugging. Share this post Link to post
Dave Nottage 557 Posted July 18, 2019 4 hours ago, rvk said: is the scanner-software (and 64bit driver) directly installed on the WTS machine? That is correct. 4 hours ago, rvk said: Not sure what you mean by this? In Windows Terminal Services (now called Remote Desktop Services, RDS) you also just run plain applications, don't you? This is what I mean: https://docs.microsoft.com/en-us/windows/win32/termserv/virtual-channel-client-dll So yes, RDS; I'm just used to the other terminology. As above, the DLL is on the same machine as the Twain driver. RDS loads the DLL when a session is started to the remote application, which communicates to the virtual channel client DLL via RDS. The remote application notifies the virtual channel to scan an image, and the DLL makes calls via the Delphi Twain code to enumerate the sources, and start scanning an image. The scanning "in progress" dialog shows OK, however the code fails in TTwainSource.ReadNative, as described earlier. The identical code to allow the user to select the source and start the scan works in a DLL loaded by a test app; it fails in the virtual channel client (RDS) DLL. I just hoped someone might know why there's a difference, because debugging isn't telling me anything other than Windows claiming that the handle is invalid. Share this post Link to post
David Heffernan 2345 Posted July 18, 2019 Nobody other than you knows where this handle comes from. For all we know you've got a simple 32/64 bit truncation error. But we can't see the relevant code. Share this post Link to post
rvk 33 Posted July 18, 2019 (edited) 27 minutes ago, Dave Nottage said: As above, the DLL is on the same machine as the Twain driver. RDS loads the DLL when a session is started to the remote application, which communicates to the virtual channel client DLL via RDS. So, the drivers are not loaded on the server itself? I'm not familiar with Virtual Channels in RDP, but I think this would mean you have the DLL on the local client and want the application, which runs on the server side in RDP, have access to the local scanner through the Virtual Channels-technology? Just like a Redirected Printer uses Virtual Channels. That's a whole lot of places where things can go wrong (that's why I asked if the scanner and drivers and DLL where locally on the server side in the RDP session itself). What was the value of the return-code on this line (in TTwainSource.TransferImages for TransferMode ttmNative): rc := Owner.TwainProc(AppInfo, @Structure, DG_IMAGE, DAT_IMAGENATIVEXFER, MSG_GET, @hNative); That seems to be where hNative gets its value (which fails). It seems the value is not checked for success there ( if rc <> TWRC_SUCCESS then ... should give error ) Edited July 18, 2019 by rvk Share this post Link to post
Dave Nottage 557 Posted July 18, 2019 15 minutes ago, rvk said: So, the drivers are not loaded on the server itself? Not on the remote machine no, since it does not have the scanner connected; the local machine does, where the RDS DLL resides. 16 minutes ago, rvk said: It seems the value is not checked for success there ( if rc <> TWRC_SUCCESS then ... should give error ) In this call, rc can be one of TWRC_XFERDONE, TWRC_CANCEL, or one of the error values. In this case, it is returning TWRC_XFERDONE (which is why it proceeds to the ReadNative call, where the error occurs, as per one of my earlier messages) so one would hope that it is returning a valid value for hNative. As far as GlobalLock is concerned, it apparently is not. Share this post Link to post
rvk 33 Posted July 18, 2019 Are your connecting client, the used mstsc.exe and RDP-session (including your app) ALL 64 bit? (If not, you can't rely on the Virtual Channel Client DLL) Did you check the numerical value of hNative (i.e. not being 0)? Share this post Link to post
Dave Nottage 557 Posted July 18, 2019 17 minutes ago, rvk said: Are your connecting client, the used mstsc.exe and RDP-session (including your app) ALL 64 bit? I'll have to check mstsc and RDP-session after the weekend, but the others are 64-bit. Regardless, the DLL succeeds in enumerating the sources, the scanning progress dialog shows, and it completes the scan; it is only when it reaches the ReadNative method and calls GlobalLock that there's an issue - why would all that comes before it succeed? 21 minutes ago, rvk said: Did you check the numerical value of hNative (i.e. not being 0)? Yes, it's non-zero. Share this post Link to post
rvk 33 Posted July 18, 2019 (edited) 45 minutes ago, Dave Nottage said: Yes, it's non-zero. So the call gives a TWRC_XFERDONE (successful) but the handle could still be invalid. The handle (hNative) is a TW_UINT32 (which is a Cardinal/32bit). I wonder if it shouldn't be a TW_Handle (which should be a NativeUInt and UInt64 on 64 bit). At least GlobalLock expects a THandle (which is UInt64 on 64 bit). Doesn't seem really wise to stuff a handle in an Cardinal/32bit on 64 bit (which like David already mentioned, could be just a simple 32/64 bit truncation error). Strange this worked locally on the machine itself but fails on RDP. Maybe the handle-numbers are much larger and it fails. Edited July 18, 2019 by rvk 1 Share this post Link to post
Dave Nottage 557 Posted July 23, 2019 On 7/19/2019 at 12:11 AM, rvk said: The handle (hNative) is a TW_UINT32 (which is a Cardinal/32bit). I wonder if it shouldn't be a TW_Handle (which should be a NativeUInt and UInt64 on 64 bit). At least GlobalLock expects a THandle (which is UInt64 on 64 bit). You're right, it should be, and I changed it to THandle (same as used by GlobalLock) for hNative in the TransferImages method, and the Handle parameter in the ReadNative method, but to no avail - same problem. On 7/19/2019 at 12:11 AM, rvk said: Strange this worked locally on the machine itself but fails on RDP. Maybe the handle-numbers are much larger and it fails. The handle numbers are larger, e.g: In the "standalone" DLL: 57278728 (36A0108) In the "RDS" DLL: 2333671976 (8B190228) and 1541866024 (5BE70228) Share this post Link to post
rvk 33 Posted July 23, 2019 Then there still could be some other type mismatches in there. Did you also try the TransferMode := ttmMemory; method already? Share this post Link to post
Dave Nottage 557 Posted July 23, 2019 39 minutes ago, rvk said: Did you also try the TransferMode := ttmMemory; method already? Yes, with a different failure; can't recall exactly. I'll check again tomorrow. Share this post Link to post