HRESULT EnumerateItems( IWiaItem *pWiaItem )
{
    //
    // Validate arguments
    //
    if (NULL == pWiaItem)
    {
        return E_INVALIDARG;
    }

    //
    // Get the item type for this item
    //
    LONG lItemType = 0;
    HRESULT hr = pWiaItem->GetItemType( &lItemType );

    //
    // Do something with this item.  Print the item name.
    //
    PrintItemName( pWiaItem );

    //
    // If this is an image, transfer it
    //
    if (lItemType & WiaItemTypeImage)
    {
        hr = TransferWiaItem( pWiaItem );
    }

    //
    // If it is a folder, or it has attachments, enumerate its children
    //
    if (lItemType & WiaItemTypeFolder ||
        lItemType & WiaItemTypeHasAttachments)
    {
        //
        // Get the child item enumerator for this item
        //    
        IEnumWiaItem *pEnumWiaItem = NULL;
        hr = pWiaItem->EnumChildItems( &pEnumWiaItem );
        if (SUCCEEDED(hr))
        {
            //
            // We will loop until we get an error or pEnumWiaItem->Next returns
            // S_FALSE to signal the end of the list.
            //
            while (S_OK == hr)
            {
                //
                // Get the next child item
                //
                IWiaItem *pChildWiaItem = NULL;
                hr = pEnumWiaItem->Next( 1, &pChildWiaItem, NULL );

                //
                // pEnumWiaItem->Next will return S_FALSE when the list is
                // exhausted, so check for S_OK before using the returned
                // value.
                //
                if (S_OK == hr)
                {
                    //
                    // Recurse into this item
                    //
                    hr = EnumerateItems( pChildWiaItem );

                    //
                    // Release this item
                    //
                    pChildWiaItem->Release();
                    pChildWiaItem = NULL;
                }
                else if (FAILED(hr))
                {
                    //
                    // Report that an error occurred during enumeration
                    //
                    ReportError( TEXT("Error calling pEnumWiaItem->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;
            }

            //
            // Release the enumerator
            //
            pEnumWiaItem->Release();
            pEnumWiaItem = NULL;
        }
    }
    return  hr;
}
HRESULT CreateWiaDeviceAndDoSomeStuff( IWiaDevMgr *pWiaDevMgr, IWiaPropertyStorage *pWiaPropertyStorage )
{
    //
    // Validate arguments
    //
    if (NULL == pWiaPropertyStorage)
    {
        return E_INVALIDARG;
    }

    //
    // 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.  We want the
    // device ID, so we can create the device.
    //
    PropSpec[0].ulKind = PRSPEC_PROPID;
    PropSpec[0].propid = WIA_DIP_DEV_ID;

    //
    // Ask for the property values
    //
    HRESULT hr = pWiaPropertyStorage->ReadMultiple( c_nPropertyCount, PropSpec, PropVar );
    if (SUCCEEDED(hr))
    {
        //
        // Check the return type for the device ID to make
        // sure this property was actually read.
        //
        if (VT_BSTR == PropVar[0].vt)
        {
            //
            // Create the WIA device, which results in obtaining
            // the root IWiaItem
            //
            IWiaItem *pWiaRootItem = NULL;
            hr = CreateWiaDevice( pWiaDevMgr, PropVar[0].bstrVal, &pWiaRootItem );
            if (SUCCEEDED(hr))
            {
                //
                // Recursively enumerate the items
                // (This function will also do some stuff with each item)
                //
                hr = EnumerateItems( pWiaRootItem );

                //
                // Free the root item
                //
                pWiaRootItem->Release();
                pWiaRootItem = NULL;
            }
            else
            {
                ReportError( TEXT("Error calling CreateWiaDevice"), hr );
            }
        }

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

    //
    // Return the result of all of this
    //
    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;
}