HRESULT wiasGetDriverItemPrivateContext( _In_ BYTE* pWiasContext, _Out_ BYTE** ppWiaDriverItemContext) { HRESULT hr = E_INVALIDARG; if (pWiasContext && ppWiaDriverItemContext) { IWiaDrvItem *pIWiaDrvItem = NULL; hr = wiasGetDrvItem(pWiasContext, &pIWiaDrvItem); if (SUCCEEDED(hr)) { hr = pIWiaDrvItem->GetDeviceSpecContext(ppWiaDriverItemContext); // // The caller will handle the failure case. A failure, may mean that // the the WIA item does not have a private device specific context // stored. This is OK, because is is not required. // } else { WIAEX_ERROR((g_hInst, "Failed to get the WIA driver item from the application item, hr = 0x%08X", hr)); } } else { WIAEX_ERROR((g_hInst, "Invalid parameter")); } return hr; }
HRESULT MakeFullItemName( _In_ IWiaDrvItem* pParent, _In_ BSTR bstrItemName, _Out_ BSTR* pbstrFullItemName) { HRESULT hr = S_OK; if (pParent && bstrItemName && pbstrFullItemName) { BSTR bstrParentFullItemName = NULL; hr = pParent->GetFullItemName(&bstrParentFullItemName); if (SUCCEEDED(hr)) { WCHAR wFullItemName[MAX_PATH * 2] = {}; hr = StringCbPrintf(wFullItemName, sizeof(wFullItemName), TEXT("%ws\\%ws"), bstrParentFullItemName, bstrItemName); if (SUCCEEDED(hr)) { *pbstrFullItemName = SysAllocString(wFullItemName); if (*pbstrFullItemName) { hr = S_OK; } else { hr = E_OUTOFMEMORY; WIAEX_ERROR((g_hInst, "Failed to allocate memory for BSTR full item name, hr = 0x%08X", hr)); } } else { WIAEX_ERROR((g_hInst, "Failed to allocate memory for BSTR full item name, hr = 0x%08X", hr)); } SysFreeString(bstrParentFullItemName); bstrParentFullItemName = NULL; } else { WIAEX_ERROR((g_hInst, "Failed to produce the full item name, hr = 0x%08X", hr)); } } else { hr = E_INVALIDARG; WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); } return hr; }
HRESULT CWiaDriver::Diagnostic( _Inout_ LPDIAG pBuffer) { HRESULT hr = S_OK; WIAEX_TRACE((g_hInst, "IStiUSD::Diagnostic..")); if ((!pBuffer) || (pBuffer->dwSize < sizeof(STI_DIAG)) || (pBuffer->sErrorInfo.dwSize < sizeof(STI_ERROR_INFO))) { hr = E_INVALIDARG; WIAEX_ERROR((g_hInst, "Invalid parameter (buffer: %p, size: %u bytes (needed: %u), error: %u bytes (needed: %u)), hr = 0x%08X", pBuffer, pBuffer ? pBuffer->dwSize : 0, sizeof(STI_DIAG), pBuffer ? pBuffer->sErrorInfo.dwSize : 0, sizeof(STI_ERROR_INFO), hr)); m_hrLastEdviceError = STIERR_INVALID_PARAM; } if (SUCCEEDED(hr)) { pBuffer->dwVendorDiagCode = 0; pBuffer->dwStatusMask = 0; pBuffer->sErrorInfo.dwGenericError = NOERROR; pBuffer->sErrorInfo.dwVendorError = 0; memset(pBuffer->sErrorInfo.szExtendedErrorText, 0, sizeof(pBuffer->sErrorInfo.szExtendedErrorText)); if (STI_DIAGCODE_HWPRESENCE == pBuffer->dwBasicDiagCode) { WIAEX_TRACE((g_hInst, "STI_DIAGCODE_HWPRESENCE..")); } else { WIAEX_ERROR((g_hInst, "Unknown basic diag code requested (and ignored): %u", pBuffer->dwBasicDiagCode)); } } WIAEX_TRACE((g_hInst, "IStiUSD::Diagnostic 0x%08X", hr)); return hr; }
WIA_DEV_CAP_DRV* CWIACapabilityManager::GetCapabilities() { WIA_DEV_CAP_DRV* pCapabilities = NULL; if ((!m_ulEvents) && (!m_ulCommands)) { WIAEX_ERROR((g_hInst, "No capabilities to return")); pCapabilities = NULL; } else { pCapabilities = &m_CapabilityArray[0]; } return pCapabilities; }
HRESULT CWIACapabilityManager::Initialize( _In_ HINSTANCE hInstance) { HRESULT hr = S_OK; if (!hInstance) { hr = E_INVALIDARG; WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); } if (SUCCEEDED(hr)) { m_hInstance = hInstance; } return hr; }
WIA_DEV_CAP_DRV* CWIACapabilityManager::GetEvents() { WIA_DEV_CAP_DRV* pEvents = NULL; if (!m_ulEvents) { WIAEX_ERROR((g_hInst, "No events to return")); pEvents = NULL; } else { // // Event capabilities are stored at the beginning of the capability list: // pEvents = &m_CapabilityArray[0]; } return pEvents; }
WIA_DEV_CAP_DRV* CWIACapabilityManager::GetCommands() { WIA_DEV_CAP_DRV* pCommands = NULL; if (!m_ulCommands) { WIAEX_ERROR((g_hInst, "No commands to return")); pCommands = NULL; } else { // // Command capabilities are stored at the end of the capability list, after the event capabilities: // pCommands = &m_CapabilityArray[m_ulEvents]; } return pCommands; }
void CWIACapabilityManager::FreeCapability( _In_ WIA_DEV_CAP_DRV *pWIADeviceCapability, BOOL bFreeCapabilityContentOnly) { if (pWIADeviceCapability) { if (pWIADeviceCapability->guid) { CoTaskMemFree(pWIADeviceCapability->guid); pWIADeviceCapability->guid = NULL; } if (pWIADeviceCapability->wszName) { CoTaskMemFree(pWIADeviceCapability->wszName); pWIADeviceCapability->wszName = NULL; } if (pWIADeviceCapability->wszDescription) { CoTaskMemFree(pWIADeviceCapability->wszDescription); pWIADeviceCapability->wszDescription = NULL; } if (pWIADeviceCapability->wszIcon) { CoTaskMemFree(pWIADeviceCapability->wszIcon); pWIADeviceCapability->wszIcon = NULL; } if (!bFreeCapabilityContentOnly) { CoTaskMemFree(pWIADeviceCapability); } } else { WIAEX_ERROR((g_hInst, "Invalid parameter, caller attempted to free a NULL WIA_DEV_CAP_DRV structure")); } }
HRESULT CWiaDriver::GetCapabilities( _Out_ PSTI_USD_CAPS pDevCaps) { HRESULT hr = S_OK; WIAEX_TRACE_BEGIN; if (!pDevCaps) { hr = E_INVALIDARG; WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X",hr)); } if (SUCCEEDED(hr)) { // // The sample driver supports device notifications (required), known also as interrupt events. // Polling (optional) it is not needed so STI_GENCAP_POLLING_NEEDED is not reported here: // memset(pDevCaps, 0, sizeof(STI_USD_CAPS)); pDevCaps->dwVersion = STI_VERSION_3; pDevCaps->dwGenericCaps = STI_GENCAP_WIA | STI_USD_GENCAP_NATIVE_PUSHSUPPORT | STI_GENCAP_NOTIFICATIONS; WIAS_TRACE((g_hInst, "Device capabilities: 0x%08X", pDevCaps->dwGenericCaps)); } if (FAILED(hr)) { m_hrLastEdviceError = hr; } WIAEX_TRACE((g_hInst, "IStiUSD::GetCapabilities 0x%08X", hr)); return hr; }
HRESULT CWIACapabilityManager::AllocateCapability( _Out_ WIA_DEV_CAP_DRV **ppWIADeviceCapability) { HRESULT hr = S_OK; WIA_DEV_CAP_DRV *pWIADeviceCapability = NULL; if (!ppWIADeviceCapability) { hr = E_INVALIDARG; WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); } if (SUCCEEDED(hr)) { *ppWIADeviceCapability = NULL; #pragma prefast(suppress:__WARNING_MEMORY_LEAK, "pWIADeviceCapability is freed with FreeCapability when the call fails") pWIADeviceCapability = (WIA_DEV_CAP_DRV*)CoTaskMemAlloc(sizeof(WIA_DEV_CAP_DRV)); if (!pWIADeviceCapability) { hr = E_OUTOFMEMORY; WIAEX_ERROR((g_hInst, "Failed to allocate memory for WIA_DEV_CAP_DRV structure, hr = 0x%08X", hr)); } else { // // Successfully created WIA_DEV_CAP_DRV, now initialize to 0. // memset(pWIADeviceCapability, 0, sizeof(WIA_DEV_CAP_DRV)); } } if (SUCCEEDED(hr)) { #pragma prefast(suppress:__WARNING_MEMORY_LEAK, "Freed with FreeCapability when the call fails") pWIADeviceCapability->guid = (GUID*)CoTaskMemAlloc(sizeof(GUID)); if (!pWIADeviceCapability->guid) { hr = E_OUTOFMEMORY; WIAEX_ERROR((g_hInst, "Failed to allocate memory for GUID member of WIA_DEV_CAP_DRV structure, hr = 0x%08X", hr)); } } if (SUCCEEDED(hr)) { #pragma prefast(suppress:__WARNING_MEMORY_LEAK, "Freed with FreeCapability when the call fails") pWIADeviceCapability->wszName = (LPOLESTR)CoTaskMemAlloc(MAX_CAPABILITY_STRING_SIZE_BYTES); if (!pWIADeviceCapability->wszName) { hr = E_OUTOFMEMORY; WIAEX_ERROR((g_hInst, "Failed to allocate memory for LPOLESTR (wszName) member of WIA_DEV_CAP_DRV structure, hr = 0x%08X", hr)); } } if (SUCCEEDED(hr)) { #pragma prefast(suppress:__WARNING_MEMORY_LEAK, "Freed with FreeCapability when the call fails") pWIADeviceCapability->wszDescription = (LPOLESTR)CoTaskMemAlloc(MAX_CAPABILITY_STRING_SIZE_BYTES); if (!pWIADeviceCapability->wszDescription) { hr = E_OUTOFMEMORY; WIAEX_ERROR((g_hInst, "Failed to allocate memory for LPOLESTR (wszDescription) member of WIA_DEV_CAP_DRV structure, hr = 0x%08X", hr)); } } if (SUCCEEDED(hr)) { #pragma prefast(suppress:__WARNING_MEMORY_LEAK, "Freed with FreeCapability when the call fails") pWIADeviceCapability->wszIcon = (LPOLESTR)CoTaskMemAlloc(MAX_CAPABILITY_STRING_SIZE_BYTES); if (!pWIADeviceCapability->wszIcon) { hr = E_OUTOFMEMORY; WIAEX_ERROR((g_hInst, "Failed to allocate memory for LPOLESTR (wszIcon) member of WIA_DEV_CAP_DRV structure, hr = 0x%08X", hr)); } } if (SUCCEEDED(hr)) { *pWIADeviceCapability->guid = GUID_NULL; memset(pWIADeviceCapability->wszName, 0, MAX_CAPABILITY_STRING_SIZE_BYTES); memset(pWIADeviceCapability->wszDescription, 0, MAX_CAPABILITY_STRING_SIZE_BYTES); memset(pWIADeviceCapability->wszIcon, 0, MAX_CAPABILITY_STRING_SIZE_BYTES); *ppWIADeviceCapability = pWIADeviceCapability; } else if (pWIADeviceCapability) { FreeCapability(pWIADeviceCapability); pWIADeviceCapability = NULL; } return hr; }
HRESULT CWIACapabilityManager::AddCapability( const GUID guidCapability, UINT uiNameResourceID, UINT uiDescriptionResourceID, ULONG ulFlags, _In_ LPCWSTR wszIcon) { HRESULT hr = S_OK; WIA_DEV_CAP_DRV *pWIADeviceCapability = NULL; WCHAR wCapabilityString[MAX_PATH] = {}; if (!wszIcon) { hr = E_INVALIDARG; WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); } // // Allocate memory for the new capability structure: // if (SUCCEEDED(hr)) { hr = AllocateCapability(&pWIADeviceCapability); if (SUCCEEDED(hr) && (!pWIADeviceCapability)) { hr = E_POINTER; WIAEX_ERROR((g_hInst, "AllocateCapability failed to return a valid pointer, hr = 0x%08X", hr)); } if (FAILED(hr)) { WIAEX_ERROR((g_hInst, "Cannot allocate memory for capability, hr = 0x%08X", hr)); } } // // Copy the capability flags and GUID identifier: // if (SUCCEEDED(hr)) { pWIADeviceCapability->ulFlags = ulFlags; *pWIADeviceCapability->guid = guidCapability; } // // Load and copy the capability name from resources: // if (SUCCEEDED(hr)) { if (LoadString(m_hInstance, uiNameResourceID, wCapabilityString, ARRAYSIZE(wCapabilityString))) { hr = StringCbCopyW(pWIADeviceCapability->wszName, MAX_CAPABILITY_STRING_SIZE_BYTES, wCapabilityString); if(FAILED(hr)) { WIAEX_ERROR((g_hInst, "Failed to copy source string (%ws) to destination string, hr = 0x%08X", wCapabilityString, hr)); } } else { hr = E_FAIL; WIAEX_ERROR((g_hInst, "Failed to load the device capability name string %u from resources, hr = 0x%08X", uiNameResourceID, hr)); } } // // Load and copy the capability description from resources: // if (SUCCEEDED(hr)) { memset(wCapabilityString, 0, sizeof(wCapabilityString)); if (LoadString(m_hInstance, uiDescriptionResourceID, wCapabilityString, ARRAYSIZE(wCapabilityString))) { hr = StringCbCopyW(pWIADeviceCapability->wszDescription, MAX_CAPABILITY_STRING_SIZE_BYTES, wCapabilityString); if(FAILED(hr)) { WIAEX_ERROR((g_hInst, "Failed to copy source string (%ws) to destination string, hr = 0x%08X", wCapabilityString, hr)); } } else { hr = E_FAIL; WIAEX_ERROR((g_hInst, "Failed to load the device capability description string %u from DLL resource, hr = 0x%08X", uiDescriptionResourceID, hr)); } } // // Copy the icon location: // if (SUCCEEDED(hr)) { memset(pWIADeviceCapability->wszIcon, 0, MAX_CAPABILITY_STRING_SIZE_BYTES); hr = StringCbCopyW(pWIADeviceCapability->wszIcon, MAX_CAPABILITY_STRING_SIZE_BYTES, wszIcon); if(FAILED(hr)) { WIAEX_ERROR((g_hInst, "Failed to copy source string (%ws) to destination string, hr = 0x%08X", wszIcon, hr)); } } // // Add the new capability item to the array: // if(SUCCEEDED(hr)) { if ((WIA_NOTIFICATION_EVENT & pWIADeviceCapability->ulFlags) || (WIA_ACTION_EVENT & pWIADeviceCapability->ulFlags)) { // // Event capabilities are inserted at the beginning of the array: // m_CapabilityArray.Insert(*pWIADeviceCapability, 0); m_ulEvents += 1; } else { // // Command capabilities are appended at the end of the array: // m_CapabilityArray.Append(*pWIADeviceCapability); m_ulCommands += 1; } if ((m_ulEvents + m_ulCommands) != (ULONG)m_CapabilityArray.Size()) { WIAEX_ERROR((g_hInst, "Counted %u capabilities (%u events, %u commands), recorded %u..", m_ulEvents + m_ulCommands, m_ulEvents, m_ulCommands, m_CapabilityArray.Size())); } } // // Clean up: // if (pWIADeviceCapability) { CoTaskMemFree(pWIADeviceCapability); pWIADeviceCapability = NULL; } return hr; }
HRESULT CWiaDriver::InitializeDeviceConnection( _In_ LPCWSTR wszDevicePath, _In_ HKEY hDeviceKey) { HRESULT hr = S_OK; WIAEX_TRACE_BEGIN; // // Validate parameters: // if ((!wszDevicePath) || (!hDeviceKey)) { hr = E_INVALIDARG; WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); } // // Initialize here the connection with the scanner device identified by wszDevicePath. // // For example: // // if (SUCCEEDED(hr)) // { // hr = m_ScannerDevice.Initialize(wszDevicePath); // if (FAILED(hr)) // { // WIAEX_ERROR((g_hInst, "Failed to initialize connection with scanner device described by %ws, hr = 0x%08X", wszDevicePath, hr)); // } // } // // // Initialize the valid format information arrays, matching the current scanner configuration if available: // if (SUCCEEDED(hr)) { hr = InitializeFormatInfoArrays(); if(FAILED(hr)) { WIAEX_ERROR((g_hInst, "Failed to initialize WIA_FORMAT_INFO arrays, hr = 0x%08X", hr)); } } // // Initialize the page size array used by this driver (only one list, for portrait orientation). // // This sample driver supports Letter, and also pretends (without actually doing it) custom // and auto-detect document sizes: // if (SUCCEEDED(hr)) { // // WIA_PAGE_CUSTOM is always supported: // m_lPortraitSizesArray.Append(WIA_PAGE_CUSTOM); // // WIA_PAGE_AUTO is also supported if the scanner reports that it supports automatic document size detection: // m_lPortraitSizesArray.Append(WIA_PAGE_AUTO); // // Other standard page sizes: // GetValidPageSizes(MAX_SCAN_AREA_WIDTH, MAX_SCAN_AREA_HEIGHT, MIN_SCAN_AREA_WIDTH, MIN_SCAN_AREA_HEIGHT, TRUE, m_lPortraitSizesArray); } // // Create the capability manager which will be initialized (uniquely per // driver session) during the first IWiaMiniDrv::drvGetCapabilities call: // if (SUCCEEDED(hr)) { hr = m_tCapabilityManager.Initialize(g_hInst); if (FAILED(hr)) { WIAEX_ERROR((g_hInst, "Failed to initialize the WIA driver capability manager object, hr = 0x%08X", hr)); } } WIAEX_TRACE_FUNC_HR; return hr; }
HRESULT CWiaDriver::GetStatus( _Inout_ PSTI_DEVICE_STATUS pDevStatus) { HRESULT hr = S_OK; if (!pDevStatus) { hr = E_INVALIDARG; WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X",hr)); } // // A driver may be requested to report one or both of the following: // // STI_DEVSTATUS_EVENTS_STATE - The driver should fill in the dwEventHandlingState member // STI_DEVSTATUS_ONLINE_STATE - The driver should fill in the dwOnlineState member // // In this case STI_DEVSTATUS_EVENTS_STATE is not expected nor supported as this driver // does not support polling events (if the driver previously set the STI_GENCAP_POLLING_NEEDED // flag in the device's STI_DEV_CAPS structure, the IStiUSD::GetStatus method is the means // by which the Event Monitor determines if a still image device event has occurred; // the Event Monitor will call the method, specifying STI_DEVSTATUS_EVENT_STATE // in the supplied STI_DEVICE_STATUS structure; the driver must poll the device // and set STI_EVENTHANDLING_PENDING if an event has occurred) // // If the caller specifies STI_DEVSTATUS_ONLINE_STATE in the supplied // STI_DEVICE_STATUS structure, the driver should set the appropriate flag // in the STI_DEVICE_STATUS structure's dwOnlineState member. // if (SUCCEEDED(hr)) { pDevStatus->dwOnlineState = 0; pDevStatus->dwHardwareStatusCode = 0; pDevStatus->dwEventHandlingState = 0; // // STI_DEVSTATUS_ONLINE_STATE: // if (pDevStatus->StatusMask & STI_DEVSTATUS_ONLINE_STATE) { // // This sample driver is always online and ready: // pDevStatus->dwOnlineState = STI_ONLINESTATE_OPERATIONAL; } // // STI_DEVSTATUS_EVENTS_STATE: // else if (pDevStatus->StatusMask & STI_DEVSTATUS_EVENTS_STATE) { // // Polled events are not supported so we don't have to return anyting here: // pDevStatus->dwEventHandlingState &= ~STI_EVENTHANDLING_PENDING; } } if (FAILED(hr)) { m_hrLastEdviceError = hr; } WIAS_TRACE((g_hInst, "IStiUSD::GetStatus 0x%08X", hr)); return hr; }
HRESULT CWiaDriver::Initialize( _In_ PSTIDEVICECONTROL pIStiDevControl, DWORD dwStiVersion, _In_ HKEY hParametersKey) { UNREFERENCED_PARAMETER(dwStiVersion); HRESULT hr = S_OK; DWORD cchDevicePath = sizeof(m_wszDevicePath) / sizeof(WCHAR); WIAEX_TRACE_BEGIN; // // Validate parameters: // if ((!pIStiDevControl) || (!hParametersKey)) { hr = E_INVALIDARG; WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); } // // Get the device path name from PnP: // if (SUCCEEDED(hr)) { memset(m_wszDevicePath, 0, sizeof(m_wszDevicePath)); hr = pIStiDevControl->GetMyDevicePortName(m_wszDevicePath, cchDevicePath); if(FAILED(hr)) { WIAEX_ERROR((g_hInst, "IStiDeviceControl::GetMyDevicePortName failed, hr = 0x%08X", hr)); } } // // Initialize the connection with the scanner: // if (SUCCEEDED(hr)) { m_hDeviceKey = hParametersKey; hr = InitializeDeviceConnection(m_wszDevicePath, m_hDeviceKey); if (FAILED(hr)) { WIAEX_ERROR((g_hInst, "InitializeDeviceConnection for DevicePath %ws failed, hr = 0x%08X", m_wszDevicePath, hr)); } } if (SUCCEEDED(hr)) { m_hrLastEdviceError = STI_ERROR_NO_ERROR; m_bInitialized = TRUE; } else { m_hrLastEdviceError = hr; m_bInitialized = FALSE; } WIAEX_TRACE((g_hInst, "IStiUSD::Initialize 0x%08X", hr)); return hr; }
HRESULT CreateWIAChildItem( _In_ LPOLESTR pszItemName, _In_ IWiaMiniDrv *pIWiaMiniDrv, _In_ IWiaDrvItem *pParent, LONG lItemFlags, GUID guidItemCategory, _Inout_opt_ IWiaDrvItem **ppChild) { UNREFERENCED_PARAMETER(guidItemCategory); HRESULT hr = E_INVALIDARG; if (pszItemName && pIWiaMiniDrv && pParent) { BSTR bstrItemName = SysAllocString(pszItemName); BSTR bstrFullItemName = NULL; IWiaDrvItem *pIWiaDrvItem = NULL; if (bstrItemName) { hr = MakeFullItemName(pParent, bstrItemName, &bstrFullItemName); if (SUCCEEDED(hr)) { WIA_DRIVER_ITEM_CONTEXT *pWiaDriverItemContext = NULL; hr = wiasCreateDrvItem(lItemFlags, bstrItemName, bstrFullItemName, pIWiaMiniDrv, sizeof(WIA_DRIVER_ITEM_CONTEXT), (BYTE **)&pWiaDriverItemContext, &pIWiaDrvItem); if (SUCCEEDED(hr)) { // // Initialize the item context data: // memset(pWiaDriverItemContext, 0, sizeof(WIA_DRIVER_ITEM_CONTEXT)); pWiaDriverItemContext->m_pUploadedImage = NULL; hr = pIWiaDrvItem->AddItemToFolder(pParent); if (FAILED(hr)) { WIAEX_ERROR((g_hInst, "Failed to add the new WIA item (%ws) to the specified parent item, hr = 0x%08X", bstrFullItemName, hr)); pIWiaDrvItem->Release(); pIWiaDrvItem = NULL; } if (SUCCEEDED(hr)) { // // If a child iterface pointer parameter was specified, then the caller // expects to have the newly created child interface pointer returned to // them (do not release the newly created item in this case). // if (ppChild) { *ppChild = pIWiaDrvItem; pIWiaDrvItem = NULL; } else if (pIWiaDrvItem) { // // The newly created child has been added to the tree, and is no longer // needed. Release it. // pIWiaDrvItem->Release(); pIWiaDrvItem = NULL; } } } else { WIAEX_ERROR((g_hInst, "Failed to create the new WIA driver item, hr = 0x%08X", hr)); } SysFreeString(bstrItemName); bstrItemName = NULL; SysFreeString(bstrFullItemName); bstrFullItemName = NULL; } else { WIAEX_ERROR((g_hInst, "Failed to create the new WIA item's full item name, hr = 0x%08X", hr)); } } else { // // Failed to allocate memory for bstrItemName. // hr = E_OUTOFMEMORY; WIAEX_ERROR((g_hInst, "Failed to allocate memory for BSTR storage item name")); } } else { WIAEX_ERROR((g_hInst, "Invalid parameter")); } return hr; }