Qt C++ wia

0

Witam, chciałbym napisać program, który skanuje obrazy, tak jak to robi zwykła aplikacja, jak np. program od HP. Do tej pory mam taki kod ale wyskakuje idtGetData failed.

#include <QCoreApplication>
#include <windows.h>
#include <stdio.h>
#include <wia.h>
#include <QDebug>

#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "wiaguid.lib")

HRESULT hr;
IWiaDevMgr *pWiaDevMgr = NULL;
IEnumWIA_DEV_INFO *pWiaEnumDevInfo = NULL;
IWiaPropertyStorage *pWiaPropertyStorage = NULL;
IWiaItem *pWiaDevice = NULL;
PROPSPEC PropSpec[3] = {0};
PROPVARIANT PropVar[3] = {0};
IWiaDataTransfer *pWiaDataTransfer = NULL;
STGMEDIUM stgMedium = {0};

void exit_program(const char* exit_message)
{
    // Clean up WIA / COM stuff
    ReleaseStgMedium(&stgMedium);
    if (pWiaDataTransfer) pWiaDataTransfer->Release();
    FreePropVariantArray(3, PropVar);
    if (pWiaDevice) pWiaDevice->Release();
    if (pWiaPropertyStorage) pWiaPropertyStorage->Release();
    if (pWiaEnumDevInfo) pWiaEnumDevInfo->Release();
    if (pWiaDevMgr) pWiaDevMgr->Release();
    CoUninitialize();

    // If an error message was supplied print it
    if (strlen(exit_message) > 0)
    {
        fprintf(stderr, exit_message);
        fprintf(stderr, "\n");
        exit(1);
    }

    // Exit the program normally
    exit(0);
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    int devnum = 1;

        hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
        if (FAILED(hr)) exit_program("Could not initialise COM");

        hr = CoCreateInstance(
                CLSID_WiaDevMgr, NULL, CLSCTX_LOCAL_SERVER,
                IID_IWiaDevMgr, (void**)&pWiaDevMgr);
        if (FAILED(hr)) exit_program("CoCreateInstance failed");

        hr = pWiaDevMgr->EnumDeviceInfo(WIA_DEVINFO_ENUM_LOCAL, &pWiaEnumDevInfo);
        if (FAILED(hr)) exit_program("EnumDeviceInfo failed");

        fprintf(stderr, "Scanning WIA devices...\n");

        int dev_count = 0;

        while (hr == S_OK)
        {
            // Try to get IWiaPropertyStorage for next device
            hr = pWiaEnumDevInfo->Next(1, &pWiaPropertyStorage, NULL);

            // If there are no more devices, stop scanning
            if (hr != S_OK) break;

            // Found another device
            dev_count++;
            fprintf(stderr, "Found device %d\n", dev_count);

            // If this is the requested device, break out of loop
            if (dev_count == devnum) break;

            // Release the current device's IWiaPropertyStorage
            pWiaPropertyStorage->Release();
            pWiaPropertyStorage = NULL;
        }

        PropSpec[0].ulKind = PRSPEC_PROPID;
        PropSpec[0].propid = WIA_DIP_DEV_ID;
        PropSpec[1].ulKind = PRSPEC_PROPID;
        PropSpec[1].propid = WIA_DIP_DEV_NAME;
        PropSpec[2].ulKind = PRSPEC_PROPID;
        PropSpec[2].propid = WIA_DIP_DEV_DESC;
        hr = pWiaPropertyStorage->ReadMultiple(3, PropSpec, PropVar);
        if (FAILED(hr)) exit_program("ReadMultiple failed");

        QString convertedBSTR((QChar*) PropVar[0].bstrVal, wcslen(PropVar[0].bstrVal));

        if (VT_BSTR == PropVar[0].vt) qDebug() << "WIA_DIP_DEV_ID : " << QString((QChar*) PropVar[0].bstrVal, wcslen(PropVar[0].bstrVal));
        if (VT_BSTR == PropVar[1].vt) qDebug() << "WIA_DIP_DEV_ID : " << QString((QChar*) PropVar[1].bstrVal, wcslen(PropVar[1].bstrVal));
        if (VT_BSTR == PropVar[2].vt) qDebug() << "WIA_DIP_DEV_ID : " << QString((QChar*) PropVar[2].bstrVal, wcslen(PropVar[2].bstrVal));
//        if (VT_BSTR == PropVar[0].vt) fprintf(stderr, TEXT("WIA_DIP_DEV_ID: %ws\n"), PropVar[0].bstrVal );
//        if (VT_BSTR == PropVar[1].vt) fprintf(stderr, TEXT("WIA_DIP_DEV_NAME: %ws\n"), PropVar[1].bstrVal );
//        if (VT_BSTR == PropVar[2].vt) fprintf(stderr, TEXT("WIA_DIP_DEV_DESC: %ws\n"), PropVar[2].bstrVal );

        hr = pWiaDevMgr->CreateDevice(PropVar[0].bstrVal, &pWiaDevice);
        if (FAILED(hr)) exit_program("CreateDevice failed");

        FreePropVariantArray(3, PropVar);

        // Configure storage medium
        GUID guidOutputFormat = WiaImgFmt_BMP;
        PropSpec[0].ulKind = PRSPEC_PROPID;
        PropSpec[0].propid = WIA_IPA_FORMAT;
        PropSpec[1].ulKind = PRSPEC_PROPID;
        PropSpec[1].propid = WIA_IPA_TYMED;
        PropVar[0].vt = VT_CLSID;
        PropVar[0].puuid = &guidOutputFormat;
        PropVar[1].vt = VT_I4;
        PropVar[1].lVal = TYMED_FILE;
        pWiaPropertyStorage->WriteMultiple(2, PropSpec, PropVar, WIA_IPA_FIRST);
        if (FAILED(hr)) exit_program("WriteMultiple failed");
        hr = pWiaDevice->QueryInterface(IID_IWiaDataTransfer, (void**)&pWiaDataTransfer);
        if (FAILED(hr)) exit_program("QueryInterface IID_IWiaDataTransfer failed");

//        stgMedium.tymed = TYMED_FILE;
//        wchar_t* filename = L"temp.bmp";
//        stgMedium.lpszFileName = filename;

        LPWSTR pwszFileName = (LPWSTR)::CoTaskMemAlloc(MAX_PATH * sizeof(WCHAR));
#ifdef UNICODE
        ::lstrcpy(pwszFileName, L"temp.bmp");
#else
        ::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, "temp.bmp", -1, pwszFileName, MAX_PATH);
