配置資料的記憶體
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_SIZE 和 WIA_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_CONTEXT的tymed成員:
應用程式所設定 的 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;
}