TWAIN.CPP

include "twaincpp.h"
#include <QtGlobal>
#include <QDateTime>
#include <QString>

#pragma execution_character_set("utf-8");

CTwain::CTwain(HWND hWnd)
{
    m_hMessageWnd = nullptr;//消息窗口句柄
    m_hTwainDLL = nullptr;//是否已载入库
    m_pDSMProc = nullptr;//数据源管理器
    m_bSourceSelected = false;//是否已选择数据源
    m_bDSOpen = false;//是否已打开数据源
    m_bDSMOpen = false;//是否已打开数据源管理器
    m_bSourceEnabled = false;//数据源是否设为可用
    m_bModalUI = true;
    m_nImageCount = TWCPP_ANYCOUNT;
    if(hWnd)
    {
        qDebug()<<"在构造函数中安装Twain";
        InitTwain(hWnd);
    }
}

CTwain::~CTwain()
{
    ReleaseTwain();
}

/*
Initializes TWAIN interface . Is already called from the constructor. 
It should be called again if ReleaseTwain is called.
hWnd is the window which has to subclassed in order to recieve
Twain messaged. Normally - this would be your main application window.
初始化TWAIN接口。已经从构造函数调用。
如果调用ReleaseTwain,则应再次调用它。
hWnd是必须进行子类化以便接收的窗口Twain消息。
通常 - 这将是您的主要应用程序窗口。
*/
bool CTwain::InitTwain(HWND hWnd)
{
    qDebug()<<"****************开始安装Twain****************";
    char libName[512];
    if(IsValidDriver())
    {
        return true;
    }
    memset(&m_AppId,0,sizeof(m_AppId));
    if(!IsWindow(hWnd))//确定给定的窗口句柄是否标识一个已存在的窗口
    {
        return false;
    }
    m_hMessageWnd = hWnd;//要传递消息的窗口
    strcpy_s(libName,"TWAIN_32.DLL");
    
    m_hTwainDLL  = LoadLibraryA(libName);//载入库
    if(m_hTwainDLL != nullptr)
    {
        qDebug()<<"已载入有效扫描驱动";

        //获取数据源管理器入
        if(!(m_pDSMProc = (DSMENTRYPROC)GetProcAddress(m_hTwainDLL,(LPCSTR)MAKEINTRESOURCE(1))))
        {
            qDebug()<<"获取数据源管理器入口失败";
            FreeLibrary(m_hTwainDLL);
            m_hTwainDLL = nullptr;
        }
        else
        {
            qDebug()<<"获取数据源管理器入口成功";
        }
    }
    if(IsValidDriver())//成功载入驱动且获取了数据源管理器
    {
        GetIdentity();//设置应用程序信息

        //打开数据源管理器
        m_bDSMOpen = CallTwainProc(&m_AppId,nullptr,DG_CONTROL,DAT_PARENT,MSG_OPENDSM,(TW_MEMREF)&m_hMessageWnd);
        if(m_bDSMOpen)
        {
            qDebug()<<"初始化Twain接口:打开数据源管理器成功";
            get_source_list();
            qDebug()<<"****************结束安装Twain****************";
            return true;
        }
        else
        {
            qDebug()<<"初始化Twain接口:打开数据源管理器失败";
            qDebug()<<"****************结束安装Twain****************";
            return false;
        }
    }
    else
    {
        qDebug()<<"****************结束安装Twain****************";
        return false;
    }
}

/*
Releases the twain interface . Need not be called unless you
want to specifically shut it down.
释放twain接口。除非你想要特别关闭它。
*/
void CTwain::ReleaseTwain()
{
    qDebug()<<"****************开始析构Twain****************";
    if(IsValidDriver())//如果已加载有效的驱动程序且存在数据源管理器入口
    {
        CloseDSM();
        FreeLibrary(m_hTwainDLL);
        m_hTwainDLL = nullptr;
        m_pDSMProc = nullptr;
        sourcelist.clear();
    }
    qDebug()<<"****************结束析构Twain****************";
}

/*
Returns true if a valid driver has been loaded
如果已加载有效的驱动程序且存在数据源管理器入口,则返回true
*/
bool CTwain::IsValidDriver() const
{
    return (m_hTwainDLL && m_pDSMProc);
}

