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

概要
前の節までで、ドライバの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-
