Home › Forums › TWAIN Classic › app does not respond to MSG_CLOSEDSREQ…
- This topic has 11 replies, 2 voices, and was last updated 16 years, 8 months ago by xyuxux.
- AuthorPosts
I am making a wrapper for TWAIN.
For example, on applications such as Photoshop and GIMP, if you choose the TWAIN wrapper and perform a scan, a list of the TWAIN’s installed on your PC will be shown on the wrapper’s user interface, allowing you to select a TWAIN to scan with.As for how it works, when messages IMAGEINFO, SETUPMEMXFER, IMAGENATIVEXFER, etc., are received in State6, scan data is retrieved from the target TWAIN for the application. That data is returned as TWAIN to the application by IMAGEMEMXFER and IMAGENATIVEXFER.
The TWAIN wrapper works as native transfer, so for memory transfer applications, the data is processed and returned.The wrapper works without problems for native transfer applications (IrfanView, Microsoft Photo Editor).
For memory transfer applications (GIMP for Windows, Photoshop7), GIMP works without problems. However, with Photoshop there is a problem.After returning Count = 0 for DG_CONTROL / DAT_PENDINGXFERS / MSG_ENDXFER, the image shows up in Photoshop. The TWAIN wrapper’s interface is still displayed, and even if the cancel button is pressed and DG_CONTROL / DAT_NULL / MSG_CLOSEDSREQ notifications are sent, DSM_Entry returns TWRC_FAILURE, and Photoshop becomes unusable.
After MSG_ENDXFER, the app does not respond to MSG_CLOSEDSREQ… does anyone know the reason for this?
Please help me out.
If I understand what you’re doing, you have written a data source and when another application selects your data source from the select source dialog your data source is displayed and in your data source the user can select other data sources. Your data source runs the other data source and when your data source recieves info from the second source your source returns it to the app. Lemme know if I have that right.
Then it sounds like you’re having trouble with Photoshop and a Ui not closing even though the image shows up in Photoshop.
Which Ui isn’t closing, yours or the second?@gabe wrote:
Which Ui isn’t closing, yours or the second?
Thanks for your response.
You have everything understood correctly.
The second UI closes, but my UI does not close.ah. so your data source doen’t close. I suppose you’ve adding debug code or can step thru the code to repeoduce. If I had to guess (and I sorta do unless you want to post code somewhere) I would say it sounds messagepump related.
Are you inheriting from nativeWindow somewhere in your code to provide the handle (and messagepump) to talk to the dsm or are you riding the handle from the app?
My wrapper was sending DG_CONTROL/DAT_NULL/MSG_CLOSEDSREQ to talk to the dsm.
I think I sent CloseDSRequest since otherwise there was no DG_CONTROL/DAT_PARENT/MSG_OPENDSM response.
This seems to be the cause of the problem.
DSM_Entry(&WrapperID, &AppID, DG_CONTROL, DAT_NULL, MSG_CLOSEDSREQ, (TW_MEMREF)NULL);
DSM_Entry(&WrapperID, NULL, DG_CONTROL, DAT_PARENT, MSG_OPENDSM, (TW_MEMREF)&in_hWnd);
DSM_Entry(&WrapperID, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETFIRST, (TW_MEMREF)&SecondDSID);
DSM_Entry(&WrapperID, NULL, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, (TW_MEMREF)&SecondDSID);
DSM_Entry(&WrapperID, &SecondDSID, DG_CONTROL, DAT_USERINTERFACE, MSG_ENABLEDS, (TW_MEMREF)&twUI);
:
Is there a way for the wrapper to open the dsm while maintaining its conversation with the app?
unrealted bit #1: Do I misunderstand you code or are you not checking the rc codes here? I know it doesn’t really relate to you question, but is it just me or are you calling Getfirst regardless of whether or not OpenDs returns rc=success and then calling GetFirst regardless of whether or not GetFirst returns rc=success? I wonder if you would see TWRC_FAILURE/TWCC_MAXCONNECTIONS if you checked the Rc and Cc during the OpenDs call… Or do you just stop getting messages everywhere?
unrelated bit#2: Are you maintaining and tracking the twState during your calls? It seems to me (from this small bit of code) that you aren’t.
>>Is there a way for the wrapper to open the dsm while maintaining its conversation with the app?
this has been asked before and someone (who I don’t know and have no reason to believe or for that matter not believe) said no. but I always wondered. It seems to me (and no, I don’t know – I just have a strong suspicion) that if your wrapper, which is itself a source, – and it looks from &in_hWnd that you are if I understand what that points to, maintained it’s own messageloop, by deriving from nativeWindow, that it should be able to talk to the dsm independant of connection to the parent app. Then your wrapper would (should be able to?) be able to close and reopen the dsm if needed to get stuff done while maintaining the conversation with the app. Or maybe I need more sleep and less coffee, hard for me to tell sometimes.
Which of the 5 DSM_Entry calls from you code do you think is the problem? Would it help if you were stepping thru the code from all parties invloved?
You mentioned testing with a couple of different some that worked other that didn’t depending on the xfer mode , is this problem reproducable with twacker?
.
I am checking the rc codes for DSM_Entry. All are returning success.
twRc = DSM_Entry(&WrapperID, &AppID, DG_CONTROL, DAT_NULL, MSG_CLOSEDSREQ, (TW_MEMREF)NULL);
if (twRc != TWRC_SUCCESS) goto error;
twRc = DSM_Entry(&WrapperID, NULL, DG_CONTROL, DAT_PARENT, MSG_OPENDSM, (TW_MEMREF)&in_hWnd);
if (twRc != TWRC_SUCCESS) goto error;
twRc = DSM_Entry(&WrapperID, NULL, DG_CONTROL, no, MSG_GETFIRST, (TW_MEMREF)&SecondDSID);
if (twRc != TWRC_SUCCESS) goto error;
twRc = DSM_Entry(&WrapperID, NULL, DG_CONTROL, no, MSG_OPENDS, (TW_MEMREF)&SecondDSID);
if (twRc != TWRC_SUCCESS) goto error;
ui.ShowUI = TRUE;
ui.ModalUI = TRUE;
ui.hParent = in_hWnd;
twRc = DSM_Entry(&WrapperID, &SecondDSID, DG_CONTROL, DAT_USERINTERFACE, MSG_ENABLEDS, (TW_MEMREF)&twUI);
if (twRc != TWRC_SUCCESS) goto error;
If I don’t make the first call, DSM_Entry(DG_CONTROL/DAT_NULL/MSG_CLOSEDSREQ), the 2nd one, DMS_Entry(DG_CONTROL/DAT_PARENT/MSG_OPENDSM) does not return, causing the wrapper to stop there.
If I do make that first call to DSM_Entry(DG_CONTROL/DAT_NULL/MSG_CLOSEDSREQ), the other calls all return with success.
After that, I perform a scan from the 2nd DS, pass the scan data to the app, and the app sends DG_CONTROL / DAT_PENDINGXFERS / MSG_ENDXFER. Everything works fine up to this point.
However, the wrapper’s UI does not close after that (It gets closed with IrfanView, so I don’t know why it doesn’t close with Photoshop) so I send DSM_Entry( DG_CONTROL / DAT_NULL / MSG_CLOSEDSREQ ), which gives me rc=TWRC_FAILURE.For in_hWnd, I am doing in_hWnd = (pTW_USERINTERFACE)(pTWMsg->pData)->hParent; when MSG_ENABLEDS is called from the app.
@gabe wrote:
Which of the 5 DSM_Entry calls from you code do you think is the problem?
I was thinking the problem is with the first DSM_Entry call.
Perhaps since I am already sending MSG_CLOSEDSREQ once there, sending MSG_CLOSEDSREQ again ends up failing.To retrieve the twState at that time, I can pass &AppID for the 2nd argument, right?
twRc = DSM_Entry(&WrapperID, &AppID, DG_CONTROL, DAT_STATUS, MSG_GET, (TW_STATUS*)&twState);
The twRc for this is also FAILURE.
@gabe wrote:
is this problem reproducable with twacker?
By twacker you mean “TWAIN_32 Twacker”, right?
With Twacker, after returning 0 in response to DG_CONTROL / DAT_PENDINGXFERS / MSG_ENDXFER, the wrapper’s UI closes, so it ends normally without having to send MSG_CLOSEDSREQ. So I cannot reproduce the problem.thanks
@xyuxux wrote:
I am checking the rc codes for DSM_Entry. All are returning success.
just checking, I thought you might be, but I was curious. The code makes more sense now – thankyou.
To retrieve the twState at that time, I can pass &AppID for the 2nd argument, right?
not the cc, the twState. You see it referenced all over in the spec – look at any of the pages that describe a triplet and there is a line that reads ‘Valid States’. There unfortunately isn’t a twain call to determine the state you’re in – at least that I can find. It’s one of those things that some people track so that they can know whether it is appropriate to do x. In my case I have a member variable and whenever I make a call to twain that is described as changing the twState I update the variable appropriatly depending on the result of the call. It is somewhat tedious but occationally it helps me understand where a call would have been correct according to the spec and when it should have failed according to the spec. Not required by any means but occationally very helpful.
With Twacker, after returning 0 in response to DG_CONTROL / DAT_PENDINGXFERS / MSG_ENDXFER, the wrapper’s UI closes, so it ends normally without having to send MSG_CLOSEDSREQ. So I cannot reproduce the problem.
if it isn’t broken in twacker then I would guess (and maybe bet heavily on) this being a problem with the ‘other program’ – photoshop in this case. And now that I’m thinking of it, I seem to remember someone else writing something about photoshop acting oddly. search thur the forum for photoshop – the only I remember were a couple of posts indication that ps really wanted one xfer mode or another, but you aren’t the first perosn to mention them acting differently than the rest.
then, do (can)you log all of the triplets that the app sends and compare what photoshop is sending vs. what IrfanView, gimp and twacker_32 are calling? it seems more likely that photoshop isn’t placing a call that the rest are. My my world, when I get a closeDsReq from a source I do a couple of things:
TwState = 5; // update my internal twState member
Control.UserInterface.DisableDs // takes twState from 5 -> 4
Control. I d e n t i t y .CloseDS() // takes twState from 4 -> 3
Control.Parent.CloseDsm() //takes twState 3 -> 2
// kill the thread that maintains the independant messageloop
StopMessageLoop();
If you log all the calls from photoshop it may be that they aren’t calling all or some of them but regardless (on some level) last part (the actual problem part) is seems odd to me – maybe it’s just my (mis)understanding of writing a ds that works real well (or at all) or odd bits of c++ that continue to plague me but,
the Ui that won’t close, it is yours. You try asking the dsm to close it and (when photoshop is the app) you get a failure from the dsm. Why don’t you close it yourself?
After returning Count = 0 for DG_CONTROL / DAT_PENDINGXFERS / MSG_ENDXFER and maybe after waiting for DG_CONTROL / DAT_NULL / MSG_CLOSEDSREQ notifications are sent,
Couldn’t you just call DestroyWindow(hwnd) in the event that the DSM returns failure?And then I re-read your post (yeah, I’m slow) and the thought came to me – wtf!? (I still beleive in the points I made above, but in review this is odder than I originally thought)
You call CloseDsReq before you call openDsm? Wahuh? The next thought that comes to mind is, how long did that take to figure out?So. (man what a mess) there are basically 2 active sessions with the dsm that are open. 1 from the calling app(gimp, photoshot,etc), that in turn gets your ds loaded, then you begin calling into the dsm again. I might have missed your answer to this but, Where does your handle come from? Are you inheriting from or deriving a class from NativeWindow or CWnd or ..? Are you sure that the messagepump is still pumping?
It seems to me that either your pump isn’t pumping or.. ok I don’t have an or..
…or maybe they do something similar to my StartMessageLoop() and StopMessageLoop(). Create a seperate thread to talk to twain and destroy that thread when they have what they want, hanging your Ui…
Spy++ or Process Monitor may be able to tell you if the hWnd that you get from photoshop disappears.
@gabe wrote:
not the cc, the twState.
Ah, sorry, I mistook it for twStatus.
I am basing my program on the sample source from the TWAIN Toolkit (TWAIN_32 Sample Source),
so I am updating twState for the ds (between the app and the wrapper).
For example, when getting DG_CONTROL / DAT_USERINTERFACE / MSG_DISABLEDS I go to STATE4, and
when getting DG_CONTROL / DAT_IDENTITY / MSG_CLOSEDS I go to STATE3.
However, I am not tracking the twState when calling the 2nd ds and getting the image data from it (between the wrapper and 2nd ds) as seen in the previous code I posted.@gabe wrote:
it seems more likely that photoshop isn’t placing a call that the rest are.
This is the log after having sent data to the app’s (gimp, twacker) IMAGEMEMXFER.
For gimp and twacker, when SUCCESS with Count = 0 is returned for DG_CONTROL / DAT_PENDINGXFERS / MSG_ENDXFER, DG_CONTROL / DAT_USERINTERFACE / MSG_DISABLEDS is sent right away by the app. At this point I close the wrapper’s UI with DestroyWindow(hWnd).-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
DAT_PENDINGXFERS : MSG_ENDXFER // app -> wrapper
— State : 700 // wrapper’s state
Count = 0
return TWRC_SUCCESS
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
DAT_USERINTERFACE : MSG_DISABLEDS
— State : 600 // DestroyWindow(hWnd)
return TWRC_SUCCESS
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
DAT_IDENTITY : MSG_CLOSEDS
— State : 400However, for Photoshop even if SUCCESS with Count = 0 is returned for DAT_PENDINGXFERS / MSG_ENDXFER, MSG_DISABLEDS does not get sent.
This is the log after having sent data to the Photoshop’s IMAGEMEMXFER.-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
DAT_PENDINGXFERS : MSG_ENDXFER
— State : 700
Count = 0
return TWRC_SUCCESS
// no response
// manually close the UI
// DestroyWindow(hWnd)
DG_CONTROL / DAT_NULL / MSG_CLOSEDSREQ // wrapper -> app
twRc : TWRC_FAILURE@gabe wrote:
Couldn’t you just call DestroyWindow(hwnd)
It seems I did not explain well enough. Closing the UI is not the problem (it will close if I call DestroyWindow), the problem is that the app or dsm returns FAILURE in response to MSG_CLOSEDSREQ.
Or, the problem is DG_CONTROL / DAT_USERINTERFACE / MSG_DISABLEDS is not sent from Photoshop.
Because of this, Photoshop does not do a DisableDS or CloseDS, so it ends up stopping when in twState=5, I think.@gabe wrote:
You call CloseDsReq before you call openDsm?
Yes, because I could not call openDsm when a session with the dsm (to talk to the app) was already open.
@gabe wrote:
Are you inheriting from or deriving a class from NativeWindow or CWnd or ..?Are you sure that the messagepump is still pumping?
NativeWindow and CWnd… are you talking C++ or C#?
I am programming in C.By handle, do you mean the in_hWnd for when the wrapper does openDsm?
twRc = DSM_Entry(&WrapperID, NULL, DG_CONTROL, DAT_PARENT, MSG_OPENDSM, (TW_MEMREF)&in_hWnd);
For in_hWnd, I am doing in_hWnd = (pTW_USERINTERFACE)(pTWMsg->pData)->hParent; when MSG_ENABLEDS is called from the app.
I am not creating a separate messagepump thread.
I am only acting when I get the DS_Entry CALLBACK.I am not tracking the twState when calling the 2nd ds and getting the image data from it
I think you need to update twState when you make calls to the secondDs on the apps behaf, I’m almost certain of it.
I am not creating a separate messagepump thread.
ahHa! more on this later.
Could you post the line of code you’re using when you send CloseDsReq?
When your CloseDsReq fails, what Condition Code is returned?I’m working on a longer response but it is going to take a bit of time as I’m having to reread a bit of the spec and compare it to the sampleDs from twain.org and GenDs toolkit from Dosadi.com to see where you fit in.
And I ran out of room on the scratch pad I was using to map the triplets involved so I have to go down to storage to get one of the industrial paper rolls I use when looking at problems that I can’t keep in my head stuff coming out of my ears.
.
@gabe wrote:
Could you post the line of code you’re using when you send CloseDsReq?
twRc = (*lpDSM_Entry)(&WrapperID, &AppID, DG_CONTROL, DAT_NULL, MSG_CLOSEDSREQ, (TW_MEMREF)NULL);
if (twRc != TWRC_SUCCESS) {
twRc = (*lpDSM_Entry)(&WrapperID, &AppID, DG_CONTROL, DAT_STATUS, MSG_GET, (TW_STATUS*)&twStatus);
TRACE("twRc : %d", twRc)
}
@gabe wrote:
When your CloseDsReq fails, what Condition Code is returned?
The twRc for this is also FAILURE.
I can pass &AppID for the 2nd argument, right?- AuthorPosts