/*
Entry point into Twain. For a complete description of this
routine  please refer to the Twain specification 1.8
进入Twain的入口点。有关此的完整描述
例程请参考Twain规范1.8
*/
bool CTwain::CallTwainProc(pTW_IDENTITY pOrigin,pTW_IDENTITY pDest,
                           TW_UINT32 DG,TW_UINT16 DAT,TW_UINT16 MSG,
                           TW_MEMREF pData)
{
//    qDebug()<<"****************开始数据源管理器相关操作****************";
    if(IsValidDriver())//如果已加载有效的驱动程序且存在数据源管理器入口
    {
        USHORT ret_val;

        //数据源管理器相关操作
        ret_val = (*m_pDSMProc)(pOrigin,pDest,DG,DAT,MSG,pData);

//        qDebug()<<"数据源管理器相关操作结果"<<ret_val;
        m_returnCode = ret_val;

        /////////////////////吐血开始//////////////////
//        if(ret_val != TWRC_SUCCESS)
//        {
//            qDebug()<<"数据源管理器相关操作失败";

//            //初始化数据源管理器
//            (*m_pDSMProc)(pOrigin,pDest,DG_CONTROL,DAT_STATUS,MSG_GET,&m_Status);
//        }
//        else
//        {
//            qDebug()<<"数据源管理器相关操作成功";
//        }
        ////////////////////吐血结束/////////////////

//        qDebug()<<"****************结束数据源管理器相关操作****************A";
        return (ret_val == TWRC_SUCCESS);
    }
    else
    {
        m_returnCode = TWRC_FAILURE;
//        qDebug()<<"****************未加载有效的驱动程序或不存在数据源管理器入口****************";
//        qDebug()<<"****************结束数据源管理器相关操作****************B";
        return false;
    }
}

/*
This function should ideally be overridden in the derived class . If only a 
few fields need to be updated , call CTawin::GetIdentity first in your
derived class
理想情况下,应在派生类中重写此函数。 如果只有一个
几个字段需要更新,首先在你的电话中调用CTawin :: GetIdentity
派生类

设置应用程序信息
*/
void CTwain::GetIdentity()
{
    // Expects all the fields in m_AppId to be set except for the id field.
    //期望m_AppId中的所有字段都要设置,除了id字段。
    m_AppId.Id = 0; // Initialize to 0 Source Manager
    // will assign real value)
    m_AppId.Version.MajorNum = 1; //Your app's version number
    m_AppId.Version.MinorNum = 0;
    m_AppId.Version.Language = TWLG_USA;
    m_AppId.Version.Country = TWCY_USA;
    strcpy_s (m_AppId.Version.Info, "1.0");
    m_AppId.ProtocolMajor = TWON_PROTOCOLMAJOR;
    m_AppId.ProtocolMinor = TWON_PROTOCOLMINOR;
    m_AppId.SupportedGroups = DG_IMAGE | DG_CONTROL;
    strcpy_s (m_AppId.Manufacturer, "MICSS");
    strcpy_s (m_AppId.ProductFamily, "Generic");
    strcpy_s (m_AppId.ProductName, "jiandao Twain");
}

/*
Called to display a dialog box to select the Twain source to use.
This can be overridden if a list of all sources is available
to the application. These sources can be enumerated by Twain.
it is not yet supportted by CTwain.
调用以显示一个对话框以选择要使用的Twain源。
如果所有源列表都可用,则可以覆盖此项
到申请。这些来源可以由Twain列举。
它还没有得到CTwain的支持。

//选择数据源
MSG_USERSELECT的效果是弹出一个框让用户选择数据源
*/
bool CTwain::SelectSource()
{
    qDebug()<<"****************开始选择数据源****************";
    memset(&m_Source,0,sizeof(m_Source));
    if(!SourceSelected())//扫描时候未选择数据源,则设置数据源为默认的数据源
    {
        SelectDefaultSource();
    }
    if(CallTwainProc(&m_AppId,nullptr,DG_CONTROL,DAT_IDENTITY,MSG_USERSELECT,&m_Source))//MSG_OPENDS
    {
        m_bSourceSelected = true;
        qDebug()<<"成功应用所选的数据源";
    }
    else
    {
        m_bSourceSelected = false;
        qDebug()<<"应用所选的数据源失败";
    }
    qDebug()<<"****************结束选择数据源****************";
    return m_bSourceSelected;
}

