В настоящее время я работаю над расширением Adobe AIR Native, которое дает возможность легко манипулировать сканером изображений с помощью TWAIN.
я использую CTwain класс найден в http://www.codeproject.com/Articles/296/A-C-Wrapper-for-TWAIN
Когда я использую этот класс в приложении Windows (.exe), он работает как положено, но в DLL (который мне нужен для создания файла ane) происходит сбой при закрытии пользовательского интерфейса Twain (при завершении сканирования или нажатии кнопки «Отмена»)
Я думаю, что проблема где-то в файле DllMain.cpp (возможно, цикл сообщений), потому что в приложении с функцией запуска APIENTRY _tWinMain это работает отлично.
Код
DllMain.cpp
#include "stdafx.h"#include "TwainCpp.h"#include "resource.h"
using namespace std;
HWND g_hwnd = NULL;
HINSTANCE g_hInstance = NULL;
BOOL isValid = false;
BOOL isCreated = false;
CTwain *twain = NULL;
LRESULT CALLBACK WndProc(HWND hWnd, unsigned message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_CREATE:
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
BOOL CreateAppWindow()
{
WNDCLASS wc;
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = g_hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
wc.lpszMenuName = "FRETwainMenu";
wc.lpszClassName = "FRETwainClass";
if(RegisterClass(&wc))
{
HWND hWnd;
char title[50];
wsprintf(title, "FRETwain:%x", g_hInstance);
hWnd = CreateWindow("FRETwainClass", title, WS_DISABLED, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_MESSAGE, NULL, g_hInstance, NULL);
if(hWnd)
{
g_hwnd = hWnd;
return TRUE;
}
return FALSE;
}
return FALSE;
}
DWORD WINAPI CreateAppThread()
{
if(CreateAppWindow())
{
MSG msg;
isCreated = true;
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
if(twain != NULL){
twain->ProcessMessage(msg);
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return TRUE;
}
return FALSE;
}
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD reason, LPVOID lpvReserved)
{
switch(reason)
{
case DLL_PROCESS_ATTACH:
g_hInstance = hInstance;
HANDLE thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CreateAppThread, (LPVOID)NULL, 0, NULL);
break;
}
return TRUE;
}
FRETwain.cpp (контекстный файл)
#include <windows.h>
#include "FRETwain.h"
extern BOOL isValid;
extern BOOL isCreated;
extern HWND g_hwnd;
extern CTwain *twain;
extern "C"{
FREObject AcquireTwain(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[])
{
FREObject result;
uint32_t ret = 0;
if(isValid){
twain->Acquire(TWCPP_ANYCOUNT);
ret = 1;
}
FRENewObjectFromBool(ret, &result);
return result;
}
FREObject setDefaultDevice(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[])
{
FREObject result;
uint32_t ret = 0;
if(isValid){
twain->SelectSource();
ret = 1;
}
FRENewObjectFromBool(ret, &result);
return result;
}
FREObject initTwain(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[])
{
FREObject result;
uint32_t isTwain = 0;
if(!isValid){
twain = new CTwain(g_hwnd, ctx);
isValid = twain->IsValidDriver();
}
if(isValid)
isTwain = 1;
FRENewObjectFromBool(isTwain, &result);
return result;
}
}
У вас нет синхронизации потоков.
Во-первых, похоже, что между инициализацией g_hwnd и его использованием в AcquireTwain и т. Д. Существует условие гонки. Вероятно, это не ваша проблема, но вы должны принять это во внимание — если вы обращаетесь к g_hwnd из основного потока AIR, то вы должны синхронизировать доступ к нему, используя CRITICAL_SECTION или мьютекс.
Однако, если вы можете просто использовать критическую секцию, чтобы убедиться, что g_hwnd правильно инициализирован, а затем отправлять сообщения в свою очередь сообщений для асинхронного выполнения захвата.
то есть отправить сообщение Windows в g_hwnd, а затем вызвать CTwain :: Acquire из потока.
Возможно, вам также понадобится создать CTwain из потока и т. Д. По сути, просто сделайте его потокобезопасным.
Я никогда не писал нативное расширение для Windows (только для iOS), поэтому не уверен в этом … но, возможно, есть способ получить дескриптор окна из среды выполнения AIR, который можно использовать без необходимости во вспомогательном потоке (если только CTwain блокирует?). Это сделало бы это намного легче.
Я нашел другую обертку Twain — C ++ версию EZTwain — работает отлично
заголовочный файл, исходный файл
цикл сообщений вызывается в том же потоке
void EZTAPI TWAIN_ModalEventLoop(void)
{
MSG msg;
while ((nState >= 5) && !hDib && GetMessage((LPMSG)&msg, NULL, 0, 0)) {
if (!TWAIN_MessageHook ((LPMSG)&msg)) {
TranslateMessage ((LPMSG)&msg);
DispatchMessage ((LPMSG)&msg);
}
} // while
} // TWAIN_ModalEventLoop
Спасибо, в любом случае