次の方法で共有


データのメモリの割り当て

WIA サービスは、適切なデータ転送を実行するために、 MINIDRV_TRANSFER_CONTEXT 構造体で提供される情報に依存します。

WIA ミニドライバーに関連するこの構造体のメンバーは次のとおりです。

bClassDrvAllocBuf - WIA サービス割り当てブール値。

pTransferBuffer - 転送されたデータに割り当てられたメモリへのポインター。

lBufferSize - pTransferBuffer メンバーが指すメモリのサイズ。

MINIDRV_TRANSFER_CONTEXT 構造体の bClassDrvAllocBuf メンバーが TRUE に設定されている場合、WIA サービスによってミニドライバーのメモリが割り当てられます。 bClassDrvAllocBuf メンバーが FALSE に設定されている場合、WIA サービスはミニドライバーのメモリを割り当てませんでした。

ミニドライバーは CoTaskMemAlloc 関数 (Microsoft Windows SDK ドキュメントで説明) を使用してメモリを割り当てる必要があります。 ミニドライバーは、メモリ位置へのポインターを pTransferBuffer に格納し、メモリのサイズを lBufferSize (バイト単位) に格納する必要があります。

bClassDrvAllocBuff メンバーは WIA_IPA_TYMED プロパティが TYMED_FILE または TYMED_MULTIPAGE_FILE に設定され、 WIA_IPA_ITEM_SIZE プロパティが 0 に設定されている場合にのみ、 FALSE に設定されます。

ミニドライバーは、 pTransferBuffer メンバーが指すバッファーをオーバーフィルしないように注意する必要があります。 これを回避するには、 lBufferSize メンバーに格納されている値以下の量でデータを書き込むことができます。

最小バッファー サイズを使用したデータ転送パフォーマンスの向上

WIA ミニドライバーは、 WIA_IPA_ITEM_SIZEWIA_IPA_BUFFER_SIZE のプロパティを設定することで、データ転送中に使用されるメモリの量を制御できます。

WIA アプリケーションでは、WIA_IPA_BUFFER_SIZE プロパティを使用して、メモリ転送中に要求する最小転送バッファー サイズを決定します。 この値が大きいほど、要求されたバンド サイズが大きくなります。 WIA アプリケーションが、WIA_IPA_BUFFER_SIZE プロパティの値よりも小さいサイズのバッファーを要求した場合、WIA サービスはこの要求されたサイズを無視し、サイズが WIA_IPA_BUFFER_SIZE バイトのバッファーを WIA ミニドライバーに要求します。 WIA サービスは常に、サイズが WIA_IPA_BUFFER_SIZE バイト以上のバッファーを WIA ミニドライバーに要求します。

WIA_IPA_BUFFER_SIZE プロパティに含まれる値は、アプリケーションが任意の時点で要求できるデータの最小量です。 バッファー サイズが大きいほど、デバイスへの要求は大きくなります。 バッファー サイズが小さすぎると、データ転送のパフォーマンスが低下する可能性があります。

デバイスが効率的な速度でデータを転送できるように、WIA_IPA_BUFFER_SIZE プロパティを適切なサイズに設定することをお勧めします。 これを行うには、最適なパフォーマンスを確保するために、デバイスの要求の数 (バッファー サイズが小さすぎず) と時間のかかる要求の数 (バッファーが大きすぎる) のバランスを取ります。

WIA ミニドライバーがデータを 転送できる場合は、 WIA_IPA_ITEM_SIZE プロパティを 0 に設定する必要があります。 転送の種類が TYMED_FILE または TYMED_MULTIPAGE_FILE の場合、ファイルに書き込む WIA サービス関数に渡されるデータ バッファーのメモリを割り当てるのはミニドライバーの責任です。 これにより、 IWiaMiniDrv::drvAcquireItemData メソッドの実装 に一貫性が提供 されます。

IWiaMiniDrv::drvAcquireItemData メソッドは、WIA サービスがデバイスからアプリケーションにデータを転送するときに呼び出されます。 WIA ドライバーは MINIDRV_TRANSFER_CONTEXTtymed メンバーを読み取ることによって、アプリケーションが試行している転送の種類 (WIA サービス経由) を決定する必要があります。

アプリケーションによって設定される tymed メンバーは、次の 4 つの値のいずれかを持つことができます。

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
データ転送メッセージ。

IPercentComplete
転送の完了率。

pmdtc->cbOffset
これを、アプリケーションが次のデータ チャンクを書き込む現在の場所に更新します。

IBytesReceived
アプリケーションに送信されるデータ チャンク内のバイト数。

pmdtc
データ転送値を含む MINIDRV_TRANSFER_CONTEXT 構造体へのポインター。

TYMED_FILE と TYMED_MULTIPAGE_FILE

ファイル転送の場合は、 IWiaMiniDrvCallBack::MiniDrvCallback コールバックを発行します。

(次のサンプル ソース コードのpmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback )

次の値を使用してコールバックを行います。

IT_MSG_STATUS
ドライバーは状態のみを送信しています (データなし)。

IT_STATUS_TRANSFER_TO_CLIENT
データ転送メッセージ。

IPercentComplete
転送の完了率。

MINIDRV_TRANSFER_CONTEXT 構造体の ItemSize メンバーが 0 に設定されている場合、これは、WIA ドライバーが結果のイメージ サイズを認識せず、独自のデータ バッファーを割り当てることをアプリケーションに示します。 WIA ドライバーは、 WIA_IPA_BUFFER_SIZE プロパティを読み取り、データの 1 つのバンドのメモリを割り当てます。 WIA ドライバーは、ここで必要なメモリの任意の量を割り当てることができますが、割り当てを小さくすることをお勧めします。

WIA サービスがドライバーのメモリを割り当てたかどうかを確認するには、 pmdtc->bClassDrvAllocBuf フラグをチェックします。 TRUE に設定すると、WIA サービスによってドライバーのメモリが割り当てられます。 割り当てられたメモリの量を確認するには、 pmdtc->lBufferSize の値をチェックします。

独自のメモリを割り当てるには、 CoTaskMemAlloc (Microsoft Windows SDK のドキュメントで説明) を使用し、 pmdtc->pTransferBuffer にあるポインターを使用します。 (ドライバーがこのメモリを割り当てたので、ドライバーも解放する必要があります。 pmdtc->lBufferSize を割り当てたサイズに設定します。 前述のように、この WIA サンプル ドライバーは、サイズ (バイト単位) が WIA_IPA_BUFFER_SIZE に含まれる値と等しいバッファーを割り当てます。 その後、ドライバーはそのメモリを使用します。

次のコード例は IWiaMiniDrv::drvAcquireItemData メソッドの実装を示しています。 この例では、両方のメモリ割り当てケースを処理できます。

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;
}