#endif
        stgMedium.tymed = TYMED_FILE;
        stgMedium.lpszFileName = pwszFileName;

        // idtGetData is currently returning S_FALSE
        hr = pWiaDataTransfer->idtGetData(&stgMedium, 0);
        if (hr == E_INVALIDARG) fprintf(stderr, "E_INVALIDARG\n");
        if (hr == E_OUTOFMEMORY) fprintf(stderr, "E_OUTOFMEMORY\n");
        if (hr == E_UNEXPECTED) fprintf(stderr, "E_UNEXPECTED\n");
        if (hr == S_FALSE) fprintf(stderr, "S_FALSE\n");
        if (hr == S_OK) fprintf(stderr, "S_OK\n");
        if (hr == STG_E_MEDIUMFULL) fprintf(stderr, "STG_E_MEDIUMFULL\n");
        if (hr == WIA_S_NO_DEVICE_AVAILABLE) fprintf(stderr, "WIA_S_NO_DEVICE_AVAILABLE\n");
        //if (FAILED(hr)) exit_program("idtGetData failed");
        if (hr != S_OK) exit_program("idtGetData failed");

        qDebug() << "Filename : " << stgMedium.lpszFileName;
        //fprintf(stderr, TEXT("Filename: %ws\n"), stgMedium.lpszFileName);

        // Not working!!
        system("copy temp.bmp other.bmp");

        // Release COM objects and exit
        exit_program("");

    return a.exec();
}
 
1

Dopóki pawie wszystko masz w funkcji main to szanse na zrobienie tego dobrze (lub na prawienie tego) są bliskie zeru.

Inne poważne błędy, które rzucają mi się w oczy bez analizy kodu:

  • użycie system("copy temp.bmp other.bmp");
  • brak pojęcia co robi return a.exec(); (odpala event loop, na którym się wszystko powinno odbyć, a u ciebie nic się nie dzieje).
  • stosowanie globalnych zmiennych

