Сканер изображений Adobe AIR Native Extension TWAIN

В настоящее время я работаю над расширением Adobe AIR Native, которое дает возможность простого управления сканером изображений с помощью TWAIN.
Я использую класс CTwain по адресу http://www.codeproject.com/Articles/296/AC-Wrapper-for-TWAIN

Когда я использую этот класс в приложении Windows (.exe), он работает, как и ожидалось, но в dll (который мне нужен для создания файла) он происходит сбой при закрытии пользовательского интерфейса устройства 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;
    }

}

person Y Borys    schedule 03.04.2013    source источник


Ответы (2)


Похоже, у вас нет синхронизации потоков.

Во-первых, похоже, что существует состояние гонки между инициализацией g_hwnd и его использованием в AcquireTwain и т. д. Вероятно, это не ваша проблема, но вы должны принять это во внимание — если вы обращаетесь к g_hwnd из основного потока AIR, вы должны синхронизировать доступ к нему с помощью CRITICAL_SECTION или мьютекса.

Однако, если вы можете просто использовать критическую секцию, чтобы убедиться, что g_hwnd правильно инициализирован, а затем отправлять сообщения в свою очередь сообщений для асинхронного получения. то есть отправьте сообщение Windows в g_hwnd, а затем вызовите CTwain::Acquire из потока.
Возможно, вам также потребуется создать CTwain из потока и т. д. По сути, просто сделайте его потокобезопасным.

Я никогда не писал собственное расширение для Windows (только для iOS), поэтому не уверен в этом... но, возможно, есть способ получить дескриптор окна из среды выполнения AIR, который можно использовать без необходимости во вторичном потоке (если только блоки CTwain?). Это сделало бы это намного проще.

person Pete    schedule 05.04.2013
comment
Сначала пытался создать CTwain с параметром GetForegroundWindow() и без файла mainDll. Прямые функции, такие как selectSource, работали нормально, но поскольку цикл сообщений не был реализован, все остальное не работало. Есть ли способ добавить цикл сообщений в HWND, полученный с помощью функции GetForegroundWindow()? - person Y Borys; 05.04.2013

Я нашел другую оболочку 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 

Спасибо, в любом случае

person Y Borys    schedule 05.04.2013