//选择默认的数据源
bool CTwain::SelectDefaultSource()
{
    qDebug()<<"未选择数据源,使用默认的数据源";
    m_bSourceSelected = CallTwainProc(&m_AppId,nullptr,DG_CONTROL,DAT_IDENTITY,MSG_GETDEFAULT,&m_Source);
    if(m_bSourceSelected)
    {
        qDebug()<<"使用默认的数据源成功";
    }
    else
    {
        qDebug()<<"使用默认的数据源失败";
    }
    return m_bSourceSelected;
}

//关闭数据源 先禁用再关闭
void CTwain::CloseDS()
{
    qDebug()<<"****************开始关闭数据源****************";
    if(DSOpen())//数据源是打开的
    {
        DisableSource();
        qDebug()<<"关闭数据源";
        CallTwainProc(&m_AppId,nullptr,DG_CONTROL,DAT_IDENTITY,MSG_CLOSEDS,(TW_MEMREF)&m_Source);
        m_bDSOpen = false;
    }
    qDebug()<<"****************结束关闭数据源****************";
}

//关闭数据源管理器
void CTwain::CloseDSM()
{
    qDebug()<<"****************开始关闭数据源管理器****************";
    if(DSMOpen())//如果数据源管理器是打开的
    {
        CloseDS();//关闭数据源
        qDebug()<<"执行关闭数据源管理器";
        CallTwainProc(&m_AppId,nullptr,DG_CONTROL,DAT_PARENT,MSG_CLOSEDSM,(TW_MEMREF)&m_hMessageWnd);
        m_bDSMOpen = false;
    }
    qDebug()<<"****************结束关闭数据源管理器****************";
}

/*如果:
    1、数据源是打开的
    2、数据源管理器是打开的
    3、数据源管理器入口存在
  返回true
*/
bool CTwain::DSMOpen() const
{
    return IsValidDriver() && m_bDSMOpen;
}

/*如果:
    1、数据源是打开的
    2、数据源管理器是打开的
    3、数据源管理器入口存在
    4、已载入扫描驱动
  返回true
*/
bool CTwain::DSOpen() const
{
    return IsValidDriver() && DSMOpen() && m_bDSOpen;
}

//打开作为输入参数提供的数据源
bool CTwain::OpenSource(TW_IDENTITY *pSource)
{
    if(pSource)
    {
        m_Source = *pSource;
    }
    if(DSMOpen())//如果此时数据源管理器是打开的
    {
        qDebug()<<"xxxxxxxxxxx";
        if(!SourceSelected())//此时未选中数据源
        {
            SelectDefaultSource();
        }
        //打开数据源
        m_bDSOpen = CallTwainProc(&m_AppId,nullptr,DG_CONTROL,DAT_IDENTITY,MSG_OPENDS,(TW_MEMREF)&m_Source);
    }
    return DSOpen();
}

/*
Should be called from the main message loop of the application. Can always be called,
it will not process the message unless a scan is in progress.
应该从应用程序的主消息循环调用。可以随时调用,
除非正在进行扫描,否则它不会处理消息。

消息事件
*/
bool CTwain::ProcessMessage(MSG msg)
{
    if (msg.message == 528) // don't really know why...
    {
        return false;
    }

    if (m_hMessageWnd == nullptr)
    {
        return false;
    }

    if(SourceEnabled() && m_pDSMProc)//如果数据源可用
    {
        TW_EVENT twEvent;
        twEvent.pEvent = (TW_MEMREF)&msg;
        twEvent.TWMessage = MSG_NULL;

        TW_UINT16 twRC = TWRC_NOTDSEVENT;
    
        //从扫描仪中获取事件
        twRC = CallTwainProc(&m_AppId,&m_Source,DG_CONTROL,DAT_EVENT,MSG_PROCESSEVENT,(TW_MEMREF)&twEvent);
        if(twRC != TWRC_NOTDSEVENT)
        {
            switch(twEvent.TWMessage)
            {
                case MSG_XFERREADY:
                    TransferImage();//传输图像或取消传输
                    break;
                case MSG_CLOSEDSREQ://关闭数据源
                    CloseDS();
                    break;
                case MSG_CLOSEDSOK:
                    break;
                case MSG_DEVICEEVENT:
                    break;
                default: ;
                    //qDebug()<<"都不是";
            }
        }
        else
        {
            qDebug()<<"无法获取事件";
        }
        return false;
    }
    else
    {
//        qDebug()<<"数据源不可用";
    }
    return false;
}

