Freigeben über


Zuordnen von Arbeitsspeicher für Daten

Der WIA-Dienst basiert auf den Informationen, die in der MINIDRV_TRANSFER_CONTEXT-Struktur bereitgestellt werden, um eine ordnungsgemäße Datenübertragung durchzuführen.

Die Elemente dieser Struktur, die für den WIA-Minitreiber relevant sind, sind:

bClassDrvAllocBuf − WIA-Dienstzuordnung Boolean.

pTransferBuffer − Zeiger auf den für die übertragenen Daten zugeordneten Arbeitsspeicher.

lBufferSize – Größe des Speichers, auf den der pTransferBuffer-Member verweist.

Wenn der bClassDrvAllocBuf-Member der MINIDRV_TRANSFER_CONTEXT-Struktur auf TRUE festgelegt ist, hat der WIA-Dienst Arbeitsspeicher für den Minitreiber zugewiesen. Wenn der bClassDrvAllocBuf-Member auf FALSE festgelegt ist, hat der WIA-Dienst keinen Arbeitsspeicher für den Minitreiber zugewiesen.

Der Minidriver sollte Arbeitsspeicher mithilfe der Funktion CoTaskMemAlloc zuordnen (beschrieben in der Microsoft Windows SDK-Dokumentation). Der Minidriver sollte dann den Zeiger auf den Speicherort des Arbeitsspeichers in pTransferBuffer und die Größe des Arbeitsspeichers in lBufferSize (in Bytes) speichern.

Das bClassDrvAllocBuff-Element wird nur auf FALSE festgelegt, wenn die WIA_IPA_TYMED-Eigenschaft auf TYMED_FILE oder TYMED_MULTIPAGE_FILE festgelegt ist und die WIA_IPA_ITEM_SIZE-Eigenschaft auf Null festgelegt ist.

Der Minidriver muss darauf achten, dass er den Puffer, auf den der pTransferBuffer-Member verweist, nicht überfüllt. Sie können dies vermeiden, indem Sie Daten in Mengen schreiben, die kleiner oder gleich dem im lBufferSize-Member gespeicherten Wert sind.

Verbessern der Datenübertragungsleistung durch Verwendung der minimalen Puffergröße

Der WIA-Minidriver kann die Während der Datenübertragung verwendete Arbeitsspeichermenge steuern, indem die Eigenschaften WIA_IPA_ITEM_SIZE und WIA_IPA_BUFFER_SIZE festgelegt werden.

Eine WIA-Anwendung verwendet die WIA_IPA_BUFFER_SIZE-Eigenschaft, um die minimale Übertragungspuffergröße zu bestimmen, die während einer Speicherübertragung angefordert werden soll. Je größer dieser Wert ist, desto größer ist die angeforderte Bandgröße. Wenn eine WIA-Anwendung einen Puffer anfordert, der kleiner als der Wert in der WIA_IPA_BUFFER_SIZE-Eigenschaft ist, ignoriert der WIA-Dienst diese angeforderte Größe und fragt den WIA-Minitreiber nach einem Puffer, der WIA_IPA_BUFFER_SIZE Bytes groß ist. Der WIA-Dienst fragt den WIA-Minitreiber immer nach Puffern, die mindestens WIA_IPA_BUFFER_SIZE Bytes groß sind.

Der Wert, den die WIA_IPA_BUFFER_SIZE -Eigenschaft enthält, ist die Mindestmenge an Daten, die eine Anwendung zu einem bestimmten Zeitpunkt anfordern kann. Je größer die Puffergröße, desto größer sind die Anforderungen an das Gerät. Zu kleine Puffergrößen können die Leistung der Datenübertragung beeinträchtigen.

Es wird empfohlen, die WIA_IPA_BUFFER_SIZE-Eigenschaft auf eine angemessene Größe festzulegen, damit das Gerät Daten mit einer effizienten Rate übertragen kann. Ausgleichen Sie dazu die Anzahl der Anforderungen (Puffergröße nicht zu klein) und die Anzahl zeitaufwändiger Anforderungen (Puffer zu groß) für Ihr Gerät, um eine optimale Leistung sicherzustellen.

Sie sollten die WIA_IPA_ITEM_SIZE-Eigenschaft auf null festlegen, wenn der WIA-Minitreiber Daten übertragen kann. Wenn der Übertragungstyp TYMED_FILE oder TYMED_MULTIPAGE_FILE ist, liegt es in der Verantwortung des Minitreibers, Arbeitsspeicher für den Datenpuffer zuzuweisen, der an die WIA-Dienstfunktion übergeben werden soll, die in die Datei schreibt. Dies sorgt für Konsistenz in der Implementierung der IWiaMiniDrv::d rvAcquireItemData-Methode .

