다음을 통해 공유


데이터에 대한 메모리 할당

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_SIZE WIA_IPA_BUFFER_SIZE 속성을 설정하여 데이터 전송 중에 사용되는 메모리 양을 제어할 수 있습니다.

WIA 애플리케이션은 WIA_IPA_BUFFER_SIZE 속성을 사용하여 메모리 전송 중에 요청할 최소 전송 버퍼 크기를 결정합니다. 이 값이 클수록 요청된 대역 크기가 커집니다. WIA 애플리케이션이 WIA_IPA_BUFFER_SIZE 속성의 값보다 작은 버퍼를 요청하는 경우 WIA 서비스는 요청된 크기를 무시하고 크기가 WIA_IPA_BUFFER_SIZE 바이트인 버퍼를 WIA 미니드라이버에 요청합니다. WIA 서비스는 항상 WIA 미니드라이버에 크기가 WIA_IPA_BUFFER_SIZE 바이트 이상인 버퍼를 요청합니다.

WIA_IPA_BUFFER_SIZE 속성에 포함된 값은 애플리케이션이 지정된 시간에 요청할 수 있는 최소 데이터 양입니다. 버퍼 크기가 클수록 디바이스에 대한 요청이 커지게 됩니다. 버퍼 크기가 너무 작을 경우 데이터 전송 성능이 저하될 수 있습니다.

디바이스가 효율적인 속도로 데이터를 전송할 수 있도록 WIA_IPA_BUFFER_SIZE 속성을 적절한 크기로 설정하는 것이 좋습니다. 최적의 성능을 보장하기 위해 요청 수(버퍼 크기가 너무 작지 않음) 및 디바이스에 대한 시간이 많이 걸리는 요청 수(버퍼가 너무 큼)의 균형을 조정하여 이 작업을 수행합니다.

WIA 미니드라이버가 데이터를 전송할 수 있는 경우 WIA_IPA_ITEM_SIZE 속성을 0으로 설정해야 합니다. 전송 형식이 TYMED_FILE 또는 TYMED_MULTIPAGE_FILE 경우 파일에 쓰는 WIA 서비스 함수에 전달될 데이터 버퍼에 대한 메모리를 할당하는 것은 미니드라이버의 책임입니다. 이는 IWiaMiniDrv::d rvAcquireItemData 메서드의 구현에서 일관성을 제공합니다.

디바이스에서 애플리케이션으로 데이터를 전송하려는 경우 WIA 서비스에서 IWiaMiniDrv::d rvAcquireItemData 메서드를 호출합니다. WIA 드라이버는 MINIDRV_TRANSFER_CONTEXT tymed 멤버를 읽어 애플리케이션이 시도하는 전송 유형(WIA 서비스를 통해)을 결정해야 합니다.

애플리케이션 에서 설정하는 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 멤버가 0으로 설정된 경우 이는 WIA 드라이버가 결과 이미지 크기를 모르고 자체 데이터 버퍼를 할당한다는 것을 애플리케이션에 나타냅니다. WIA 드라이버는 WIA_IPA_BUFFER_SIZE 속성을 읽고 단일 데이터 대역에 대한 메모리를 할당합니다. WIA 드라이버는 여기에 필요한 모든 양의 메모리를 할당할 수 있지만 할당을 작게 유지하는 것이 좋습니다.

WIA 서비스에서 드라이버에 대한 메모리를 할당했는지 확인하려면 pmdtc-bClassDrvAllocBuf> 플래그를 검사. TRUE로 설정된 경우 WIA 서비스에서 드라이버에 대한 메모리를 할당합니다. 할당된 메모리 양을 확인하려면 pmdtc-lBufferSize>의 값을 검사.

사용자 고유의 메모리를 할당하려면 CoTaskMemAlloc(Microsoft Windows SDK 설명서에 설명됨)을 사용하고 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;
}