/*
Queries the capability of the Twain Data Source
查询twain数据源的功能
*/
bool CTwain::GetCapability(TW_CAPABILITY& twCap,TW_UINT16 cap,TW_UINT16 conType)
{
    if(DSOpen())
    {
        twCap.Cap = cap;
        twCap.ConType = conType;
        twCap.hContainer = nullptr;

        if(CallTwainProc(&m_AppId,&m_Source,DG_CONTROL,DAT_CAPABILITY,MSG_GET,(TW_MEMREF)&twCap))
        {
            return true;
        }
    }
    return false;
}

/*
Queries the capability of the Twain Data Source
同上 重载函数
*/
bool CTwain::GetCapability(TW_UINT16 cap,TW_UINT32& value)
{
    TW_CAPABILITY twCap;
    if(GetCapability(twCap,cap))
    {
        pTW_ONEVALUE pVal;
        pVal = (pTW_ONEVALUE )GlobalLock(twCap.hContainer);
        if(pVal)
        {
            value = pVal->Item;
            GlobalUnlock(pVal);
            GlobalFree(twCap.hContainer);
            return true;
        }
    }
    return false;
}

/*
Sets the capability of the Twain Data Source
设置twain数据源的功能
*/
bool CTwain::SetCapability(TW_UINT16 cap,TW_UINT16 value,bool sign)
{
    if(DSOpen())
    {
        TW_CAPABILITY twCap;
        pTW_ONEVALUE pVal;
        bool ret_value = false;

        twCap.Cap = cap;
        twCap.ConType = TWON_ONEVALUE;
        twCap.hContainer = GlobalAlloc(GHND,sizeof(TW_ONEVALUE));

        if(twCap.hContainer)
        {
            pVal = (pTW_ONEVALUE)GlobalLock(twCap.hContainer);
            pVal->ItemType = sign ? TWTY_INT16 : TWTY_UINT16;
            pVal->Item = (TW_UINT32)value;
            GlobalUnlock(twCap.hContainer);
            ret_value = SetCapability(twCap);
            GlobalFree(twCap.hContainer);
        }
        return ret_value;
    }
    return false;
}

bool CTwain::SetResolution(TW_UINT16 cap,TW_UINT32 value)
{
    if(DSOpen())
    {
        TW_CAPABILITY twCap;
        pTW_ONEVALUE pVal;
        BOOL ret_value = FALSE;

        twCap.Cap = cap;
        twCap.ConType = TWON_ONEVALUE;
        twCap.hContainer = GlobalAlloc(GHND,sizeof(TW_ONEVALUE));

        if(twCap.hContainer)
        {
            pVal = (pTW_ONEVALUE)GlobalLock(twCap.hContainer);
            pVal->ItemType = TWTY_FIX32;
            pVal->Item = (TW_UINT32)value;
            GlobalUnlock(twCap.hContainer);
            ret_value = SetCapability(twCap);
            GlobalFree(twCap.hContainer);
        }
        return ret_value;
    }
    return FALSE;
}

/*
Sets the capability of the Twain Data Source
同上 重载函数
*/
bool CTwain::SetCapability(TW_CAPABILITY& cap)
{
    if(DSOpen())
    {
        return CallTwainProc(&m_AppId,&m_Source,DG_CONTROL,DAT_CAPABILITY,MSG_SET,(TW_MEMREF)&cap);
    }
    return false;
}

/*
Sets the number of images which can be accpeted by the application at one time
设置应用程序一次可接收的图像数
*/
bool CTwain::SetImageCount(TW_INT16 nCount)
{
    if(SetCapability(CAP_XFERCOUNT,(TW_UINT16)nCount,true))
    {
        m_nImageCount = nCount;
        return true;
    }
    else
    {
        if(GetRC() == TWRC_CHECKSTATUS)
        {
            TW_UINT32 count;
            if(GetCapability(CAP_XFERCOUNT,count))
            {
                nCount = (TW_INT16)count;
                if(SetCapability(CAP_XFERCOUNT,nCount))
                {
                    m_nImageCount = nCount;
                    return true;
                }
            }
        }
    }
    return false;
}

