共用方式為


配置資料的記憶體

WIA 服務依賴 MINIDRV_TRANSFER_CONTEXT 結構中提供的資訊來執行適當的資料傳輸。

與 WIA 迷你驅動程式相關的這個結構成員如下:

bClassDrvAllocBuf - WIA 服務配置布林值。

pTransferBuffer - 為傳輸的資料配置記憶體指標。

lBufferSize - pTransferBuffer 成員所指向的記憶體大小。

如果MINIDRV_TRANSFER_CONTEXT結構的 bClassDrvAllocBuf 成員設定為 TRUE,則 WIA 服務會為 minidriver 配置記憶體。 如果 bClassDrvAllocBuf 成員設定為 FALSE,WIA 服務並未為 minidriver 配置任何記憶體。

minidriver 應該使用CoTaskMemAlloc函式來配置記憶體, (如Microsoft Windows SDK檔) 中所述。 minidriver 接著應該會將記憶體位置的指標儲存在 pTransferBuffer 中,並以位元組為單位) (lBufferSize (。

bClassDrvAllocBuff成員只有在WIA_IPA_TYMED屬性設定為TYMED_FILE或 TYMED_MULTIPAGE_FILE,且WIA_IPA_ITEM_SIZE屬性設定為零時,才會設定為FALSE

minidriver 必須小心不要過度填滿 pTransferBuffer 成員所指向的緩衝區。 您可以藉由將資料寫入小於或等於 lBufferSize 成員中所儲存的值來避免這個問題。

使用最小緩衝區大小增強資料傳輸效能

WIA 迷你驅動程式可以藉由設定 WIA_IPA_ITEM_SIZEWIA_IPA_BUFFER_SIZE 屬性來控制資料傳輸期間使用的記憶體數量。

WIA 應用程式會使用 WIA_IPA_BUFFER_SIZE 屬性來決定在記憶體傳輸期間要求的最低傳輸緩衝區大小。 這個值越大,要求之帶狀大小就越大。 如果 WIA 應用程式要求大小小於 WIA_IPA_BUFFER_SIZE 屬性值的緩衝區,WIA 服務會忽略此要求的大小,並要求 WIA 迷你驅動程式取得大小WIA_IPA_BUFFER_SIZE位元組的緩衝區。 WIA 服務一律會向 WIA 迷你驅動程式詢問大小至少WIA_IPA_BUFFER_SIZE位元組的緩衝區。

WIA_IPA_BUFFER_SIZE 屬性包含的值是應用程式隨時可以要求的資料量下限。 緩衝區大小愈大,要求就會愈大到裝置。 太小的緩衝區大小可能會降低資料傳輸的效能。

建議您將 WIA_IPA_BUFFER_SIZE 屬性設定為合理的大小,讓裝置以有效率的速度傳輸資料。 若要這樣做,請平衡緩衝區大小 (緩衝區大小不) 太小的要求數目,以及為裝置 (緩衝區) 太大的要求數目,以確保最佳效能。

如果 WIA 迷你驅動程式可以傳輸資料,您應該將 WIA_IPA_ITEM_SIZE 屬性設定為零。 如果傳輸類型TYMED_FILE或TYMED_MULTIPAGE_FILE,則迷你驅動程式必須負責配置記憶體給寫入檔案的 WIA 服務函式。 這會在 IWiaMiniDrv::d rvAcquireItemData 方法的實作中提供一致性。

當 WIA 服務想要將資料從裝置傳輸到應用程式時,WIA 服務會呼叫 IWiaMiniDrv::d rvAcquireItemData 方法。 WIA 驅動程式應該透過 WIA 服務判斷透過 WIA 服務 (的傳輸類型,) 方法是讀取MINIDRV_TRANSFER_CONTEXTtymed成員:

應用程式所設定 的 tymed 成員可以有下列四個值之一:

TYMED_FILE
將資料傳送至檔案。

TYMED_MULTIPAGE_FILE
將資料傳輸到多頁檔案格式。

TYMED_CALLBACK
將資料傳送至記憶體。

TYMED_MULTIPAGE_CALLBACK
將資料多頁傳送至記憶體。

不同的 TYMED 設定XXX_CALLBACK和XXX_FILE變更呼叫應用程式的回呼介面的使用方式。

TYMED_CALLBACK和TYMED_MULTIPAGE_CALLBACK

針對記憶體傳輸,發出 IWiaMiniDrvCallBack::MiniDrvCallback 回 呼:

下列範例原始程式碼 (pmdtc-pIWiaMiniDrvCallBack-MiniDrvCallback >>)

使用下列值進行回呼:

IT_MSG_DATA
驅動程式正在傳輸資料。

IT_STATUS_TRANSFER_TO_CLIENT
資料傳輸訊息。

lPercentComplete
完成的傳輸百分比。

pmdtc-cbOffset >
將此更新為應用程式應該寫入下一個資料區塊的目前位置。

lBytesReceived
要傳送至應用程式之資料區塊中的位元組數目。

pmdtc
包含資料傳輸值的 MINIDRV_TRANSFER_CONTEXT 結構的指標。

TYMED_FILE和TYMED_MULTIPAGE_FILE

針對檔案傳輸,發出 IWiaMiniDrvCallBack::MiniDrvCallback 回 呼::

下列範例原始程式碼 (pmdtc-pIWiaMiniDrvCallBack-MiniDrvCallback >>)

使用下列值進行回呼。

IT_MSG_STATUS
驅動程式只會傳送狀態, (沒有資料) 。

IT_STATUS_TRANSFER_TO_CLIENT
資料傳輸訊息。

lPercentComplete
完成的傳輸百分比。

如果MINIDRV_TRANSFER_CONTEXT結構的 ItemSize 成員設定為零,這會向應用程式指出 WIA 驅動程式不知道產生的映射大小,然後配置自己的資料緩衝區。 WIA 驅動程式會讀取 WIA_IPA_BUFFER_SIZE 屬性,並為單一資料範圍配置記憶體。 WIA 驅動程式可以在這裡配置它所需的任何記憶體數量,但建議將配置保持小。

若要查看 WIA 服務是否已為驅動程式配置記憶體,請檢查 pmdtc-bClassDrvAllocBuf > 旗標。 如果設定為 TRUE,則 WIA 服務已為驅動程式配置記憶體。 若要瞭解配置多少記憶體,請檢查 pmdtc-lBufferSize >中的值。

若要配置您自己的記憶體,請使用 Microsoft Windows SDK 檔) 中所述的CoTaskMemAlloc (,並使用位於 pmdtc-pTransferBuffer >中的指標。 (請記住,驅動程式已配置此記憶體,因此驅動程式也必須釋放它。) 將 pmdtc-lBufferSize > 設定為您配置的大小。 如先前所述,此 WIA 範例驅動程式會配置緩衝區的大小,以位元組為單位,等於 WIA_IPA_BUFFER_SIZE中包含的值。 驅動程式接著會使用該記憶體。

下列範例示範 IWiaMiniDrv::d rvAcquireItemData 方法的實作。 這個範例可以處理這兩個記憶體配置案例。

HRESULT _stdcall CWIADevice::drvAcquireItemData(
  BYTE                      *pWiasContext,
  LONG                      lFlags,
  PMINIDRV_TRANSFER_CONTEXT pmdtc,
  LONG                      *plDevErrVal)
{
  //
  // If the caller did not pass in the correct parameters,
  // then fail the call with E_INVALIDARG.
  //

  if (!pWiasContext) {
    return E_INVALIDARG;
  }

  if (!pmdtc) {
    return E_INVALIDARG;
  }

  if (!plDevErrVal) {
    return E_INVALIDARG;
  }

  *plDevErrVal = 0;

  HRESULT hr = E_FAIL;
  LONG lBytesTransferredToApplication = 0;
  LONG lClassDrvAllocSize = 0;
  //
  // (1) Memory allocation
  //

  if (pmdtc->bClassDrvAllocBuf) {

    //
    // WIA allocated the buffer for data transfers
    //

    lClassDrvAllocSize = pmdtc->lBufferSize;
    hr = S_OK;
  } else {

    //
    // Driver allocated the buffer for data transfers
    //

    hr = wiasReadPropLong(pWiasContext, WIA_IPA_BUFFER_SIZE, &lClassDrvAllocSize,NULL,TRUE);
    if (FAILED(hr)) {

      //
      // no memory was allocated, here so we can return early
      //

      return hr;
    }

    //
    // allocate memory of WIA_IPA_BUFFER_SIZE (own min buffer size)
    //

    pmdtc->pTransferBuffer = (PBYTE) CoTaskMemAlloc(lClassDrvAllocSize);
    if (!pmdtc->pTransferBuffer) {

      //
      // no memory was allocated, here so we can return early
      //

      return E_OUTOFMEMORY;
    }

    //
    // set the lBufferSize member
    //

    pmdtc->lBufferSize = lClassDrvAllocSize;
  }

  //
  // (2) Gather all information about data transfer settings and
  //     calculate the total data amount to transfer
  //

  if (hr == S_OK) {
    //
    // WIA service will populate the MINIDRV_TRANSFER_CONTEXT by reading the WIA properties.
    //
    // The following values will be written as a result of the 
    // wiasGetImageInformation() call
    //
    // pmdtc->lWidthInPixels
    // pmdtc->lLines
    // pmdtc->lDepth
    // pmdtc->lXRes
    // pmdtc->lYRes
    // pmdtc->lCompression
    // pmdtc->lItemSize
    // pmdtc->guidFormatID
    // pmdtc->tymed
    //
    // if the FORMAT is set to BMP or MEMORYBMP, the
    // following values will also be set automatically
    //
    // pmdtc->cbWidthInBytes
    // pmdtc->lImageSize
    // pmdtc->lHeaderSize
    // pmdtc->lItemSize (will be updated using the known image format information)
    //

    hr = wiasGetImageInformation(pWiasContext,0,pmdtc);
    if (hr == S_OK) {

      //
      // (3) Send the image data to the application
      //

      LONG lDepth = 0;
      hr = wiasReadPropLong(pWiasContext, WIA_IPA_DEPTH, &lDepth,NULL,TRUE);
      if (hr == S_OK) {

        LONG lPixelsPerLine = 0;
        hr = wiasReadPropLong(pWiasContext, WIA_IPA_PIXELS_PER_LINE, &lPixelsPerLine,NULL,TRUE);
        if (hr == S_OK) {

            LONG lBytesPerLineRaw     = ((lPixelsPerLine * lDepth) + 7) / 8;
            LONG lBytesPerLineAligned = (lPixelsPerLine * lDepth) + 31;
            lBytesPerLineAligned      = (lBytesPerLineAligned / 8) & 0xfffffffc;
            LONG lTotalImageBytes     = pmdtc->lImageSize + pmdtc->lHeaderSize;
            LONG lBytesReceived       = pmdtc->lHeaderSize;
            lBytesTransferredToApplication = 0;
            pmdtc->cbOffset = 0;

            while ((lBytesReceived)) {

              LONG lPercentComplete = (LONG)(((float)lBytesTransferredToApplication/(float)lTotalImageBytes) * 100.0f);
              switch (pmdtc->tymed) {
              case TYMED_MULTIPAGE_CALLBACK:
              case TYMED_CALLBACK:
                {
                  hr = pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback(IT_MSG_DATA,IT_STATUS_TRANSFER_TO_CLIENT,
                                                                  lPercentComplete,pmdtc->cbOffset,lBytesReceived,pmdtc,0);
                pmdtc->cbOffset += lBytesReceived;
                lBytesTransferredToApplication += lBytesReceived;
           }
            break;
          case TYMED_MULTIPAGE_FILE:
          case TYMED_FILE:
            {
                //
                // lItemSize is the amount that wiasWriteBufToFile will write to FILE
                //

                pmdtc->lItemSize = lBytesReceived;
                hr = wiasWriteBufToFile(0,pmdtc);
                if (FAILED(hr)) {
                    break;
                }

                hr = pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback(IT_MSG_STATUS,IT_STATUS_TRANSFER_TO_CLIENT,
                                                                  lPercentComplete,0,0,NULL,0);
                lBytesTransferredToApplication += lBytesReceived;
              }
              break;
          default:
              {
          hr = E_FAIL;
              }
              break;
          }

          //
          // scan from device, requesting ytesToReadFromDevice
          //

          LONG lBytesRemainingToTransfer = (lTotalImageBytes - lBytesTransferredToApplication);
          if (lBytesRemainingToTransfer <= 0) {
              break;
            }

            //
            // calculate number of bytes to request from device
            //

            LONG lBytesToReadFromDevice = (lBytesRemainingToTransfer > pmdtc->lBufferSize) ? pmdtc->lBufferSize : lBytesRemainingToTransfer;

            // RAW data request
            lBytesToReadFromDevice = (lBytesToReadFromDevice / lBytesPerLineAligned) * lBytesPerLineRaw;

            // Aligned data request
            // lBytesToReadFromDevice = (lBytesToReadFromDevice / lBytesPerLineAligned) * lBytesPerLineAligned;

            if ((hr == S_FALSE)||FAILED(hr)) {

              //
              // user canceled or the callback failed for some reason
              //

              break;
            }

            //
            // request byte amount from device
            //

            hr = GetDataFromMyDevice(pmdtc->pTransferBuffer, lBytesToReadFromDevice, (DWORD*)&lBytesReceived);
            if (FAILED(hr)) {
                break;
            }

            //
            // this device returns raw data.  If your device does this too, then you should call the AlignInPlace
            // helper function to align the data.
            //

            lBytesReceived = AlignMyRawData(pmdtc->pTransferBuffer,lBytesReceived,lBytesPerLineAligned,lBytesPerLineRaw);

          } // while ((lBytesReceived))
        }
      }
    }
  }

  //
  // free any allocated memory for buffers
  //

  if (!pmdtc->bClassDrvAllocBuf) {
    CoTaskMemFree(pmdtc->pTransferBuffer);
    pmdtc->pTransferBuffer = NULL;
    pmdtc->lBufferSize = 0;
  }

  return hr;
}