Radzę najpierw opanować podstawy jakiegoś frameworka (Qt) zanim zaczniesz kombinować bardziej zaawansowane rzeczy, bo w przeciwnym razie bardziej będziesz walczył z własną niewiedzą czego używasz, niż z istotą problemu.

0

Ma ktoś jakiś pomysł jak to zrobić ?? Bo ciągle próbuję i nie udaje mi się zrobić.

0

Jaką wartość zwraca idtGetData?

0

Jeżeli chodzi o te przypisywanie

hr = pWiaDataTransfer->idtGetData(&stgMedium, 0);

to jak wypisałem przez qDebug() to wyskoczyło mi -2147467259

qDebug() << (hr = pWiaDataTransfer->idtGetData(&stgMedium, 0));
0
pWiaPropertyStorage->WriteMultiple(2, PropSpec, PropVar, WIA_IPA_FIRST);
if (FAILED(hr)) exit_program("WriteMultiple failed");

Czegoś tu brakuje...

Sprawdź, czy wywołanie WriteMultiple zwraca S_OK.

0

@_0x666_ zwraca S_OK

if (hr == S_OK) qDebug() << "WriteMultiple : OK";

I wypisuje mi "WriteMultiple : OK";

Nie wiem czy to coś ma wspólnego ale na msdn pisze coś że od systemów VISTA i wzwyż trzeba używać IWiaDevMgr2 itd.

0

Nie "trzeba", tylko "możesz". IWiaDevMgr2 został wprowadzony od Visty, więc siłą rzeczy nie możesz użyć go w systemach wcześniejszych.

Wracając do problemu. Sprawdź metodą IWiaDataTransfer::idtQueryGetData, czy format, w którym chcesz wyciągnąć dane jest obsługiwany.

0

@_0x666_ no właśnie zapomniałem napisać, że program tworzę na Windows 10

0

Nie sądzę, żeby to miało jakieś znaczenie.

Sprawdź format.

0

Kod poniżej dla idtQueryGetData zwraca S_OK

        WIA_FORMAT_INFO *m_pFormats;
        m_pFormats = new WIA_FORMAT_INFO;

        m_pFormats->guidFormatID = WiaImgFmt_BMP;
        m_pFormats->lTymed = TYMED_FILE;

        // idtGetData is currently returning S_FALSE
        hr = pWiaDataTransfer->idtGetData(&stgMedium, 0);

        if(pWiaDataTransfer->idtQueryGetData(m_pFormats) == S_OK)
            qDebug() << "pWiaDataTransfer->idtQueryGetData : S_OK";
        else
            qDebug() << "pWiaDataTransfer->idtQueryGetData : S_FALSE";
0

Po co ten new? Nie wystarczy zwykła zmienna lokalna?

WIA_FORMAT_INFO wia_Formats;

wia_Formats.guidFormatID = WiaImgFmt_BMP;
wia_Formats.lTymed = TYMED_FILE;
 
if(pWiaDataTransfer->idtQueryGetData(&wia_Formats) == S_OK) ...

Jeśli format jest ok, to może zamiast podawać jedynie temp.bmp, podaj pełną ścieżkę dostępu. Z tymi względnymi ścieżkami bywa różnie.

0

Dalej to samo. Ale dziwi mnie dlaczego w ogóle skaner i zaczyna skanować.

0

Skanuje, bo sam proces skanowania został poprawnie zainicjowany, problem leży w wygenerowaniu/przetransferowaniu bitmapy do aplikacji.

0

@_0x666_ a u cb działa ten kod

0

Niestety nie mam skanera, więc nie jestem w stanie sprawdzić tego kodu. Szukałem jakichś wirtualnych skanerów, ale znalazłem jedynie z obsługą protokołu TWAIN, dla WIA nie ma (albo nie szukałem zbyt dobrze).

Próbowałeś odpalić ten kod pod WinXP? Może faktycznie jest coś na rzeczy z tymi interfejsami (microsoft z reguły dbał o zachowanie wstecznej kompatybilności. No ale..).

0

Właśnie instaluję na maszynie wirtualnej xp i zobaczymy.

0

Na XP idtGetData zwraca S_FALSE;

1 użytkowników online, w tym zalogowanych: 0, gości: 1