/*
Called to enable the Twain Acquire Dialog. This too can be
overridden but is a helluva job . 
调用以启用TWAIN获取对话框。这也可以
被重写,但这是一个地狱般的工作。

使数据源可用
*/
bool CTwain::EnableSource(bool showUI)
{
    qDebug()<<"****************开始使数据源可用****************";
    if(DSOpen() && !SourceEnabled())//数据源打开了且数据源不可用
    {
        twUI.ShowUI = false/*showUIfalse*/;//是否打开默认的UI  111111111111111111111111111111111这里不设为false会报错  看看
        twUI.hParent = (TW_HANDLE)m_hMessageWnd;//消息窗口作为默认ui的主窗口
        //启用数据源
        if(CallTwainProc(&m_AppId,&m_Source,DG_CONTROL,DAT_USERINTERFACE,MSG_ENABLEDS,(TW_MEMREF)&twUI))
        {
            m_bSourceEnabled = true;
            m_bModalUI = twUI.ModalUI;
            qDebug()<<"启用数据源成功 EnableSource";
        }
        else
        {
            m_bSourceEnabled = false;
            m_bModalUI = true;
            qDebug()<<"启用数据源失败 EnableSource";
        }
        return m_bSourceEnabled;
    }
    return false;
}

/*
Called to acquire images from the source. parameter numImages i the
numberof images that you an handle concurrently

调用以从源获取图像。参数numImages i
同时处理的图像数
*/
bool CTwain::Acquire(int numImages,TW_UINT16 duplex,TW_UINT16 size,TW_UINT16 pixel,TW_UINT16 resolution)
{
    qDebug()<<"****************开始启动扫描****************";
    if(DSOpen() || OpenSource())//数据源是打开可用的
    {
        BOOL ret_value = SetCapability(CAP_DUPLEXENABLED,duplex,TRUE);
        ret_value = SetCapability(ICAP_SUPPORTEDSIZES,size,TRUE);
        ret_value = SetCapability(ICAP_PIXELTYPE,pixel,TRUE);
        ret_value = SetResolution(ICAP_XRESOLUTION,resolution);
        ret_value = SetResolution(ICAP_YRESOLUTION,resolution);
        // lqh - 设置传输模式为文件
        ret_value = SetCapability(ICAP_XFERMECH,TWSX_FILE,TRUE);

        //设置扫描的最大张数
        if(SetImageCount(numImages))
        {
            if(EnableSource())
            {
                return true;
            }
            else
            {
                qDebug()<<"启用扫描源失败";
                return false;
            }
        }
    }
    return false;
}

//禁用数据源
bool CTwain::DisableSource()
{
    qDebug()<<"****************开始禁用数据源****************";
    if(SourceEnabled())//数据源目前的状态是:可用
    {
        //禁用数据源
        if(CallTwainProc(&m_AppId,&m_Source,DG_CONTROL,DAT_USERINTERFACE,MSG_DISABLEDS,&twUI))
        {
            m_bSourceEnabled = false;
            qDebug()<<"禁用数据源成功";
            return true;
        }
        else
        {
            qDebug()<<"禁用数据源失败";
            return false;
        }
    }
    else
    {
        qDebug()<<"数据源目前的状态是不可用,不用再次禁用";
    }
    return false;
}

/*
Gets Imageinfo for an image which is about to be transferred.
获取即将传输的图像的ImageInfo
*/
bool CTwain::GetImageInfo(TW_IMAGEINFO& info)
{
    qDebug()<<"****************开始获取图片信息****************";
    if(SourceEnabled())//如果数据源是可用的
    {
        bool b = CallTwainProc(&m_AppId,&m_Source,DG_IMAGE,DAT_IMAGEINFO,MSG_GET,(TW_MEMREF)&info);
        if(b == true)
        {
            qDebug()<<"成功获取即将传输的图片信息";
        }
        else
        {
            qDebug()<<"获取即将传输的图片信息失败";
        }
        return b;
    }
    return false;
}

