HRESULT WIACamera::GetDeviceProperty(const unsigned int CamID, const PropertyType Type, int *piValue)
{
	HRESULT hr = S_OK;
	if ( CamID >= m_iCount ) return S_FALSE;

	IWiaPropertyStorage *pWiaPropertyStorage;
	hr = m_vRootItem[CamID]->QueryInterface(IID_IWiaPropertyStorage,(void**)&pWiaPropertyStorage);
	if (hr != S_OK) {
		return E_NOINTERFACE;
	}

	PROPSPEC PropSpec;
	PROPVARIANT PropVar;
	PropSpec.ulKind = PRSPEC_PROPID;

	if ( Type==CAMERA_SHUTTERSPEED ) {
		PropSpec.propid = WIA_DPC_EXPOSURE_TIME;
		hr = pWiaPropertyStorage->ReadMultiple( 1, &PropSpec, &PropVar );
	} else if ( Type==CAMERA_GAIN ) {
		PropSpec.propid = WIA_DPC_EXPOSURE_INDEX;
		hr = pWiaPropertyStorage->ReadMultiple( 1, &PropSpec, &PropVar );
	} else if ( Type==CAMERA_APERTURE ) {
		PropSpec.propid = WIA_DPC_FNUMBER;
		hr = pWiaPropertyStorage->ReadMultiple( 1, &PropSpec, &PropVar );
	} else {
		hr = E_NOTIMPL;
	}

	if (pWiaPropertyStorage) {
		pWiaPropertyStorage->Release();
		pWiaPropertyStorage = NULL;
	}
	if (hr == S_OK) {
		*piValue = (int)PropVar.lVal;
	}

	return hr;
}
//This function enumerates WIA devices and then creates an instance of each device.
//After that it calls EnumerateAndDownloadItems() on the root item got from creation of device.
HRESULT EnumerateWiaDevices( IWiaDevMgr2 *pWiaDevMgr2 )
{
    // Validate arguments
    if (NULL == pWiaDevMgr2)
    {
        HRESULT hr = E_INVALIDARG;
        ReportError(TEXT("Invalid argument passed to EnumerateWiaDevices()"),hr);
        return hr;
    }

    // Get a device enumerator interface
    IEnumWIA_DEV_INFO *pWiaEnumDevInfo = NULL;
    HRESULT hr = pWiaDevMgr2->EnumDeviceInfo( WIA_DEVINFO_ENUM_LOCAL, &pWiaEnumDevInfo );
    if (SUCCEEDED(hr))
    {
        // Reset the device enumerator to the beginning of the list
        hr = pWiaEnumDevInfo->Reset();
        if (SUCCEEDED(hr))
        {
            // We will loop until we get an error or pWiaEnumDevInfo->Next returns
            // S_FALSE to signal the end of the list.
            while (S_OK == hr)
            {
                // Get the next device's property storage interface pointer
                IWiaPropertyStorage *pWiaPropertyStorage = NULL;
                hr = pWiaEnumDevInfo->Next( 1, &pWiaPropertyStorage, NULL );

                // pWiaEnumDevInfo->Next will return S_FALSE when the list is
                // exhausted, so check for S_OK before using the returned
                // value.
                if (hr == S_OK)
                {
                    // Read some device properties - Device ID,name and descripion and return Device ID needed for creating Device
                    BSTR bstrDeviceID = NULL;
                    HRESULT hr1 = ReadWiaPropsAndGetDeviceID( pWiaPropertyStorage ,&bstrDeviceID);
                    if(SUCCEEDED(hr1))
                    {
                        // Call a function to create the device using device ID 
                        IWiaItem2 *pWiaRootItem2 = NULL;
                        hr1 = pWiaDevMgr2->CreateDevice( 0, bstrDeviceID, &pWiaRootItem2 );
                        if(SUCCEEDED(hr1))
                        {
                            // Enumerate items and for each item do transfer
                            hr1 = EnumerateAndDownloadItems( pWiaRootItem2 );
                            if(FAILED(hr1))
                            {
                                ReportError(TEXT("EnumerateAndDownloadItems() failed in EnumerateWiaDevices()"),hr1);
                            }
                            //Release pWiaRootItem2
                            pWiaRootItem2->Release();
                            pWiaRootItem2 = NULL;
                        }
                        else
                        {
                            ReportError(TEXT("Error calling IWiaDevMgr2::CreateDevice()"),hr1);
                        }
                    }
                    else
                    {
                        ReportError(TEXT("ReadWiaPropsAndGetDeviceID() failed in EnumerateWiaDevices()"),hr1);
                    }
                        
                    // Release the device's IWiaPropertyStorage*
                    pWiaPropertyStorage->Release();
                    pWiaPropertyStorage = NULL;
                }
                else if (FAILED(hr))
                {
                    // Report that an error occurred during enumeration
                    ReportError( TEXT("Error calling IEnumWIA_DEV_INFO::Next()"), hr );
                }
            }
            
            //
            // If the result of the enumeration is S_FALSE, since this
            // is normal, we will change it to S_OK.
            //
            if (S_FALSE == hr)
            {
                hr = S_OK;
            }
        }
        else
        {
            // Report that an error occurred calling Reset()
            ReportError( TEXT("Error calling IEnumWIA_DEV_INFO::Reset()"), hr );
        }
        // Release the enumerator
        pWiaEnumDevInfo->Release();
        pWiaEnumDevInfo = NULL;
    }
    else
    {
        // Report that an error occurred trying to create the enumerator
        ReportError( TEXT("Error calling IWiaDevMgr2::EnumDeviceInfo"), hr );
    }

    // Return the result of the enumeration
    return hr;
}
// This function downloads item after setting the format for the item and initializing callback (depending on category,itemtype)
// with the directory to download images to as well as the filename for the downloaded image.
HRESULT DownloadItem(IWiaItem2* pWiaItem2)
{
    if( (!pWiaItem2) )
    {
        HRESULT hr = E_INVALIDARG;
        ReportError(TEXT("Invalid argument passed to DownloadItem()"),hr);
        return hr;
    }
     // Get the IWiaTransfer interface
    IWiaTransfer *pWiaTransfer = NULL;
    HRESULT hr = pWiaItem2->QueryInterface( IID_IWiaTransfer, (void**)&pWiaTransfer );
    if (SUCCEEDED(hr))
    {
        // Create our callback class
        CWiaTransferCallback *pWiaClassCallback = new CWiaTransferCallback;
        if (pWiaClassCallback)
        {
            // Get the IWiaTransferCallback interface from our callback class.
            IWiaTransferCallback *pWiaTransferCallback = NULL;
            hr = pWiaClassCallback->QueryInterface( IID_IWiaTransferCallback, (void**)&pWiaTransferCallback );
            if (SUCCEEDED(hr))
            {
                //Set the format for the item to BMP
                IWiaPropertyStorage* pWiaPropertyStorage = NULL;
                HRESULT hr = pWiaItem2->QueryInterface( IID_IWiaPropertyStorage, (void**)&pWiaPropertyStorage );
                if(SUCCEEDED(hr))
                {
                    hr = WritePropertyGuid(pWiaPropertyStorage,WIA_IPA_FORMAT,WiaImgFmt_BMP);
                    if(FAILED(hr))
                    {
                        ReportError(TEXT("WritePropertyGuid() failed in DownloadItem().Format couldn't be set to BMP"),hr);
                    }
           
                    //Get the file extension and initialize callback with this extension and directory in which to transfer image 
                    //along with feeder flag.
                    //This will result in m_szFileName member callback class being set on which GetNextStream() will create and return a stream 
                    BSTR bstrFileExtension = NULL;
                    ReadPropertyBSTR(pWiaPropertyStorage,WIA_IPA_FILENAME_EXTENSION, &bstrFileExtension);
            
                    //Get the temporary folder path which is the directory where we will download the images
                    TCHAR bufferTempPath[MAX_TEMP_PATH];
                    GetTempPath(MAX_TEMP_PATH , bufferTempPath);
            
                    // Find out item type
                    GUID itemCategory = GUID_NULL;
                    ReadPropertyGuid(pWiaItem2,WIA_IPA_ITEM_CATEGORY,&itemCategory );
                    
                    BOOL bFeederTransfer = FALSE;
                    
                    if(IsEqualGUID(itemCategory,WIA_CATEGORY_FEEDER))
                    {
                        //Set WIA_IPS_PAGES to ALL_PAGES will enable transfer of all pages in the document feeder (multi-page transfer).
                        //If somebody wants to scan a specific number of pages say N, he should set WIA_IPS_PAGES to N. 
                        WritePropertyLong(pWiaPropertyStorage,WIA_IPS_PAGES,ALL_PAGES);
                         
                        bFeederTransfer = TRUE;
            
                    }

                    //Initialize the callback class with the directory, file extension and feeder flag
                    pWiaClassCallback->InitializeCallback(bufferTempPath,bstrFileExtension,bFeederTransfer);
                    
                    //Now download file item
                    hr = pWiaTransfer->Download(0,pWiaTransferCallback);
                    if(S_OK == hr)
                    {
                        _tprintf(TEXT("\npWiaTransfer->Download() on file item SUCCEEDED"));
                    }
                    else if(S_FALSE == hr)
                    {
                        ReportError(TEXT("pWiaTransfer->Download() on file item returned S_FALSE. File may be empty"),hr);
                    }
                    else if(FAILED(hr))
                    {
                        ReportError(TEXT("pWiaTransfer->Download() on file item failed"),hr);
                    }
            
                    //Release pWiaPropertyStorage interface
                    pWiaPropertyStorage->Release();
                    pWiaPropertyStorage = NULL;
                }
                else
                {
                    ReportError(TEXT("QueryInterface failed on IID_IWiaPropertyStorage"),hr);
                }

                // Release the callback interface
                pWiaTransferCallback->Release();
                pWiaTransferCallback = NULL;
            }
            else
            {
                ReportError( TEXT("pWiaClassCallback->QueryInterface failed on IID_IWiaTransferCallback"), hr );
            }
            // Release our callback.  It should now delete itself.
            pWiaClassCallback->Release();
            pWiaClassCallback = NULL;
        }
        else
        {
            ReportError( TEXT("Unable to create CWiaTransferCallback class instance") );
        }
            
        // Release the IWiaTransfer
        pWiaTransfer->Release();
        pWiaTransfer = NULL;
    }
    else
    {
        ReportError( TEXT("pIWiaItem2->QueryInterface failed on IID_IWiaTransfer"), hr );
    }
    return hr;
}
HRESULT EnumerateWiaDevices( IWiaDevMgr *pWiaDevMgr )
{
    //
    // Validate arguments
    //
    if (NULL == pWiaDevMgr)
    {
        return E_INVALIDARG;
    }

    //
    // Get a device enumerator interface
    //
    IEnumWIA_DEV_INFO *pWiaEnumDevInfo = NULL;
    HRESULT hr = pWiaDevMgr->EnumDeviceInfo( WIA_DEVINFO_ENUM_LOCAL, &pWiaEnumDevInfo );
    if (SUCCEEDED(hr))
    {
        //
        // Reset the device enumerator to the beginning of the list
        //
        hr = pWiaEnumDevInfo->Reset();
        if (SUCCEEDED(hr))
        {
            //
            // We will loop until we get an error or pWiaEnumDevInfo->Next returns
            // S_FALSE to signal the end of the list.
            //
            while (S_OK == hr)
            {
                //
                // Get the next device's property storage interface pointer
                //
                IWiaPropertyStorage *pWiaPropertyStorage = NULL;
                hr = pWiaEnumDevInfo->Next( 1, &pWiaPropertyStorage, NULL );

                //
                // pWiaEnumDevInfo->Next will return S_FALSE when the list is
                // exhausted, so check for S_OK before using the returned
                // value.
                //
                if (hr == S_OK)
                {
                    //
                    // Do something with the device's IWiaPropertyStorage*
                    //
                    ReadSomeWiaProperties( pWiaPropertyStorage );

                    //
                    // Call a helper function to create the device
                    // and do some stuff with it.
                    //
                    CreateWiaDeviceAndDoSomeStuff( pWiaDevMgr, pWiaPropertyStorage );

                    //
                    // Release the device's IWiaPropertyStorage*
                    //
                    pWiaPropertyStorage->Release();
                    pWiaPropertyStorage = NULL;
                }
                else if (FAILED(hr))
                {
                    //
                    // Report that an error occurred during enumeration
                    //
                    ReportError( TEXT("Error calling pWiaEnumDevInfo->Next"), hr );
                }
            }
            
            //
            // If the result of the enumeration is S_FALSE, since this
            // is normal, we will change it to S_OK.
            //
            if (S_FALSE == hr)
            {
                hr = S_OK;
            }
        }
        else
        {
            //
            // Report that an error occurred calling Reset()
            //
            ReportError( TEXT("Error calling IEnumWIA_DEV_INFO::Reset()"), hr );
        }

        //
        // Release the enumerator
        //
        pWiaEnumDevInfo->Release();
        pWiaEnumDevInfo = NULL;
    }
    else
    {
        //
        // Report that an error occurred trying to create the enumerator
        //
        ReportError( TEXT("Error calling IWiaDevMgr::EnumDeviceInfo"), hr );
    }

    //
    // Return the result of the enumeration
    //
    return hr;
}
HRESULT PrintItemName( IWiaItem *pWiaItem )
{
    //
    // Validate arguments
    //
    if (NULL == pWiaItem)
    {
        return E_INVALIDARG;
    }

    //
    // Get the IWiaPropertyStorage interface
    //
    IWiaPropertyStorage *pWiaPropertyStorage = NULL;
    HRESULT hr = pWiaItem->QueryInterface( IID_IWiaPropertyStorage, (void**)&pWiaPropertyStorage );
    if (SUCCEEDED(hr))
    {
        //
        // Declare PROPSPECs and PROPVARIANTs, and initialize them to zero.
        //
        PROPSPEC PropSpec[1] = {0};
        PROPVARIANT PropVar[1] = {0};

        //
        // How many properties are we querying for?
        //
        const ULONG c_nPropertyCount = sizeof(PropSpec)/sizeof(PropSpec[0]);

        //
        // Define which properties we want to read:
        // Device ID.  This is what we'd use to create
        // the device.
        //
        PropSpec[0].ulKind = PRSPEC_PROPID;
        PropSpec[0].propid = WIA_IPA_FULL_ITEM_NAME;

        //
        // Ask for the property values
        //
        hr = pWiaPropertyStorage->ReadMultiple( c_nPropertyCount, PropSpec, PropVar );
        if (SUCCEEDED(hr))
        {
            //
            // IWiaPropertyStorage::ReadMultiple will return S_FALSE if some
            // properties could not be read, so we have to check the return
            // types for each requested item.
            //
            
            //
            // Check the return type for the device ID
            //
            if (VT_BSTR == PropVar[0].vt)
            {
                //
                // Do something with the device ID
                //
                _tprintf( TEXT("Item Name: %ws\n"), PropVar[0].bstrVal );
            }

            //
            // Free the returned PROPVARIANTs
            //
            FreePropVariantArray( c_nPropertyCount, PropVar );
        }
        else
        {
            ReportError( TEXT("Error calling IWiaPropertyStorage::ReadMultiple"), hr );
        }

        //
        // Release the IWiaPropertyStorage interface
        //
        pWiaPropertyStorage->Release();
        pWiaPropertyStorage = NULL;
    }

    //
    // Return the result of reading the properties
    //
    return hr;
}
HRESULT TransferWiaItem( IWiaItem *pWiaItem )
{
    //
    // Validate arguments
    //
    if (NULL == pWiaItem)
    {
        return E_INVALIDARG;
    }
    
    //
    // Get the IWiaPropertyStorage interface so we can set required properties
    //
    IWiaPropertyStorage *pWiaPropertyStorage = NULL;
    HRESULT hr = pWiaItem->QueryInterface( IID_IWiaPropertyStorage, (void**)&pWiaPropertyStorage );
    if (SUCCEEDED(hr))
    {
        //
        // Prepare PROPSPECs and PROPVARIANTs for setting the
        // media type and format
        //
        PROPSPEC PropSpec[2] = {0};
        PROPVARIANT PropVariant[2] = {0};
        const ULONG c_nPropCount = sizeof(PropVariant)/sizeof(PropVariant[0]);

        //
        // Use BMP as the output format
        //
        GUID guidOutputFormat = WiaImgFmt_BMP;

        //
        // Initialize the PROPSPECs
        //
        PropSpec[0].ulKind = PRSPEC_PROPID;
        PropSpec[0].propid = WIA_IPA_FORMAT;
        PropSpec[1].ulKind = PRSPEC_PROPID;
        PropSpec[1].propid = WIA_IPA_TYMED;

        //
        // Initialize the PROPVARIANTs
        //
        PropVariant[0].vt = VT_CLSID;
        PropVariant[0].puuid = &guidOutputFormat;
        PropVariant[1].vt = VT_I4;
        PropVariant[1].lVal = TYMED_FILE;

        //
        // Set the properties
        //
        hr = pWiaPropertyStorage->WriteMultiple( c_nPropCount, PropSpec, PropVariant, WIA_IPA_FIRST );
        if (SUCCEEDED(hr))
        {
            //
            // Get the IWiaDataTransfer interface
            //
            IWiaDataTransfer *pWiaDataTransfer = NULL;
            hr = pWiaItem->QueryInterface( IID_IWiaDataTransfer, (void**)&pWiaDataTransfer );
            if (SUCCEEDED(hr))
            {
                //
                // Create our callback class
                //
                CWiaDataCallback *pCallback = new CWiaDataCallback;
                if (pCallback)
                {
                    //
                    // Get the IWiaDataCallback interface from our callback class.
                    //
                    IWiaDataCallback *pWiaDataCallback = NULL;
                    hr = pCallback->QueryInterface( IID_IWiaDataCallback, (void**)&pWiaDataCallback );
                    if (SUCCEEDED(hr))
                    {
                        //
                        // Perform the transfer using default settings
                        //
                        STGMEDIUM stgMedium = {0};
                        hr = pWiaDataTransfer->idtGetData( &stgMedium, pWiaDataCallback );
                        if (S_OK == hr)
                        {
                            //
                            // Print the filename (note that this filename is always
                            // a WCHAR string, not TCHAR.
                            //
                            _tprintf( TEXT("Transferred filename: %ws\n"), stgMedium.lpszFileName );

                            //
                            // Release any memory associated with the stgmedium
                            //
                            ReleaseStgMedium( &stgMedium );
                        }
                        else
                        {
                            ReportError( TEXT("pWiaDataTransfer->idtGetData failed"), hr );
                        }

                        //
                        // Release the callback interface
                        //
                        pWiaDataCallback->Release();
                        pWiaDataCallback = NULL;
                    }
                    else
                    {
                        ReportError( TEXT("pCallback->QueryInterface failed on IID_IWiaDataCallback"), hr );
                    }

                    //
                    // Release our callback.  It should now delete itself.
                    //
                    pCallback->Release();
                    pCallback = NULL;
                }
                else
                {
                    ReportError( TEXT("Unable to create CWiaDataCallback class instance") );
                }

                //
                // Release the IWiaDataTransfer
                //
                pWiaDataTransfer->Release();
                pWiaDataTransfer = NULL;
            }
            else
            {
                ReportError( TEXT("pWiaItem->QueryInterface failed on IID_IWiaDataTransfer"), hr );
            }
        }

        //
        // Release the IWiaPropertyStorage
        //
        pWiaPropertyStorage->Release();
        pWiaPropertyStorage = NULL;
    }
    else
    {
        ReportError( TEXT("pWiaItem->QueryInterface failed on IID_IWiaPropertyStorage"), hr );
    }

    return hr;
}
HRESULT WIACamera::SetDeviceProperty(const unsigned int CamID, const PropertyType Type, const int iValue, bool bAuto)
{
	HRESULT hr = S_OK;
	if ( CamID >= m_iCount ) return S_FALSE;

	IWiaPropertyStorage *pWiaPropertyStorage;
	hr = m_vRootItem[CamID]->QueryInterface(IID_IWiaPropertyStorage,(void**)&pWiaPropertyStorage);
	if (hr != S_OK) {
		return E_NOINTERFACE;
	}

	PROPSPEC PropSpec;
	PROPVARIANT PropVar;
	PropSpec.ulKind = PRSPEC_PROPID;
	PropVar.vt = VT_I4;

	if ( Type==CAMERA_SHUTTERSPEED ) {
		// shutter speed変更の際には,撮影モード変更後,値を設定
		long lResult;
		PropSpec.propid = WIA_DPC_EXPOSURE_MODE;
		hr = ReadPropertyLong( pWiaPropertyStorage, &PropSpec, &lResult);

		if (bAuto) {
			// EXPOSUREMODE_MANUAL	-> EXPOSUREMODE_APERTURE_PRIORITY
			// EXPOSUREMODE_SHUTTER_PRIORITY	-> EXPOSUREMODE_AUTO
			// OTHER : NOTHING 
			if ( lResult==EXPOSUREMODE_MANUAL ) {
				PropVar.lVal = EXPOSUREMODE_APERTURE_PRIORITY;
				hr = pWiaPropertyStorage->WriteMultiple( 1, &PropSpec, &PropVar, 2 );
			} else if ( lResult==EXPOSUREMODE_SHUTTER_PRIORITY ) {
				PropVar.lVal = EXPOSUREMODE_AUTO;
				hr = pWiaPropertyStorage->WriteMultiple( 1, &PropSpec, &PropVar, 2 );
			}
		} else {
			// EXPOSUREMODE_MANUAL	<- EXPOSUREMODE_APERTURE_PRIORITY
			// EXPOSUREMODE_SHUTTER_PRIORITY	<- EXPOSUREMODE_AUTO
			// OTHER : NOTHING 
			if ( lResult==EXPOSUREMODE_APERTURE_PRIORITY ) {
				PropVar.lVal = EXPOSUREMODE_MANUAL;
				hr = pWiaPropertyStorage->WriteMultiple( 1, &PropSpec, &PropVar, 2 );
			} else if ( lResult==EXPOSUREMODE_AUTO ) {
				PropVar.lVal = EXPOSUREMODE_SHUTTER_PRIORITY;
				hr = pWiaPropertyStorage->WriteMultiple( 1, &PropSpec, &PropVar, 2 );
			}
			//	then Set Value.
			PropSpec.propid = WIA_DPC_EXPOSURE_TIME;
			PropVar.lVal = iValue;
			hr = pWiaPropertyStorage->WriteMultiple( 1, &PropSpec, &PropVar, 2 );
		}
	} else if ( Type==CAMERA_APERTURE ) {
		// 絞り変更の際には,撮影モード変更後,値を設定
		long lResult;
		PropSpec.propid = WIA_DPC_EXPOSURE_MODE;
		hr = ReadPropertyLong( pWiaPropertyStorage, &PropSpec, &lResult);

		if (bAuto) {
			// EXPOSUREMODE_MANUAL	-> EXPOSUREMODE_SHUTTER_PRIORITY
			// EXPOSUREMODE_APERTURE_PRIORITY	-> EXPOSUREMODE_AUTO
			// OTHER : NOTHING 
			if ( lResult==EXPOSUREMODE_MANUAL ) {
				PropVar.lVal = EXPOSUREMODE_SHUTTER_PRIORITY;
				hr = pWiaPropertyStorage->WriteMultiple( 1, &PropSpec, &PropVar, 2 );
			} else if ( lResult==EXPOSUREMODE_APERTURE_PRIORITY ) {
				PropVar.lVal = EXPOSUREMODE_AUTO;
				hr = pWiaPropertyStorage->WriteMultiple( 1, &PropSpec, &PropVar, 2 );
			}
		} else {
			// EXPOSUREMODE_MANUAL	<- EXPOSUREMODE_SHUTTER_PRIORITY
			// EXPOSUREMODE_APERTURE_PRIORITY	<- EXPOSUREMODE_AUTO
			// OTHER : NOTHING 
			if ( lResult==EXPOSUREMODE_SHUTTER_PRIORITY ) {
				PropVar.lVal = EXPOSUREMODE_MANUAL;
				hr = pWiaPropertyStorage->WriteMultiple( 1, &PropSpec, &PropVar, 2 );
			} else if ( lResult==EXPOSUREMODE_AUTO ) {
				PropVar.lVal = EXPOSUREMODE_APERTURE_PRIORITY;
				hr = pWiaPropertyStorage->WriteMultiple( 1, &PropSpec, &PropVar, 2 );
			}
			//	then Set Value.
			PropSpec.propid = WIA_DPC_FNUMBER;
			PropVar.lVal = iValue;
			hr = pWiaPropertyStorage->WriteMultiple( 1, &PropSpec, &PropVar, 2 );
		}
	} else if ( Type==CAMERA_GAIN ) {
		PropSpec.propid = WIA_DPC_EXPOSURE_INDEX;
		if (bAuto) {
			PropVar.lVal = 0xFFFF;
		} else {
			PropVar.lVal = iValue;
		}
		hr = pWiaPropertyStorage->WriteMultiple( 1, &PropSpec, &PropVar, 2 );
	} else {
		hr = E_NOTIMPL;
	}

	if (pWiaPropertyStorage) {
		pWiaPropertyStorage->Release();
		pWiaPropertyStorage = NULL;
	}

	return hr;
}
HRESULT WIACamera::VideoCameraCapture(IWiaItem* pIWiaRoot, IplImage** ppIplImage)
{
	static int COUNTER = 0;
	COUNTER++;
	HRESULT hr = S_OK;
	if (pIWiaRoot==NULL) {
		cvReleaseImage(ppIplImage);
		(*ppIplImage) = NULL;
		return hr;
	}

	IWiaPropertyStorage *pIWiaPropStg	= NULL;
	// Get the next WIA device
	hr = pIWiaRoot->QueryInterface(IID_IWiaPropertyStorage,(void**)&pIWiaPropStg);

	if (SUCCEEDED(hr))	{
		// Get the device type of the device
		PROPSPEC    PropSpec[3];
		PROPVARIANT PropVar[3];
		memset(PropVar,0,sizeof(PropVar));
		PropSpec[0].ulKind = PRSPEC_PROPID;
		PropSpec[0].propid = WIA_DIP_DEV_ID;
		PropSpec[1].ulKind = PRSPEC_PROPID;
		PropSpec[1].propid = WIA_DIP_DEV_TYPE;
		PropSpec[2].ulKind = PRSPEC_PROPID;
		PropSpec[2].propid = WIA_DPV_IMAGES_DIRECTORY;
		// Get the type and the ID of each device
		hr = pIWiaPropStg->ReadMultiple(sizeof(PropSpec)/sizeof(PROPSPEC),
										PropSpec, PropVar);
		WORD myDev = GET_STIDEVICE_TYPE(PropVar[1].lVal);
		if (SUCCEEDED(hr)) {
			hr = m_pWiaVideo->put_ImagesDirectory(PropVar[2].bstrVal);
	    }
		if (SUCCEEDED(hr)) {
	        hr = m_pWiaVideo->put_PreviewVisible(FALSE);
			hr = m_pWiaVideo->CreateVideoByWiaDevID(PropVar[0].bstrVal, NULL, FALSE, TRUE);
	    }
	}
    //
    // Take a picture.  When this function returns, WIA Video will have already
    // captured a still image from the video stream, and it saved the image in
    // the 'FileName' file.
    //
	BSTR bstrFileName = NULL;

    if (SUCCEEDED(hr))
    {
		Sleep(2000);
		hr = m_pWiaVideo->TakePicture(&bstrFileName);
    }

    if (SUCCEEDED(hr))
    {
		cvReleaseImage(ppIplImage);
		// Convert to a char*
		const int BUFFER_SIZE = 4096;
		char filepath[BUFFER_SIZE];
		_bstr_t bstrIntermediate(bstrFileName);    // convert to
												// _bstr_t
		// you have to go through _bstr_t to have it work in ANSI
		// and Unicode
		sprintf_s(filepath, BUFFER_SIZE, "%s", (LPCTSTR)bstrIntermediate);
		(*ppIplImage) = cvLoadImage((char*)filepath);
	}
	return hr;
}
HRESULT WIACamera::Initialize()
{
	// CoInitialize(NULL);
	CoInitializeEx(NULL, COINIT_MULTITHREADED);

    IEnumWIA_DEV_INFO   *pWiaEnumDevInfo    = NULL;
	
	//
    // Create an instance of the device manager
    //
	HRESULT hr = CoCreateInstance( CLSID_WiaDevMgr, NULL, CLSCTX_LOCAL_SERVER, IID_IWiaDevMgr, (void**)&m_pWiaDevMgr );
    hr = CoCreateInstance(CLSID_WiaVideo, NULL, CLSCTX_INPROC_SERVER, IID_IWiaVideo, (void**) &m_pWiaVideo);

	if (SUCCEEDED(hr)) {
		//
		// Enumerate WIA devices on the system
		//
		hr = m_pWiaDevMgr->EnumDeviceInfo(WIA_DEVINFO_ENUM_LOCAL, &pWiaEnumDevInfo);
	}

	//
	// Reset the enumeration to start at the beginning of the list.
	//
	if (SUCCEEDED(hr)) {
		//
		// Call Reset on Enumerator
		//
		hr = pWiaEnumDevInfo->Reset();
	}

    BOOL bFound = FALSE;
	while ( SUCCEEDED(hr) ) {
		IWiaPropertyStorage *pIWiaPropStg	= NULL;
	    ULONG               ulFetched		= NULL;
		//
		// Get the next WIA device
		//
		hr = pWiaEnumDevInfo->Next(1, &pIWiaPropStg, &ulFetched);

		if (hr == S_OK)	{
			//
			// Get the device type of the device
			//
			PROPSPEC    PropSpec[3];
			PROPVARIANT PropVar[3];
			memset(PropVar,0,sizeof(PropVar));
			PropSpec[0].ulKind = PRSPEC_PROPID;
			PropSpec[0].propid = WIA_DIP_DEV_ID;
			PropSpec[1].ulKind = PRSPEC_PROPID;
			PropSpec[1].propid = WIA_DIP_DEV_TYPE;
			PropSpec[2].ulKind = PRSPEC_PROPID;
			PropSpec[2].propid = WIA_DIP_DEV_NAME;

			//
			// Get the type and the ID of each device
			//
			hr = pIWiaPropStg->ReadMultiple(sizeof(PropSpec)/sizeof(PROPSPEC),
											PropSpec, PropVar);

			//
			// If the device is a streaming video device/digital camera,
			//  get its ID
			//
			if (GET_STIDEVICE_TYPE(PropVar[1].lVal) == StiDeviceTypeStreamingVideo 
				|| GET_STIDEVICE_TYPE(PropVar[1].lVal) == StiDeviceTypeDigitalCamera) {
				std::wcerr	<< "WIA_DIP_DEV_ID :\t"		<< PropVar[0].bstrVal << std::endl
							<< "WIA_DIP_DEV_NAME :\t"	<< PropVar[2].bstrVal << std::endl;	
				bFound = TRUE;

				const size_t BUFFER_SIZE = 1024;
				char buf[BUFFER_SIZE];
				_bstr_t bstrIntermediate;

				bstrIntermediate.Assign(PropVar[0].bstrVal);
				sprintf_s((char*)buf, BUFFER_SIZE, "%s", (LPCTSTR)bstrIntermediate);
				char* strID = new char [strlen(buf)+1];
				strcpy_s( strID, strlen(buf)+1, buf );
				m_vCameraID.push_back(strID);

				bstrIntermediate.Assign(PropVar[2].bstrVal);
				sprintf_s((char*)buf, BUFFER_SIZE, "%s", (LPCTSTR)bstrIntermediate);
				char* strName = new char [strlen(buf)+1];
				strcpy_s( strID, strlen(buf)+1, buf );
				m_vCameraName.push_back(strName);
				delete [] strID;
				delete [] strName;

				//
				// Create a WIA device and get the recommended
				// images directory
				//
				IWiaItem *pRootItem = NULL;
				hr = m_pWiaDevMgr->CreateDevice(PropVar[0].bstrVal,
											&pRootItem);
				if (GET_STIDEVICE_TYPE(PropVar[1].lVal) == StiDeviceTypeStreamingVideo) {
					// ビデオカメラ特有の処理
					m_pCaptureFunc.push_back( &WIACamera::VideoCameraCapture );
				} else {
					// デジタルカメラ特有の処理
					m_pCaptureFunc.push_back( &WIACamera::DigitalCameraCapture );
				}
				if (SUCCEEDED(hr)) { 
					m_vRootItem.push_back(pRootItem);
				} else {
					m_vRootItem.push_back(NULL);
					throw "Error:\n";
					return hr;
				}
			}
		} else {
			break;
		}

		if (pIWiaPropStg) {
			pIWiaPropStg->Release();
			pIWiaPropStg = NULL;
		}
	}

	if (pWiaEnumDevInfo) {
		pWiaEnumDevInfo->Release();
		pWiaEnumDevInfo = NULL;
	}
	if (!bFound)
	{
		//
		// We did not find any WIA video streaming devices.  There is nothing left
		// to do.  Set result to E_FAIL
		//
		hr = E_FAIL;
		return hr;
	}


	m_iCount = (unsigned int)m_vRootItem.size();
	
    //
    // Return the result of creating the device manager
    //
    return hr;
}
HRESULT WIACamera::DigitalCameraCapture(IWiaItem* pIWiaRoot, IplImage** ppIplImage)
{
	HRESULT hr = S_OK;

	IWiaItem* pIWiaItem = NULL;
	hr = pIWiaRoot->DeviceCommand( 0, &WIA_CMD_TAKE_PICTURE, &pIWiaItem );

	if (pIWiaItem==NULL) {
		cvReleaseImage(ppIplImage);
		(*ppIplImage) = NULL;
		return hr;
	}
	IStream **ppStream = NULL;
	LONG	lCount = 0;
	// Create the data callback interface
	CDataCallback *pDataCallback = new CDataCallback( &lCount,&ppStream );
	if (pDataCallback == NULL) {
		return E_OUTOFMEMORY;
	}

	{
		// Get the interface pointers
		IWiaPropertyStorage *pWiaPropertyStorage;
		hr = pIWiaItem->QueryInterface(IID_IWiaPropertyStorage,(void**)&pWiaPropertyStorage);
		if (hr != S_OK) {
			return E_NOINTERFACE;
		}

		IWiaDataTransfer *pIWiaDataTransfer;
		hr = pIWiaItem->QueryInterface(IID_IWiaDataTransfer, (void**)&pIWiaDataTransfer);
		if (hr != S_OK) {
			return E_NOINTERFACE;
		}

		// Set the transfer type
		PROPSPEC specTymed;
		specTymed.ulKind = PRSPEC_PROPID;
		specTymed.propid = WIA_IPA_TYMED;

		PROPVARIANT varTymed;
		varTymed.vt = VT_I4;
		varTymed.lVal = TYMED_CALLBACK;

		hr = pWiaPropertyStorage->WriteMultiple(1, &specTymed, &varTymed, WIA_IPA_FIRST );
		PropVariantClear(&varTymed);
		if (FAILED(hr)) {
			return hr;
		}

		// If there is no transfer format specified, use the device default
		GUID guidFormat = GUID_NULL;
		GUID *pguidFormat = &guidFormat;
		PROPSPEC specPreferredFormat;

		specPreferredFormat.ulKind = PRSPEC_PROPID;
		specPreferredFormat.propid = WIA_IPA_PREFERRED_FORMAT;

		hr = ReadPropertyGuid( pWiaPropertyStorage, &specPreferredFormat, pguidFormat );
		if (FAILED(hr))	{
			return hr;
		}

		// Set the transfer format
		PROPSPEC specFormat;
		PROPVARIANT varFormat;
		specFormat.ulKind = PRSPEC_PROPID;
		specFormat.propid = WIA_IPA_FORMAT;
		varFormat.vt = VT_CLSID;
		varFormat.puuid = (CLSID *) CoTaskMemAlloc(sizeof(CLSID));
		if (varFormat.puuid == NULL) {
			return E_OUTOFMEMORY;
		}
		*varFormat.puuid = *pguidFormat;
		hr = pWiaPropertyStorage->WriteMultiple( 1, &specFormat, &varFormat, WIA_IPA_FIRST );
		PropVariantClear(&varFormat);
		if (FAILED(hr)) {
			return hr;
		}

		// Read the transfer buffer size from the device, default to 64K
		PROPSPEC specBufferSize;
		specBufferSize.ulKind = PRSPEC_PROPID;
		specBufferSize.propid = WIA_IPA_BUFFER_SIZE;
		LONG nBufferSize;
		hr = ReadPropertyLong( pWiaPropertyStorage, &specBufferSize, &nBufferSize );
		if (FAILED(hr)) {
			nBufferSize = 64 * 1024;
		}

		// Choose double buffered transfer for better performance
		WIA_DATA_TRANSFER_INFO WiaDataTransferInfo = { 0 };
		WiaDataTransferInfo.ulSize        = sizeof(WIA_DATA_TRANSFER_INFO);
		WiaDataTransferInfo.ulBufferSize  = 2 * nBufferSize;
		WiaDataTransferInfo.bDoubleBuffer = TRUE;

		// Start the transfer
		hr = pIWiaDataTransfer->idtGetBandedData( &WiaDataTransferInfo, pDataCallback );

		if (pWiaPropertyStorage) {
			pWiaPropertyStorage->Release();
			pWiaPropertyStorage = NULL;
		}
		if (pIWiaDataTransfer) {
			pIWiaDataTransfer->Release();
			pIWiaDataTransfer = NULL;
		}
	}
	if (pIWiaItem) {
		// Delete file from DigitalCamera storage
		pIWiaItem->DeleteItem(0);
		pIWiaItem->Release();
		pIWiaItem = NULL;
	}

	if (lCount!=1) throw "Error.\n"; 

	if ( SUCCEEDED(hr) ) { 
		Gdiplus::Bitmap myBmp(ppStream[0]);
		int Width = myBmp.GetWidth();
		int Height = myBmp.GetHeight();
		Gdiplus::Rect rect(0, 0, Width, Height);
		Gdiplus::BitmapData myBitmapData;
		Gdiplus::Status res = 
			myBmp.LockBits(
			&rect, Gdiplus::ImageLockModeRead,
			PixelFormat24bppRGB, &myBitmapData
		);
		if ( (*ppIplImage)==NULL ) {
			(*ppIplImage) = cvCreateImage(cvSize(Width,Height),IPL_DEPTH_8U,3);
		} else {
			CvSize oldSize = cvGetSize((*ppIplImage));
			if ( oldSize.width!=Width || oldSize.height!=Height ) {
				throw "Warning.\n";
				cvReleaseImage(&(*ppIplImage));
				(*ppIplImage) = cvCreateImage(cvSize(Width,Height),IPL_DEPTH_8U,3);
			}
		}

		unsigned char *pIplData = (unsigned char*)(*ppIplImage)->imageData;
		for ( int h=0; h < Height; h++) {
			unsigned char *pIplLine = &pIplData[(*ppIplImage)->widthStep*h];
			unsigned char *pBitmapLine = &((unsigned char*)myBitmapData.Scan0)[myBitmapData.Stride*h];
			memcpy( pIplLine, pBitmapLine, sizeof(unsigned char)*Width*3 );
			/*
			for ( int w=0; w < Width; w++) {
				pIplLine[w*3+0] = pBitmapLine[w*3+2];
				pIplLine[w*3+1] = pBitmapLine[w*3+1];
				pIplLine[w*3+2] = pBitmapLine[w*3+0];
			}
			*/
		}

	} else {
		delete (*ppIplImage);
		(*ppIplImage) = NULL;
	}
	ppStream[0]->Release();

	return hr;
}