Allocation de la mémoire pour les données
Le service WIA s’appuie sur les informations fournies dans la structure MINIDRV_TRANSFER_CONTEXT pour effectuer un transfert de données approprié.
Les membres de cette structure qui sont pertinents pour le minidriver WIA sont les suivants :
bClassDrvAllocBuf − Allocation de service WIA Boolean.
pTransferBuffer - Pointeur vers la mémoire allouée pour les données transférées.
lBufferSize : taille de la mémoire pointée par le membre pTransferBuffer .
Si le membre bClassDrvAllocBuf de la structure MINIDRV_TRANSFER_CONTEXT est défini sur TRUE, le service WIA a alloué de la mémoire pour le minidriver. Si le membre bClassDrvAllocBuf est défini sur FALSE, le service WIA n’a pas alloué de mémoire pour le minidriver.
Le minidriver doit allouer de la mémoire à l’aide de la fonction CoTaskMemAlloc (décrite dans la documentation Microsoft Windows SDK). Le minidriver doit ensuite stocker le pointeur vers l’emplacement de mémoire dans pTransferBuffer et la taille de la mémoire dans lBufferSize (en octets).
Le membre bClassDrvAllocBuff est défini sur FALSE uniquement si la propriété WIA_IPA_TYMED a la valeur TYMED_FILE ou TYMED_MULTIPAGE_FILE et si la propriété WIA_IPA_ITEM_SIZE a la valeur zéro.
Le minidriver doit faire attention à ne pas surcharger la mémoire tampon pointée par le membre pTransferBuffer . Vous pouvez éviter cela en écrivant des données dans des quantités inférieures ou égales à la valeur stockée dans le membre lBufferSize .
Amélioration des performances de transfert de données à l’aide de la taille minimale de la mémoire tampon
Le minidriver WIA peut contrôler la quantité de mémoire utilisée pendant le transfert de données en définissant les propriétés WIA_IPA_ITEM_SIZE et WIA_IPA_BUFFER_SIZE .
Une application WIA utilise la propriété WIA_IPA_BUFFER_SIZE pour déterminer la taille minimale de mémoire tampon de transfert à demander pendant un transfert de mémoire. Plus cette valeur est grande, plus la taille de la bande demandée est grande. Si une application WIA demande une mémoire tampon dont la taille est inférieure à la valeur de la propriété WIA_IPA_BUFFER_SIZE, le service WIA ignore cette taille demandée et demande au minidriver WIA une mémoire tampon de WIA_IPA_BUFFER_SIZE octets. Le service WIA demande toujours au minidriver WIA des mémoires tampons d’au moins WIA_IPA_BUFFER_SIZE octets.
La valeur que contient la propriété WIA_IPA_BUFFER_SIZE est la quantité minimale de données qu’une application peut demander à tout moment. Plus la taille de la mémoire tampon est grande, plus les demandes seront adressées à l’appareil. Les tailles de mémoire tampon trop petites peuvent ralentir les performances du transfert de données.
Il est recommandé de définir la propriété WIA_IPA_BUFFER_SIZE sur une taille raisonnable pour permettre à l’appareil de transférer des données à un débit efficace. Pour ce faire, équilibrez le nombre de requêtes (taille de mémoire tampon pas trop petite) et le nombre de requêtes chronophages (mémoire tampon trop volumineuse) pour votre appareil afin de garantir des performances optimales.
Vous devez définir la propriété WIA_IPA_ITEM_SIZE sur zéro si le minidriver WIA peut transférer des données. Si le type de transfert est TYMED_FILE ou TYMED_MULTIPAGE_FILE, il incombe au minidriver d’allouer de la mémoire pour la mémoire tampon de données à passer à la fonction de service WIA qui écrit dans le fichier. Cela fournit une cohérence dans l’implémentation de la méthode IWiaMiniDrv::d rvAcquireItemData .
La méthode IWiaMiniDrv::d rvAcquireItemData est appelée par le service WIA lorsqu’il a l’intention de transférer des données de l’appareil vers une application. Le pilote WIA doit déterminer le type de transfert (via le service WIA) que l’application tente de tenter, en lisant le membre lié du MINIDRV_TRANSFER_CONTEXT :
Le membre lié , qui est défini par l’application, peut avoir l’une des quatre valeurs suivantes :
TYMED_FILE
Transférez des données vers un fichier.
TYMED_MULTIPAGE_FILE
Transférez des données vers un format de fichier multipage.
TYMED_CALLBACK
Transférez des données en mémoire.
TYMED_MULTIPAGE_CALLBACK
Transférez plusieurs pages de données en mémoire.
Les différents paramètres TYMED XXX_CALLBACK et XXX_FILE modifier l’utilisation de l’appel de l’interface de rappel de l’application.
TYMED_CALLBACK et TYMED_MULTIPAGE_CALLBACK
Pour un transfert de mémoire, émettez un rappel IWiaMiniDrvCallBack::MiniDrvCallback :
(pmdtc-pIWiaMiniDrvCallBack-MiniDrvCallback>> dans l’exemple de code source suivant)
Effectuez le rappel à l’aide des valeurs suivantes :
IT_MSG_DATA
Le pilote transfère des données.
IT_STATUS_TRANSFER_TO_CLIENT
Message de transfert de données.
lPercentComplete
Pourcentage du transfert terminé.
pmdtc-cbOffset>
Mettez-le à jour vers l’emplacement actuel où l’application doit écrire le segment de données suivant.
lBytesReceived
Nombre d’octets dans le segment de données envoyé à l’application.
pmdtc
Pointeur vers une structure MINIDRV_TRANSFER_CONTEXT qui contient les valeurs de transfert de données.
TYMED_FILE et TYMED_MULTIPAGE_FILE
Pour un transfert de fichiers, émettez un rappel IWiaMiniDrvCallBack::MiniDrvCallback ::
(pmdtc-pIWiaMiniDrvCallBack-MiniDrvCallback>> dans l’exemple de code source suivant)
Effectuez le rappel à l’aide des valeurs suivantes.
IT_MSG_STATUS
Le pilote envoie status uniquement (aucune donnée).
IT_STATUS_TRANSFER_TO_CLIENT
Message de transfert de données.
lPercentComplete
Pourcentage du transfert terminé.
Si le membre ItemSize de la structure MINIDRV_TRANSFER_CONTEXT est défini sur zéro, cela indique à l’application que le pilote WIA ne connaît pas la taille d’image résultante et qu’il allouera ensuite ses propres mémoires tampons de données. Le pilote WIA lit la propriété WIA_IPA_BUFFER_SIZE et alloue de la mémoire pour une seule bande de données. Le pilote WIA peut allouer n’importe quelle quantité de mémoire dont il a besoin ici, mais il est recommandé de conserver une petite allocation.
Pour voir si le service WIA a alloué de la mémoire au pilote, case activée l’indicateur pmdtc-bClassDrvAllocBuf>. S’il est défini sur TRUE, le service WIA a alloué de la mémoire pour le pilote. Pour déterminer la quantité de mémoire allouée, case activée la valeur dans pmdtc-lBufferSize>.
Pour allouer votre propre mémoire, utilisez CoTaskMemAlloc (décrit dans la documentation Microsoft Windows SDK) et utilisez le pointeur situé dans pmdtc-pTransferBuffer>. (N’oubliez pas que le pilote a alloué cette mémoire, de sorte que le pilote doit également la libérer.) Définissez pmdtc-lBufferSize> sur la taille que vous avez allouée. Comme indiqué précédemment, cet exemple de pilote WIA alloue une mémoire tampon dont la taille, en octets, est égale à la valeur contenue dans WIA_IPA_BUFFER_SIZE. Le pilote utilise ensuite cette mémoire.
L’exemple suivant montre une implémentation de la méthode IWiaMiniDrv::d rvAcquireItemData . Cet exemple peut gérer les deux cas d’allocation de mémoire.
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;
}