/*
Trasnfers the image or cancels the transfer depending on the state of the
TWAIN system
根据图像的状态传输图像或取消传输
*/
void CTwain::TransferImage()
{
    qDebug()<<"****************根据图像的状态传输图像或取消传输****************";
    TW_IMAGEINFO info;//图片信息
    bool bContinue = true;
    while(bContinue)
    {
        if(GetImageInfo(info))//获取图片信息
        {

            /* lqh start */
            TW_SETUPFILEXFER filexfer;
            memset(&filexfer, 0, sizeof(filexfer));
            QString file = "C:\\SCANFILES\\scan_" + QDateTime::currentDateTime().toString("yyyyMMddHHmmsszzz") +".bmp";
            qDebug() << "scan file = " << file ;
            filexfer.Format = TWFF_BMP/*TWFF_BMP*/;
            strcpy(filexfer.FileName,file.toLatin1().data());

            CallTwainProc(&m_AppId,&m_Source,DG_CONTROL, DAT_SETUPFILEXFER, MSG_SET, (TW_MEMREF)&(filexfer));
            /* lqh end */

            int permission;
            permission = ShouldTransfer(info);
            qDebug()<<"执行到这";
            switch(permission)
            {
                case TWCPP_CANCELTHIS:
                    qDebug()<<"执行到这01";
                    bContinue = EndTransfer();//结束当前的传输
                    break;

                case TWCPP_CANCELALL:
                    qDebug()<<"执行到这02";
                    CancelTransfer();//中止所有传输
                    bContinue = false;
                    break;

                case TWCPP_DOTRANSFER:
                    qDebug()<<"执行到这03";
                    bContinue = GetImage(info);//获取图片
                    break;
            }
        }
    }
}

/*
Ends the current transfer.
Returns true if the more images are pending
结束当前传输。
如果有更多图像挂起,则返回true
*/
bool CTwain::EndTransfer()
{
    qDebug()<<"****************执行结束当前传输****************";
    TW_PENDINGXFERS twPend;
    if(CallTwainProc(&m_AppId,&m_Source,DG_CONTROL,DAT_PENDINGXFERS,MSG_ENDXFER,(TW_MEMREF)&twPend))
    {
        if (twPend.Count==0)
        {
            DisableSource();
        }
        return twPend.Count != 0;
    }
    return false;
}

/*
Aborts all transfers
中止所有传输
*/
void CTwain::CancelTransfer()
{
    qDebug()<<"****************执行终止所有传输****************";
    TW_PENDINGXFERS twPend;
    CallTwainProc(&m_AppId,&m_Source,DG_CONTROL,DAT_PENDINGXFERS,MSG_RESET,(TW_MEMREF)&twPend);
}

/*
Calls TWAIN to actually get the image
调用twain以实际获取图像
*/
bool CTwain::GetImage(TW_IMAGEINFO& info)
{
    qDebug()<<"****************获得图片****************";
    HANDLE hBitmap;
//    CallTwainProc(&m_AppId,&m_Source,DG_IMAGE,DAT_IMAGENATIVEXFER,MSG_GET,&hBitmap);
    //这里失败了
    CallTwainProc(&m_AppId,&m_Source,DG_IMAGE, DAT_IMAGEFILEXFER, MSG_GET, NULL);

    qDebug()<<"m_returnCode "<<m_returnCode;

    switch(m_returnCode)
    {
        case TWRC_XFERDONE:
                qDebug()<<"01";
                CopyImage(hBitmap,info);//本类的虚函数 子类实现获取图片后的操作
                break;
        case TWRC_CANCEL:
                qDebug()<<"02";
                break;
        case TWRC_FAILURE:
                break;
                CancelTransfer();//终止传输
                return false;
    }
    GlobalFree(hBitmap);//释放图片内存
    return EndTransfer();
}

//获取数据源列表
void CTwain::get_source_list()
{
    if(!sourcelist.isEmpty())
    {
        sourcelist.clear();
    }

    if (CallTwainProc(&m_AppId,nullptr,DG_CONTROL,DAT_IDENTITY,MSG_GETFIRST,&m_Source))
    {
        TW_IDENTITY temp_Source = m_Source;
        sourcelist.append(temp_Source);//添加到链表
//        qDebug()<<"可用扫描仪:"<<temp_Source.ProductName;
        while(CallTwainProc(&m_AppId,nullptr,DG_CONTROL,DAT_IDENTITY,MSG_GETNEXT,&m_Source))
        {
            TW_IDENTITY temp_Source = m_Source;
            sourcelist.append(temp_Source);//添加到链表
//            qDebug()<<"可用扫描仪:"<<temp_Source.ProductName;
        }

        m_Source = sourcelist.value(0);//第一个可用的扫描源
        m_bSourceSelected = TRUE;
    }
    else
    {
        qDebug()<<"没有可用的扫描仪";
        m_bSourceSelected = FALSE;
    }
}

 

posted @ 2021-05-18 06:24  myrj  阅读(352)  评论(0编辑  收藏  举报