スキャンできるようにする

概要

前の節までで、ドライバのUIが表示されるようになりました。

ドライバのUIが表示されるだけで、スキャンできませんでしたがスキャンできるようにします。

 

ソース

DSがEnableされている間は、アプリケーションが受け取ったメッセージをDSにも送らなければなりません。

どこで処理をすればいいのか悩みましたが、PreTranslateMessageで処理すると良い感じでした。

State 5から6へは、DSからのメッセージで遷移します。

 

State 5 to 6 

BOOL CMainFrame::PreTranslateMessage(MSG* pMsg) 
{
    // TODO: この位置に固有の処理を追加するか、または基本クラスを呼び出してください
    TW_EVENT twEvent;
    TW_INT16 twRC;
    memset(&twEvent, 0, sizeof(TW_EVENT));

    if(m_bEnableDS){
        twRC = TWRC_NOTDSEVENT;
        twEvent.pEvent = (TW_MEMREF)pMsg;
        twEvent.TWMessage = MSG_NULL;
        twRC = (*theApp.m_pDSM_ENTRY)(&theApp.m_AppID,&theApp.m_DSID,DG_CONTROL,DAT_EVENT,MSG_PROCESSEVENT,(TW_MEMREF)&twEvent);

        switch(twEvent.TWMessage){
        case MSG_XFERREADY:
            NativeXfer();
            break;
        case MSG_CLOSEDSREQ:
            DisableDS();
            CloseDS();
            break;
        case MSG_CLOSEDSOK:
            DisableDS();
            CloseDS();
            break;
        default:
            break;
        }

        if(twRC == TWRC_DSEVENT) return TRUE;
    }

    return CFrameWnd::PreTranslateMessage(pMsg);
}

 

DSからMSG_XFERREADYが来たら、イメージの転送を開始します。

ネイティブ転送でスキャンするとDIBが返されるので、返されたDIBのハンドルをドキュメントクラスで管理しているだけです。

State 6 to 7

BOOL CMainFrame::NativeXfer()
{
    TW_UINT16 twRC;

    CScanDoc* pDoc = (CScanDoc*)GetActiveDocument();
    if(pDoc == NULL) return FALSE;

    TW_UINT32 twBitmap;
    twRC = (*theApp.m_pDSM_ENTRY)(&theApp.m_AppID,&theApp.m_DSID,DG_IMAGE,DAT_IMAGENATIVEXFER,MSG_GET,(TW_MEMREF)&twBitmap);

    switch(twRC){
    case TWRC_XFERDONE:
        pDoc->SetBitmap((TW_UINT32)twBitmap);
        InvalidateRect(NULL,TRUE);

        DoEndXfer();
        DisableDS();
        CloseDS();
        break;
    case TWRC_CANCEL:
        DoEndXfer();
        DisableDS();
        CloseDS();
        break;
    case TWRC_FAILURE:
        DoEndXfer();
        DisableDS();
        CloseDS();
        break;
    }

    return TRUE;
}

 

ちなみに、ビュークラスのOnDrawでクライアント領域にスキャンしたイメージを表示します。

void CScanView::OnDraw(CDC* pDC)
{
    CScanDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    // TODO: この場所にネイティブ データ用の描画コードを追加します。
    if(pDoc != NULL){
        TW_UINT32 twBitmap = (TW_UINT32)pDoc->GetBitmap();
        if(twBitmap != NULL){
            LPVOID pBitmap = (LPVOID)::GlobalLock((LPVOID)twBitmap);
            BITMAPINFOHEADER* pbih = (BITMAPINFOHEADER*)pBitmap;
            SetScrollSizes(MM_TEXT,CSize(pbih->biWidth,pbih->biHeight));
            HDC hDC = pDC->GetSafeHdc();
            BYTE* pData = (BYTE*)pBitmap+sizeof(BITMAPINFOHEADER);
            if(pbih->biBitCount < 16){
                if(pbih->biClrUsed != 0){
                    pData += (sizeof(RGBQUAD)*pbih->biClrUsed);
                }
                else{
                    pData += (1 << pbih->biBitCount)*sizeof(RGBQUAD);
                }
            }
            ::SetDIBitsToDevice(hDC,0,0,pbih->biWidth,pbih->biHeight,0,0,0,pbih->biHeight,(LPVOID)pData,
            (BITMAPINFO*)pBitmap,DIB_RGB_COLORS);
            ::GlobalUnlock((LPVOID)twBitmap);
        }
    }
}

 

TWRC_XFERDONEだったら、DSをDisableしてCloseします。

ホントはカウンタを見て、まだスキャンするものがあったらスキャンするんですけど、今はとりあえずADF非サポートなので一枚読んだら問答無用で終了します。

State 7 to 6 to 5

void CMainFrame::DoEndXfer()
{
    TW_PENDINGXFERS twPendingXfer;
    TW_INT16 twRC;

    twRC = (*theApp.m_pDSM_ENTRY)(&theApp.m_AppID,&theApp.m_DSID,DG_CONTROL,DAT_PENDINGXFERS,MSG_ENDXFER,(TW_MEMREF)&twPendingXfer);
}

State 5 to 4
void CMainFrame::DisableDS()
{
    TW_INT16 twRC;
    TW_USERINTERFACE twUI;

    twRC = (*theApp.m_pDSM_ENTRY)(&theApp.m_AppID,&theApp.m_DSID,DG_CONTROL,DAT_USERINTERFACE,MSG_DISABLEDS,(TW_MEMREF)&twUI);
}

State 4 to 3
void CMainFrame::CloseDS()
{
    TW_INT16 twRC;

    twRC = (*theApp.m_pDSM_ENTRY)(&theApp.m_AppID,NULL,DG_CONTROL,DAT_IDENTITY,MSG_CLOSEDS,(TW_MEMREF)&theApp.m_DSID);
}

 

State 3 to 2

BOOL CScanApp::CloseDSM()
{
    TW_UINT16 rc;
    rc = (*m_pDSM_ENTRY)(&m_AppID,NULL,DG_CONTROL,DAT_PARENT,MSG_CLOSEDSM,(TW_MEMREF)&m_pMainWnd->m_hWnd);

    return TRUE;
}

CloseDSMはExitInstanceで呼べば良い感じだと思います。

また、もともとTWAIN_32.DLLを解放する処理をしているので、そこでState 2からState 1に遷移します。

 

また、終了時や一度スキャンしたあとにスキャンしたときにDIBを解放する処理を忘れずにやっておきましょう。

以上で、一応一枚だけスキャンするプログラムが動くようになります。

 

EXEファイルを公開しておきます。

必要なDLLがあるかもしれませんが、とりあえずVCがインストールされていれば動くはずです。

とりあえず、MFCをスタティックリンクしておきましたが。(ここら辺のことが、全然分かっていないので・・・。)

実行ファイル:Scan.lzh (165k Byte) -Version 1.0.0.0-

VC6プロジェクト:Src1000.LZH(105k Byte) -Version 1.0.0.0-