Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Il servizio WIA si basa sulle informazioni fornite nella struttura MINIDRV_TRANSFER_CONTEXT per eseguire un trasferimento dei dati appropriato.
I membri di questa struttura rilevanti per il minidriver WIA sono:
bClassDrvAllocBuf − Boolean di allocazione del servizio WIA.
pTransferBuffer − Puntatore alla memoria allocata per i dati trasferiti.
lBufferSize − Dimensioni della memoria a cui punta il membro pTransferBuffer.
Se il membro bClassDrvAllocBuf della struttura MINIDRV_TRANSFER_CONTEXT è impostato su TRUE, il servizio WIA ha allocato la memoria per il minidriver. Se il membro bClassDrvAllocBuf è impostato su FALSE, il servizio WIA non ha allocato memoria per il minidriver.
Il minidriver deve allocare memoria usando la funzione CoTaskMemAlloc (descritta nella documentazione di Microsoft Windows SDK). Il minidriver deve quindi archiviare il puntatore nella posizione di memoria in pTransferBuffer e le dimensioni della memoria in lBufferSize (in byte).
Il membro bClassDrvAllocBuff è impostato su false solo se la proprietà WIA_IPA_TYMED è impostata su TYMED_FILE o TYMED_MULTIPAGE_FILE e la proprietà WIA_IPA_ITEM_SIZE è impostata su zero.
Il minidriver deve prestare attenzione a non sovrariempire il buffer a cui punta il membro pTransferBuffer. È possibile evitare questo problema scrivendo dati in quantità minori o uguali al valore archiviato nel membro lBufferSize.
Miglioramento delle prestazioni di trasferimento dei dati tramite dimensioni minime del buffer
Il minidriver WIA può controllare la quantità di memoria usata durante il trasferimento dei dati impostando le proprietà WIA_IPA_ITEM_SIZE e WIA_IPA_BUFFER_SIZE.
Un'applicazione WIA usa la proprietà WIA_IPA_BUFFER_SIZE per determinare le dimensioni minime del buffer di trasferimento da richiedere durante un trasferimento di memoria. Maggiore è questo valore, maggiore sarà la dimensione della banda richiesta. Se un'applicazione WIA richiede un buffer di dimensioni inferiori rispetto al valore nella proprietà WIA_IPA_BUFFER_SIZE, il servizio WIA ignora le dimensioni richieste e richiede al minidriver WIA un buffer delle dimensioni specificate da WIA_IPA_BUFFER_SIZE byte. Il servizio WIA chiede sempre al minidriver WIA di memorizzare buffer con dimensioni almeno WIA_IPA_BUFFER_SIZE byte.
Il valore contenuto dalla proprietà WIA_IPA_BUFFER_SIZE è la quantità minima di dati che un'applicazione può richiedere in qualsiasi momento. Maggiore sarà la dimensione del buffer, maggiore sarà la quantità di richieste per il dispositivo. Le dimensioni del buffer troppo piccole possono rallentare le prestazioni del trasferimento dei dati.
È consigliabile impostare la proprietà WIA_IPA_BUFFER_SIZE su una dimensione ragionevole per consentire al dispositivo di trasferire i dati a una velocità efficiente. Eseguire questa operazione bilanciando il numero di richieste (dimensioni del buffer non troppo piccole) e il numero di richieste dispendiose in termini di tempo (buffer troppo grandi) per il dispositivo per garantire prestazioni ottimali.
È consigliabile impostare la proprietà WIA_IPA_ITEM_SIZE su zero se il minidriver WIA può trasferire i dati. Se il tipo di trasferimento è TYMED_FILE o TYMED_MULTIPAGE_FILE, è responsabilità del minidriver allocare memoria per il buffer di dati da passare alla funzione del servizio WIA che scrive nel file. Ciò garantisce coerenza nell'implementazione del metodo IWiaMiniDrv::drvAcquireItemData.
Il metodo IWiaMiniDrv::d rvAcquireItemData viene chiamato dal servizio WIA quando intende trasferire i dati dal dispositivo a un'applicazione. Il driver WIA deve determinare quale tipo di trasferimento (tramite il servizio WIA) sta tentando di eseguire l'applicazione leggendo il membro del MINIDRV_TRANSFER_CONTEXT:
Il elemento tymed, impostato dall'applicazione, può assumere uno dei seguenti quattro valori:
TYMED_FILE
Trasferire i dati in un file.
TYMED_MULTIPAGE_FILE
Trasferire i dati in un formato di file a più pagine.
TYMED_CALLBACK
Trasferire i dati in memoria.
TYMED_MULTIPAGE_CALLBACK
Trasferire più pagine di dati in memoria.
Le diverse impostazioni TYMED XXX_CALLBACK e XXX_FILE modificano l'uso dell'interfaccia di callback dell'applicazione.
TYMED_CALLBACK e TYMED_MULTIPAGE_CALLBACK
Per un trasferimento di memoria, eseguire un callback IWiaMiniDrvCallBack::MiniDrvCallback:
(pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback nel codice sorgente di esempio seguente)
Eseguire il callback usando i valori seguenti:
IT_MSG_DATA
Il driver sta trasferendo i dati.
STATO_IT_TRASFERIMENTO_A_CLIENTE
Messaggio di trasferimento dei dati.
lPercentComplete
Percentuale del trasferimento completato.
pmdtc->cbOffset
Aggiorna la posizione attuale in cui l'applicazione deve scrivere il blocco di dati successivo.
lBytesReceived
Numero di byte nel blocco di dati inviato all'applicazione.
pmdtc
Puntatore a una struttura MINIDRV_TRANSFER_CONTEXT che contiene i valori di trasferimento dei dati.
TYMED_FILE e TYMED_MULTIPAGE_FILE
Per un trasferimento di file, eseguire il callback IWiaMiniDrvCallBack::MiniDrvCallback.
(pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback nel codice sorgente di esempio seguente)
Eseguire il callback usando i valori seguenti.
IT_MSG_STATUS
Il driver invia solo lo stato (nessun dato).
STATO_TRASFERIMENTO_AL_CLIENTE
Messaggio di trasferimento dei dati.
lPercentComplete
La percentuale del trasferimento che è stata completata.
Se il membro ItemSize della struttura MINIDRV_TRANSFER_CONTEXT è impostato su zero, indica all'applicazione che il driver WIA non conosce le dimensioni dell'immagine risultante e allocherà i propri buffer di dati. Il driver WIA leggerà la proprietà WIA_IPA_BUFFER_SIZE e allocherà la memoria per una singola banda di dati. Il driver WIA può allocare qualsiasi quantità di memoria necessaria qui, ma è consigliabile che l'allocazione venga mantenuta piccola.
Per verificare se il servizio WIA ha allocato memoria per il driver, controllare il flag pmdtc->bClassDrvAllocBuf. Se è impostato su TRUE, il servizio WIA ha allocato memoria per il driver. Per scoprire la quantità di memoria allocata, controllare il valore in pmdtc->lBufferSize.
Per allocare memoria personalizzata, usare CoTaskMemAlloc (descritto nella documentazione di Microsoft Windows SDK) e usare il puntatore disponibile in pmdtc->pTransferBuffer. Tenere presente che il driver ha allocato questa memoria, quindi il driver deve anche liberarla. Impostare pmdtc->lBufferSize sulle dimensioni allocate. Come indicato in precedenza, questo driver di esempio WIA alloca un buffer le cui dimensioni, in byte, sono uguali al valore contenuto in WIA_IPA_BUFFER_SIZE. Il driver usa quindi tale memoria.
Nell'esempio seguente viene illustrata un'implementazione del metodo IWiaMiniDrv::drvAcquireItemData. Questo esempio può gestire entrambi i casi di allocazione della memoria.
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;
}