Die IWiaMiniDrv::d rvAcquireItemData-Methode wird vom WIA-Dienst aufgerufen, wenn daten vom Gerät an eine Anwendung übertragen werden sollen. Der WIA-Treiber sollte bestimmen, welche Art von Übertragung (über den WIA-Dienst) die Anwendung versucht, indem er den tymed-Member des MINIDRV_TRANSFER_CONTEXT liest:

Der tymed-Member , der von der Anwendung festgelegt wird, kann einen der folgenden vier Werte aufweisen:

TYMED_FILE
Übertragen von Daten in eine Datei.

TYMED_MULTIPAGE_FILE
Übertragen von Daten in ein mehrseitiges Dateiformat.

TYMED_CALLBACK
Übertragen von Daten in den Arbeitsspeicher.

TYMED_MULTIPAGE_CALLBACK
Übertragen mehrerer Datenseiten in den Arbeitsspeicher.

Die verschiedenen TYMED-Einstellungen XXX_CALLBACK und XXX_FILE die Verwendung des Aufrufs der Rückrufschnittstelle der Anwendung ändern.

TYMED_CALLBACK und TYMED_MULTIPAGE_CALLBACK

Geben Sie für eine Speicherübertragung einen IWiaMiniDrvCallBack::MiniDrvCallback-Rückruf aus:

(pmdtc-pIWiaMiniDrvCallBack-MiniDrvCallback>> im folgenden Beispielquellcode)

Führen Sie den Rückruf mit den folgenden Werten aus:

IT_MSG_DATA
Der Treiber überträgt Daten.

IT_STATUS_TRANSFER_TO_CLIENT
Die Datenübertragungsnachricht.

lPercentComplete
Der Prozentsatz der abgeschlossenen Übertragung.

pmdtc-cbOffset>
Aktualisieren Sie dies an den aktuellen Speicherort, an dem die Anwendung den nächsten Datenblock schreiben soll.

lBytesReceived
Die Anzahl der Bytes im Datenblock, der an die Anwendung gesendet wird.

pmdtc
Zeiger auf eine MINIDRV_TRANSFER_CONTEXT-Struktur , die die Datenübertragungswerte enthält.

TYMED_FILE und TYMED_MULTIPAGE_FILE

Geben Sie für eine Dateiübertragung einen IWiaMiniDrvCallBack::MiniDrvCallback-Rückruf aus:

(pmdtc-pIWiaMiniDrvCallBack-MiniDrvCallback>> im folgenden Beispielquellcode)

Führen Sie den Rückruf mit den folgenden Werten aus.

IT_MSG_STATUS
Der Treiber sendet nur status (keine Daten).

IT_STATUS_TRANSFER_TO_CLIENT
Die Datenübertragungsnachricht.

lPercentComplete
Der Prozentsatz der abgeschlossenen Übertragung.

Wenn der ItemSize-Member der MINIDRV_TRANSFER_CONTEXT-Struktur auf 0 festgelegt ist, gibt dies der Anwendung an, dass der WIA-Treiber die resultierende Bildgröße nicht kennt und dann seine eigenen Datenpuffer zuordnet. Der WIA-Treiber liest die eigenschaft WIA_IPA_BUFFER_SIZE und ordnet Arbeitsspeicher für ein einzelnes Datenband zu. Der WIA-Treiber kann hier eine beliebige Menge an Arbeitsspeicher zuordnen, es wird jedoch empfohlen, die Zuordnung klein zu halten.

Überprüfen Sie das Flag pmdtc-bClassDrvAllocBuf, um festzustellen, ob der WIA-Dienst> Arbeitsspeicher für den Treiber zugewiesen hat. Wenn er auf TRUE festgelegt ist, hat der WIA-Dienst Arbeitsspeicher für den Treiber zugewiesen. Um herauszufinden, wie viel Arbeitsspeicher zugeordnet wurde, überprüfen Sie den Wert in pmdtc-lBufferSize>.

Um Ihren eigenen Arbeitsspeicher zuzuweisen, verwenden Sie CoTaskMemAlloc (beschrieben in der Microsoft Windows SDK-Dokumentation), und verwenden Sie den Zeiger in pmdtc-pTransferBuffer>. (Denken Sie daran, dass der Treiber diesen Arbeitsspeicher zugewiesen hat, sodass der Treiber ihn auch freigeben muss.) Legen Sie pmdtc-lBufferSize> auf die von Ihnen zugewiesene Größe fest. Wie bereits erwähnt, ordnet dieser WIA-Beispieltreiber einen Puffer zu, dessen Größe in Bytes dem in WIA_IPA_BUFFER_SIZE enthaltenen Wert entspricht. Der Treiber verwendet dann diesen Arbeitsspeicher.

Das folgende Beispiel zeigt eine Implementierung der IWiaMiniDrv::d rvAcquireItemData-Methode . In diesem Beispiel können beide Speicherbelegungsfälle behandelt werden.

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