Home › Forums › TWAIN Classic › Crash if force close Data Source when acquire image
- This topic has 2 replies, 1 voice, and was last updated 9 years ago by kmbui.
- AuthorPosts
Hi,
I write a dll that handle image acquire from imaging software data source.
There is a strange case that cost me days without any solution:
1. Use PortView (an Twain data source from Port View imaging software).
2. Open PortView to acquire image.
3. In PortView, import an image, then close (press X button on UI).
4. Close data source programmatically:
(*g_pDSM_Entry) (&g_AppID, 0, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, &srcID)
Then my dll crash.In step #3, in does not crash if:
3a. Close PortView without importing an image (has no image).
3b. Click Send button on UI to send the image to the dll.I try do find any different between the crash case and 3b to do something specially, but there’s nothing:
– Both case has: event.TWMessage == MSG_XFERREADY (In 3a event.TWMessage == MSG_CLOSEDSREQ).
– Both case has image transferred back to the dll.Any hint would be much appreciated.
Thanks,More info:
In step #4, i call 3 commands:4.1. (*g_pDSM_Entry) (&g_AppID, &srcID, DG_CONTROL, DAT_USERINTERFACE, MSG_DISABLEDS, &ui)
4.2. (*g_pDSM_Entry) (&g_AppID, 0, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, &srcID)
4.3 (*g_pDSM_Entry) (&g_AppID, 0, DG_CONTROL, DAT_PARENT, MSG_CLOSEDSM, (TW_MEMREF)&hwnd)and it crash at #4.2.
if i comment out #4.1, it crash at 4.3.Here is my whole function:
static int acquireByName(JNIEnv *env, BOOL showUI, BOOL modal, const char* sourceName, int maxImages, jobjectArray images)
{
TW_UINT16 rc;
// Create a static window whose handle is passed to DSM_Entry() when we
// open the data source manager.
HWND hwnd = CreateWindow("STATIC",
sourceName,
WS_POPUPWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
HWND_DESKTOP,
0,
g_hinstDLL,
0);
// If window could not be created, throw exception. Because the exception
// is not actually thrown until execution returns to Java, we must return
// a value -- (jobject) 0 was chosen to represent Image null. This value
// will not be seen in the Java code because of the exception.
if (hwnd == 0)
{
return TWRC_FAILURE;
}
// Ensure that the default data source's dialog box does not disappear
// behind other windows, which can be very disconcerting to the user. We do
// that by making the hwnd -- created above and passed to DSM_Entry() below
// -- the handle of the topmost window.
SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW);
// Open Data Source Manager
BLOCK_BEGIN(1)
// Open the data source manager.
rc = (*g_pDSM_Entry) (&g_AppID,
0,
DG_CONTROL,
DAT_PARENT,
MSG_OPENDSM,
(TW_MEMREF)&hwnd);
// If data source manager could not be opened, throw exception. Because the
// exception is not actually thrown until execution returns to Java, we
// first exit current block to destroy previously-created window and return
// a value (which isn't seen in the Java code).
if (rc != TWRC_SUCCESS)
{
EXIT_CURRENT_BLOCK
}
// Open Data Source
BLOCK_BEGIN(2)
// Find the data source match the name
TW_IDENTITY srcID;
memset(&srcID, 0, sizeof(srcID));
BOOL found = FALSE;
// Check with first DataSource
rc = (*g_pDSM_Entry) (&g_AppID,
0,
DG_CONTROL,
DAT_IDENTITY,
MSG_GETFIRST,
(TW_MEMREF)&srcID);
if (rc == TWRC_SUCCESS)
{
// found
if (_stricmp(srcID.ProductName, sourceName) == 0)
{
found = TRUE;
}
else
{
do
{
rc = (*g_pDSM_Entry) (&g_AppID,
0,
DG_CONTROL,
DAT_IDENTITY,
MSG_GETNEXT,
(TW_MEMREF)&srcID);
if (rc == TWRC_SUCCESS)
{
// found
if (_stricmp(srcID.ProductName, sourceName) == 0)
{
found = TRUE;
break;
}
}
} while (rc == TWRC_SUCCESS);
}
if (found != TRUE)
{
EXIT_CURRENT_BLOCK
}
}
else
{
EXIT_CURRENT_BLOCK
}
// Open the selected data source.
rc = (*g_pDSM_Entry) (&g_AppID,
0,
DG_CONTROL,
DAT_IDENTITY,
MSG_OPENDS,
&srcID);
// If default data source could not be opened, throw exception. Because the
// exception is not actually thrown until execution returns to Java, we
// first exit current block to close data source manager and destroy the
// previously-created window.
if (rc != TWRC_SUCCESS)
{
EXIT_CURRENT_BLOCK
}
// Does capturing
BLOCK_BEGIN(3)
// Prepare to enable the default data source. Make sure to show the data
// source's own user interface (dialog box).
TW_USERINTERFACE ui;
ui.ShowUI = showUI;
ui.ModalUI = modal;
ui.hParent = hwnd;
// Enable the default data source.
rc = (*g_pDSM_Entry) (&g_AppID,
&srcID,
DG_CONTROL,
DAT_USERINTERFACE,
MSG_ENABLEDS,
&ui);
// If default data source could not be enabled, throw exception. Because
// the exception is not actually thrown until execution returns to Java, we
// first exit current block to close data source, close data source
// manager and destroy the previously-created window.
if (rc != TWRC_SUCCESS)
{
EXIT_CURRENT_BLOCK
}
// Begin the event-handling loop. Data transfer takes place in this loop.
MSG msg;
TW_EVENT event;
TW_PENDINGXFERS pxfers;
memset(&pxfers, 0, sizeof(TW_PENDINGXFERS));
while (GetMessage((LPMSG)&msg, 0, 0, 0))
{
// Each window message must be forwarded to the data source.
event.pEvent = (TW_MEMREF)&msg;
event.TWMessage = MSG_NULL;
rc = (*g_pDSM_Entry) (&g_AppID,
&srcID,
DG_CONTROL,
DAT_EVENT,
MSG_PROCESSEVENT,
(TW_MEMREF)&event);
// If the message does not correspond to a data source event, we must
// dispatch it to the appropriate Windows window.
if (rc == TWRC_NOTDSEVENT)
{
TranslateMessage((LPMSG)&msg);
DispatchMessage((LPMSG)&msg);
continue;
}
// If the default data source is requesting that the data source's
// dialog box be closed (user pressed Cancel), we must break out of the
// message loop.
if (event.TWMessage == MSG_CLOSEDSREQ)
break;
// If the default data source is requesting that it is ready to begin
// the data transfer, we must perform that transfer.
if (event.TWMessage == MSG_XFERREADY)
{
int acquiredImages = 0;
do
{
// Obtain information about the first image to be transferred.
TW_IMAGEINFO ii;
rc = (*g_pDSM_Entry) (&g_AppID,
&srcID,
DG_IMAGE,
DAT_IMAGEINFO,
MSG_GET,
(TW_MEMREF)&ii);
// If unable to obtain image information ...
if (rc != TWRC_SUCCESS)
{
// Cancel all transfers.
(*g_pDSM_Entry) (&g_AppID,
&srcID,
DG_CONTROL,
DAT_PENDINGXFERS,
MSG_RESET,
(TW_MEMREF)&pxfers);
// break out of event loop.
break;
}
// If image is compressed or is not 8-bit color and not 24-bit color ...
if (ii.Compression != TWCP_NONE || ii.BitsPerPixel != 8 && ii.BitsPerPixel != 24)
{
// Cancel all transfers.
(*g_pDSM_Entry) (&g_AppID,
&srcID,
DG_CONTROL,
DAT_PENDINGXFERS,
MSG_RESET,
(TW_MEMREF)&pxfers);
// break out of event loop.
break;
}
// Perform the transfer.
TW_UINT32 handle;
rc = (*g_pDSM_Entry) (&g_AppID,
&srcID,
DG_IMAGE,
DAT_IMAGENATIVEXFER,
MSG_GET,
(TW_MEMREF)&handle);
// If image not successfully transferred ...
if (rc != TWRC_XFERDONE)
{
// Cancel all remaining transfers.
(*g_pDSM_Entry) (&g_AppID,
&srcID,
DG_CONTROL,
DAT_PENDINGXFERS,
MSG_RESET,
(TW_MEMREF)&pxfers);
// break out of event loop.
break;
}
rc = (*g_pDSM_Entry) (&g_AppID,
&srcID,
DG_CONTROL,
DAT_PENDINGXFERS,
MSG_ENDXFER,
(TW_MEMREF)&pxfers);
// Transfer Windows-based DIB to a Java-based Image (via a MemoryImageSource).
LPBITMAPINFOHEADER lpbmih;
lpbmih = (LPBITMAPINFOHEADER)GlobalLock((HANDLE)handle);
jobject image;
/*if (ii.BitsPerPixel == 8)
{
image = xferDIB8toImage(lpbmih, env);
}
else
{
image = xferDIB24toImage(lpbmih, env);
}
env->SetObjectArrayElement(images, acquiredImages, image);*/
GlobalUnlock((HANDLE)handle);
GlobalFree((HANDLE)handle);
acquiredImages++;
if (acquiredImages >= maxImages)
{
// Cancel all remaining transfers.
(*g_pDSM_Entry) (&g_AppID,
&srcID,
DG_CONTROL,
DAT_PENDINGXFERS,
MSG_RESET,
(TW_MEMREF)&pxfers);
// break out of acquire loop.
break;
}
} while (pxfers.Count != 0);
// break out of event loop.
break;
}
}
// Disable the data source.
(*g_pDSM_Entry) (&g_AppID,
&srcID,
DG_CONTROL,
DAT_USERINTERFACE,
MSG_DISABLEDS,
&ui);
BLOCK_END(3)
// Close the data source.
(*g_pDSM_Entry) (&g_AppID,
0,
DG_CONTROL,
DAT_IDENTITY,
MSG_CLOSEDS,
&srcID);
BLOCK_END(2)
// Close the data source manager.
(*g_pDSM_Entry) (&g_AppID,
0,
DG_CONTROL,
DAT_PARENT,
MSG_CLOSEDSM,
(TW_MEMREF)&hwnd);
BLOCK_END(1)
DestroyWindow(hwnd);
return TWRC_SUCCESS;
}
- AuthorPosts