|
|
/*++
Copyright (C) 1999- Microsoft Corporation
Module Name:
camera.cpp
Abstract:
This module implements the CPTPCamera class, which is a generic implementation of a PTP camera. Transport-specific processing is implemented in a sub-class.
Author:
William Hsieh (williamh) created
Revision History:
--*/
#include "ptppch.h"
//
// This thread reads event data from the device and sends it back to the minidriver
//
// Input:
// pParam -- pointer to the CPTPCamera subclassed object which can read the data
// Output:
// Thread exit code
//
DWORD WINAPI EventThread( LPVOID pParam ) { DBG_FN("EventThread"); HRESULT hr = S_OK; CPTPCamera *pDevice;
wiauDbgTrace("EventThread", "starting");
pDevice = (CPTPCamera *)pParam; if (!pDevice) { wiauDbgError("EventThread", "invalid arg"); return ERROR_INVALID_PARAMETER; }
DWORD Win32Err;
//
// Call the callback once with a NULL pointer so that it can initialize itself
//
hr = (pDevice->GetPTPEventCallback())(pDevice->GetEventCallbackParam(), NULL); if (FAILED(hr)) { //
// Log an error, but keep on catching events
//
wiauDbgError("EventThread", "event callback failed"); }
//
// Read an event from the device. If an error occurs, log an error message and then
// continue, unless the operation was aborted by the main thread.
//
PPTP_EVENT pEventBuffer = pDevice->GetEventBuffer(); while (TRUE) { ZeroMemory(pEventBuffer, sizeof(*pEventBuffer)); hr = pDevice->ReadEvent(pEventBuffer); if (FAILED(hr)) { wiauDbgError("EventThread", "ReadEvent failed"); break;; }
if (hr == S_FALSE) { wiauDbgTrace("EventThread", "ReadEvent cancelled"); break; }
if (g_dwDebugFlags & WIAUDBG_DUMP) { DumpEvent(pEventBuffer); } //
// Send the event back to the minidriver via its callback function
//
hr = (pDevice->GetPTPEventCallback())(pDevice->GetEventCallbackParam(), pEventBuffer); if (FAILED(hr)) { wiauDbgError("EventThread", "event callback failed"); } }
//
// The thread will now exit normally
//
wiauDbgTrace("EventThread", "exiting"); return 0; }
//
// Constructor for CPTPCamera
//
CPTPCamera::CPTPCamera() : m_hEventThread(NULL), m_SessionId(0), m_Phase(CAMERA_PHASE_NOTREADY), m_NextTransactionId(PTP_TRANSACTIONID_MIN), m_pTransferBuffer(NULL), m_pPTPEventCB(NULL), m_pPTPDataCB(NULL), m_pEventCallbackParam(NULL), m_pDataCallbackParam(NULL), m_bCameraWasReset(FALSE), m_HackModel(HACK_MODEL_NONE), m_HackVersion(0.0) { //PP_INIT_TRACING(L"Microsoft\\WIA\\PtpUsb");
}
//
// Destructor for CPTPCamera
//
CPTPCamera::~CPTPCamera() { if (m_pTransferBuffer) { delete [] m_pTransferBuffer; m_pTransferBuffer = NULL; }
//PP_CLEANUP();
}
//
// This function is the first one called by the driver to open access to the camera. The
// subclass Open should call this function first.
//
// Input:
// DevicePortName -- name used by sub-class to access device
// pPTPEventCB -- pointer to event callback function
//
HRESULT CPTPCamera::Open( LPWSTR DevicePortName, PTPEventCallback pPTPEventCB, PTPDataCallback pPTPDataCB, LPVOID pEventParam, BOOL bEnableEvents ) { DBG_FN("CPTPCamera::Open");
HRESULT hr = S_OK; if (!DevicePortName || ((bEnableEvents == TRUE) && (!pPTPEventCB))) { wiauDbgError("Open", "invalid arg"); return E_INVALIDARG; }
m_bEventsEnabled = bEnableEvents;
//
// Allocate the re-usable transfer buffer
//
m_pTransferBuffer = new BYTE[TRANSFER_BUFFER_SIZE]; if (!m_pTransferBuffer) { wiauDbgError("Open", "memory allocation failed"); return E_OUTOFMEMORY; }
//
// Save the callback pointers and object
//
m_pPTPEventCB = pPTPEventCB; m_pPTPDataCB = pPTPDataCB; m_pEventCallbackParam = pEventParam; m_pDataCallbackParam = NULL; //
// The camera isn't actually ready yet, but this is the best place to set the phase to idle
//
m_Phase = CAMERA_PHASE_IDLE;
if (m_bEventsEnabled) { //
// Create a thread to listen for events
//
DWORD ThreadId; m_hEventThread = CreateThread(NULL, // security descriptor
0, // stack size, use same size as this thread
EventThread, // thread procedure
this, // parameter to the thread
CREATE_SUSPENDED, // creation flags
&ThreadId // to receive thread id
); if (!m_hEventThread) { hr = HRESULT_FROM_WIN32(::GetLastError()); wiauDbgErrorHr(hr, "Open", "CreateThread failed"); return hr; } }
//
// The subclass should now open the device with CreateFile or equivalent
//
return hr; }
//
// This function closes the connection to the camera.
//
HRESULT CPTPCamera::Close() { DBG_FN("CPTPCamera::Close");
HRESULT hr = S_OK;
if (IsCameraSessionOpen()) { hr = CloseSession(); if (FAILED(hr)) { wiauDbgError("Close", "CloseSession failed"); return hr; } }
return hr; }
//
// This function is responsible for executing a PTP command, reading or
// writing any necessary data, and reading the response
//
// Input/Output:
// pData -- pointer to use for optional reading or writing of data
//
HRESULT CPTPCamera::ExecuteCommand( BYTE *pReadData, UINT *pReadDataSize, BYTE *pWriteData, UINT WriteDataSize, UINT NumCommandParams, CAMERA_PHASE NextPhase ) { DBG_FN("CPTPCamera::ExecuteCommand");
HRESULT hr = S_OK;
BOOL bCommandCancelled = FALSE;
//
// If data is being tranferred, check the appropriate buffer pointer
//
if ((NextPhase == CAMERA_PHASE_DATAIN && (!pReadData || !pReadDataSize)) || (NextPhase == CAMERA_PHASE_DATAOUT && !pWriteData)) { wiauDbgError("ExecuteCommand", "invalid arg"); return E_INVALIDARG; }
//
// Verify NumCommandParams is not too big
//
if (NumCommandParams > COMMAND_NUMPARAMS_MAX) { wiauDbgError("ExecuteCommand", "Too many command params"); return E_INVALIDARG; }
//
// Verify that the camera is ready
//
if (m_Phase != CAMERA_PHASE_IDLE) { wiauDbgError("ExecuteCommand", "camera is not in idle phase, phase = %d", m_Phase); return E_FAIL; }
//
// Set the session and transaction IDs
//
if (IsCameraSessionOpen()) { m_CommandBuffer.SessionId = m_SessionId; m_CommandBuffer.TransactionId = GetNextTransactionId(); } else { if (m_CommandBuffer.OpCode == PTP_OPCODE_GETDEVICEINFO || m_CommandBuffer.OpCode == PTP_OPCODE_OPENSESSION) { m_CommandBuffer.SessionId = PTP_SESSIONID_NOSESSION; m_CommandBuffer.TransactionId = PTP_TRANSACTIONID_NOSESSION; } else { wiauDbgError("ExecuteCommand", "session must first be opened"); return E_FAIL; } }
if (g_dwDebugFlags & WIAUDBG_DUMP) DumpCommand(&m_CommandBuffer, NumCommandParams);
//
// Send the command to the camera
//
m_Phase = CAMERA_PHASE_CMD; hr = SendCommand(&m_CommandBuffer, NumCommandParams); if (FAILED(hr)) { wiauDbgError("ExecuteCommand", "SendCommand failed"); m_Phase = CAMERA_PHASE_IDLE;
RecoverFromError(); return hr; } m_Phase = NextPhase;
//
// Get data, if necessary
//
if (m_Phase == CAMERA_PHASE_DATAIN) { hr = ReadData(pReadData, pReadDataSize); if (FAILED(hr)) { m_Phase = CAMERA_PHASE_IDLE; wiauDbgError("ExecuteCommand", "ReadData failed"); RecoverFromError(); return hr; }
if (hr == S_FALSE) { bCommandCancelled = TRUE; } else { //
// If transfer was cancelled, ReadData has already set appropriate next phase
// If not, set it to CAMERA_PHASE_RESPONSE now
//
m_Phase = CAMERA_PHASE_RESPONSE; } } else { // there is no data phase, tell caller there is no in data
// (please, note that caller knows and will adjust for
// obligatory response size) #337129
if(pReadDataSize) *pReadDataSize = 0; }
//
// Send data, if necessary
//
if (m_Phase == CAMERA_PHASE_DATAOUT) { hr = SendData(pWriteData, WriteDataSize); if (FAILED(hr)) { wiauDbgError("ExecuteCommand", "SendData failed"); m_Phase = CAMERA_PHASE_IDLE;
RecoverFromError(); return hr; }
if (hr == S_FALSE) { bCommandCancelled = TRUE; } else { //
// If transfer was cancelled, SendData has already set appropriate next phase
// If not, set it to CAMERA_PHASE_RESPONSE now
//
m_Phase = CAMERA_PHASE_RESPONSE; } }
//
// Read the response, if necessary
//
if (m_Phase == CAMERA_PHASE_RESPONSE) { memset(&m_ResponseBuffer, NULL, sizeof(m_ResponseBuffer));
hr = ReadResponse(&m_ResponseBuffer); if (FAILED(hr)) { wiauDbgError("ExecuteCommand", "ReadResponse failed"); m_Phase = CAMERA_PHASE_IDLE;
RecoverFromError(); return hr; }
if (g_dwDebugFlags & WIAUDBG_DUMP) DumpResponse(&m_ResponseBuffer);
if (m_ResponseBuffer.ResponseCode != PTP_RESPONSECODE_OK && m_ResponseBuffer.ResponseCode != PTP_RESPONSECODE_SESSIONALREADYOPENED) { wiauDbgError("ExecuteCommand", "bad response code = 0x%04x", m_ResponseBuffer.ResponseCode); //
// Convert the PTP response code to an HRESULT;
//
hr = HRESULT_FROM_PTP(m_ResponseBuffer.ResponseCode); }
m_Phase = CAMERA_PHASE_IDLE; }
if (SUCCEEDED(hr) && bCommandCancelled) { hr = S_FALSE; }
return hr; }
//
// All of the "command" functions below have the same basic structure:
// 1. Check the arguments (if any) to make sure they are valid
// 2. Set up the opcode and parameters (if any) in the command buffer
// 3. Call ExecuteCommand
// 4. Check the return code
// 5. Parse the returned raw data (if any) into a PTP structure
// 6. If debugging is turned on, dump the data
// 7. Return
//
//
// This function gets the device info structure from the camera
//
// Output:
// pDeviceInfo -- to receive the structure
//
HRESULT CPTPCamera::GetDeviceInfo( CPtpDeviceInfo *pDeviceInfo ) { DBG_FN("CPTPCamera::GetDeviceInfo");
HRESULT hr = S_OK; if (!pDeviceInfo) { wiauDbgError("GetDeviceInfo", "invalid arg"); return E_INVALIDARG; }
m_CommandBuffer.OpCode = PTP_OPCODE_GETDEVICEINFO;
UINT size = TRANSFER_BUFFER_SIZE; hr = ExecuteCommand(m_pTransferBuffer, &size, NULL, 0, 0, CAMERA_PHASE_DATAIN); if (FAILED(hr)) { wiauDbgError("GetDeviceInfo", "ExecuteCommand failed"); return hr; }
hr = pDeviceInfo->Init(m_pTransferBuffer); if (FAILED(hr)) { wiauDbgError("GetDeviceInfo", "couldn't parse DeviceInfo data"); return hr; }
if (g_dwDebugFlags & WIAUDBG_DUMP) pDeviceInfo->Dump();
//
// Set the model and version hack variables
//
SetupHackInfo(pDeviceInfo);
return hr; }
//
// This function opens a session on the camera for the caller. It is a little different
// than the other command functions. If it initially fails, it tries to recover and
// execute the OpenSession command again. It also starts the event thread.
//
// Input:
// SessionId -- the session ID to open
//
HRESULT CPTPCamera::OpenSession( DWORD SessionId ) { DBG_FN("CPTPCamera::OpenSession");
HRESULT hr = S_OK; if (!SessionId) { wiauDbgError("OpenSession", "invalid arg"); return E_INVALIDARG; }
if (IsCameraSessionOpen()) { wiauDbgError("OpenSession", "tried to open a session when one is already open"); return E_FAIL; }
m_CommandBuffer.OpCode = PTP_OPCODE_OPENSESSION; m_CommandBuffer.Params[0] = SessionId;
hr = ExecuteCommand(NULL, NULL, NULL, 0, 1, CAMERA_PHASE_RESPONSE); if (FAILED(hr)) { wiauDbgError("OpenSession", "ExecuteCommand failed... attempting to recover and re-execute"); hr = RecoverFromError(); if (FAILED(hr)) { wiauDbgError("OpenSession", "RecoverFromError failed"); return hr; }
//
// Trying executing the command again
//
hr = ExecuteCommand(NULL, NULL, NULL, 0, 1, CAMERA_PHASE_RESPONSE); if (FAILED(hr)) { wiauDbgError("OpenSession", "ExecuteCommand failed the second time"); return hr; } }
//
// Set the session id
//
m_SessionId = SessionId;
wiauDbgTrace("OpenSession", "session %d opened", m_SessionId);
//
// Resume the event thread that was created suspended
//
if (!m_hEventThread) { wiauDbgError("OpenSession", "event thread is null"); return E_FAIL; }
if (ResumeThread(m_hEventThread) > 1) { wiauDbgError("OpenSession", "ResumeThread failed"); return E_FAIL; }
return hr; }
//
// This function closes the session
//
HRESULT CPTPCamera::CloseSession() { DBG_FN("CPTPCamera::CloseSession");
HRESULT hr = S_OK; m_CommandBuffer.OpCode = PTP_OPCODE_CLOSESESSION;
hr = ExecuteCommand(NULL, NULL, NULL, 0, 0, CAMERA_PHASE_RESPONSE); if (FAILED(hr)) { wiauDbgError("CloseSession", "ExecuteCommand failed"); return hr; }
wiauDbgTrace("CloseSession", "session closed");
//
// The session is closed, so reset the session and transaction ids
//
m_SessionId = PTP_SESSIONID_NOSESSION; m_NextTransactionId = PTP_TRANSACTIONID_MIN; m_Phase = CAMERA_PHASE_NOTREADY;
return hr; }
//
// This function retrieves the list of all available storages on the device
//
// Output:
// pStorageIdArray -- An empty array to receive the storage IDs
//
HRESULT CPTPCamera::GetStorageIDs( CArray32 *pStorageIdArray ) { DBG_FN("CPTPCamera::GetStorageIDs");
HRESULT hr = S_OK;
if (!pStorageIdArray) { wiauDbgError("GetStorageIDs", "invalid arg"); return E_INVALIDARG; }
m_CommandBuffer.OpCode = PTP_OPCODE_GETSTORAGEIDS;
UINT size = TRANSFER_BUFFER_SIZE; hr = ExecuteCommand(m_pTransferBuffer, &size, NULL, 0, 0, CAMERA_PHASE_DATAIN); if (FAILED(hr)) { wiauDbgError("GetStorageIDs", "ExecuteCommand failed"); return hr; }
BYTE *pTemp = m_pTransferBuffer; if (!pStorageIdArray->Parse(&pTemp)) { wiauDbgError("GetStorageIDs", "couldn't parse storage id array"); return hr; }
if (g_dwDebugFlags & WIAUDBG_DUMP) pStorageIdArray->Dump(" Storage ids =", " ");
return hr; }
//
// This function gets the information about the given storage
//
// Input:
// StorageId -- the storage ID to get info about
// Output:
// pStorageInfo -- the structure to receive the information
//
HRESULT CPTPCamera::GetStorageInfo( DWORD StorageId, CPtpStorageInfo *pStorageInfo ) { DBG_FN("CPTPCamera::GetStorageInfo");
HRESULT hr = S_OK;
if (!StorageId || !pStorageInfo) { wiauDbgError("GetStorageInfo", "invalid arg"); return E_INVALIDARG; } m_CommandBuffer.OpCode = PTP_OPCODE_GETSTORAGEINFO; m_CommandBuffer.Params[0] = StorageId;
UINT size = TRANSFER_BUFFER_SIZE; hr = ExecuteCommand(m_pTransferBuffer, &size, NULL, 0, 1, CAMERA_PHASE_DATAIN); if (FAILED(hr)) { wiauDbgError("GetStorageInfo", "ExecuteCommand failed"); return hr; }
hr = pStorageInfo->Init(m_pTransferBuffer, StorageId); if (FAILED(hr)) { wiauDbgError("GetStorageInfo", "couldn't parse storage info"); return hr; }
if (g_dwDebugFlags & WIAUDBG_DUMP) pStorageInfo->Dump();
return hr; }
//
// This function gets the number of objects on a storage, optionally in a specific
// format or under a specific association object
//
// Input:
// StorageId -- the designated storage, e.g. PTP_STORAGEID_ALL
// FormatCode -- optional format type, e.g. PTP_FORMATCODE_ALL, PTP_FORMATCODE_IMAGE
// ParentObjectHandle -- the object handle under which to count objects
// Output:
// pNumObjects -- to receive the number of the object.
//
HRESULT CPTPCamera::GetNumObjects( DWORD StorageId, WORD FormatCode, DWORD ParentObjectHandle, UINT *pNumObjects ) { DBG_FN("CPTPCamera::GetNumObjects");
HRESULT hr = S_OK; if (!StorageId || !pNumObjects) { wiauDbgError("GetNumObjects", "invalid arg"); return E_INVALIDARG; }
m_CommandBuffer.OpCode = PTP_OPCODE_GETNUMOBJECTS; m_CommandBuffer.Params[0] = StorageId; m_CommandBuffer.Params[1] = FormatCode; m_CommandBuffer.Params[2] = ParentObjectHandle;
hr = ExecuteCommand(NULL, NULL, NULL, 0, 3, CAMERA_PHASE_RESPONSE); if (FAILED(hr)) { wiauDbgError("GetNumObjects", "ExecuteCommand failed"); return hr; }
*pNumObjects = m_ResponseBuffer.Params[0];
wiauDbgTrace("GetNumObjects", "number of objects = %d", *pNumObjects);
return hr; }
//
// This function gets the object handles under the given parent object
//
// Input:
// StorageId -- the designated storage, e.g. PTP_STORAGEID_ALL
// FormatCode -- specifies what format type, e.g. PTP_FORMATCODE_ALL, PTP_FORMATCODE_IMAGE
// ParentObjectHandle -- the object handle under which to enumerate the objects
// Output:
// pObjectHandleArray -- the array to receive the object handles
//
HRESULT CPTPCamera::GetObjectHandles( DWORD StorageId, WORD FormatCode, DWORD ParentObjectHandle, CArray32 *pObjectHandleArray ) { DBG_FN("CPTPCamera::GetObjectHandles");
HRESULT hr = S_OK;
if (!StorageId || !pObjectHandleArray) { wiauDbgError("GetObjectHandles", "invalid arg"); return E_INVALIDARG; } m_CommandBuffer.OpCode = PTP_OPCODE_GETOBJECTHANDLES; m_CommandBuffer.Params[0] = StorageId; m_CommandBuffer.Params[1] = FormatCode; m_CommandBuffer.Params[2] = ParentObjectHandle;
UINT size = TRANSFER_BUFFER_SIZE; hr = ExecuteCommand(m_pTransferBuffer, &size, NULL, 0, 3, CAMERA_PHASE_DATAIN); if (FAILED(hr)) { wiauDbgError("GetObjectHandles", "ExecuteCommand failed"); return hr; }
BYTE *pTemp = m_pTransferBuffer; if (!pObjectHandleArray->Parse(&pTemp)) { wiauDbgError("GetStorageIDs", "couldn't parse object handle array"); return hr; }
if (g_dwDebugFlags & WIAUDBG_DUMP) pObjectHandleArray->Dump(" Object handles =", " ");
return hr; }
//
// This function gets the object info structure
//
// Input:
// ObjectHandle -- the object handle
// Output:
// pObjectInfo -- pointer to retreived object info
//
HRESULT CPTPCamera::GetObjectInfo( DWORD ObjectHandle, CPtpObjectInfo *pObjectInfo ) { DBG_FN("CPTPCamera::GetObjectInfo");
HRESULT hr = S_OK;
if (!ObjectHandle || !pObjectInfo) { wiauDbgError("GetObjectInfo", "invalid arg"); return E_INVALIDARG; } m_CommandBuffer.OpCode = PTP_OPCODE_GETOBJECTINFO; m_CommandBuffer.Params[0] = ObjectHandle;
UINT size = TRANSFER_BUFFER_SIZE; hr = ExecuteCommand(m_pTransferBuffer, &size, NULL, 0, 1, CAMERA_PHASE_DATAIN); if (FAILED(hr)) { wiauDbgError("GetObjectInfo", "ExecuteCommand failed"); return hr; } hr = pObjectInfo->Init(m_pTransferBuffer, ObjectHandle); if (FAILED(hr)) { wiauDbgError("GetObjectInfo", "couldn't parse object info"); return hr; }
if (g_dwDebugFlags & WIAUDBG_DUMP) pObjectInfo->Dump();
return hr; }
//
// This function retrieves an object
//
// Input:
// ObjectHandle -- the handle that represents the object
// pBuffer -- the buffer to use for transfer
// BufferLen -- the buffer size
//
HRESULT CPTPCamera::GetObjectData( DWORD ObjectHandle, BYTE *pBuffer, UINT *pBufferLen, LPVOID pCallbackParam ) { DBG_FN("CPTPCamera::GetObjectData"); HRESULT hr = S_OK;
if (!pBuffer || !pBufferLen || *pBufferLen == 0) { wiauDbgError("GetObjectData", "invalid arg"); return E_INVALIDARG; }
m_CommandBuffer.OpCode = PTP_OPCODE_GETOBJECT; m_CommandBuffer.Params[0] = ObjectHandle;
m_pDataCallbackParam = pCallbackParam;
hr = ExecuteCommand(pBuffer, pBufferLen, NULL, 0, 1, CAMERA_PHASE_DATAIN); if (FAILED(hr)) { wiauDbgError("GetObjectData", "ExecuteCommand failed"); //
// go ahead to have m_pDataCallbackParam cleared
//
}
m_pDataCallbackParam = NULL; return hr; }
//
// This function gets the thumbnail for an object
//
// Input:
// ObjectHandle -- the handle that represents the object
// pBuffer -- the buffer to use for transfer
// BufferLen -- the buffer size
//
HRESULT CPTPCamera::GetThumb( DWORD ObjectHandle, BYTE *pBuffer, UINT *pBufferLen ) { DBG_FN("CPTPCamera::GetThumb"); HRESULT hr = S_OK;
if (!pBuffer || !pBufferLen || *pBufferLen == 0) { wiauDbgError("GetThumb", "invalid arg"); return E_INVALIDARG; }
m_CommandBuffer.OpCode = PTP_OPCODE_GETTHUMB; m_CommandBuffer.Params[0] = ObjectHandle;
hr = ExecuteCommand(pBuffer, pBufferLen, NULL, 0, 1, CAMERA_PHASE_DATAIN); if (FAILED(hr)) { wiauDbgError("GetThumb", "ExecuteCommand failed"); return hr; } return hr; }
//
// This function deletes the given object and its children
//
// Input:
// ObjectHandle -- object handle that represents the object to be deleted, e.g. PTP_OBJECTHANDLE_ALL
// FormatCode -- Limits the scope of the deletion if objects of FormatCode type, e.g. PTP_FORMATCODE_NOTUSED, PTP_FORMATCODE_ALLIMAGES
//
HRESULT CPTPCamera::DeleteObject( DWORD ObjectHandle, WORD FormatCode ) { DBG_FN("CPTPCamera::DeleteObject"); HRESULT hr = S_OK;
m_CommandBuffer.OpCode = PTP_OPCODE_DELETEOBJECT; m_CommandBuffer.Params[0] = ObjectHandle; m_CommandBuffer.Params[1] = FormatCode;
hr = ExecuteCommand(NULL, NULL, NULL, 0, 2, CAMERA_PHASE_RESPONSE); if (FAILED(hr)) { wiauDbgError("DeleteObject", "ExecuteCommand failed"); return hr; } return hr; }
//
// This function sends an ObjectInfo structure to the device in preparation for sending an object
//
// Input:
// StorageId -- storage id for the new object, e.g. PTP_STORAGEID_UNDEFINED
// ParentObjectHandle -- parent to use for the new object, e.g. PTP_OBJECTHANDLE_UNDEFINED, PTP_OBJECTHANDLE_ROOT
// pDeviceInfo -- pointer to DeviceInfo structure
// Output:
// pResultStorageId -- location to store storage id where object will be stored
// pResultParentObjectHandle -- parent object under which object will be stored
// pResultObjectHandle -- location to store handle for the new object
//
HRESULT CPTPCamera::SendObjectInfo( DWORD StorageId, DWORD ParentObjectHandle, CPtpObjectInfo *pObjectInfo, DWORD *pResultStorageId, DWORD *pResultParentObjectHandle, DWORD *pResultObjectHandle ) { DBG_FN("CPTPCamera::SendObjectInfo"); HRESULT hr = S_OK;
if (!pObjectInfo || !pResultStorageId || !pResultParentObjectHandle || !pResultObjectHandle) { wiauDbgError("SendObjectInfo", "invalid arg"); return E_INVALIDARG; }
m_CommandBuffer.OpCode = PTP_OPCODE_SENDOBJECTINFO; m_CommandBuffer.Params[0] = StorageId; m_CommandBuffer.Params[1] = ParentObjectHandle;
BYTE *pRaw = m_pTransferBuffer; pObjectInfo->WriteToBuffer(&pRaw); UINT size = (UINT) (pRaw - m_pTransferBuffer);
hr = ExecuteCommand(NULL, NULL, m_pTransferBuffer, size, 2, CAMERA_PHASE_DATAOUT); if (FAILED(hr)) { wiauDbgError("SendObjectInfo", "ExecuteCommand failed"); return hr; }
*pResultStorageId = m_ResponseBuffer.Params[0]; *pResultParentObjectHandle = m_ResponseBuffer.Params[1]; *pResultObjectHandle = m_ResponseBuffer.Params[2];
wiauDbgTrace("SendObjectInfo", "ObjectInfo added, storage = 0x%08x, parent = 0x%08x, handle = 0x%08x", *pResultStorageId, *pResultParentObjectHandle, *pResultObjectHandle); return hr; }
//
// This function sends data for a new object
//
// Input:
// pBuffer -- pointer to raw data
// BufferLen -- length of the buffer
//
HRESULT CPTPCamera::SendObjectData( BYTE *pBuffer, UINT BufferLen ) { DBG_FN("CPTPCamera::SendObjectData"); HRESULT hr = S_OK;
if (!pBuffer) { wiauDbgError("SendObjectData", "invalid arg"); return E_INVALIDARG; }
m_CommandBuffer.OpCode = PTP_OPCODE_SENDOBJECT;
hr = ExecuteCommand(NULL, NULL, pBuffer, BufferLen, 0, CAMERA_PHASE_DATAOUT); if (FAILED(hr)) { wiauDbgError("SendObjectData", "ExecuteCommand failed"); return hr; }
return hr; }
//
// This function asks the device to initiate a capture. The newly added object
// will be reported via an ObjectAdded event, or StoreFull event if the store is full.
//
// Input:
// StorageId -- where to save the capture object, e.g. PTP_STORAGEID_DEFAULT
// FormatCode -- indicates what kind of object to capture, e.g. PTP_FORMATCODE_DEFAULT
//
HRESULT CPTPCamera::InitiateCapture( DWORD StorageId, WORD FormatCode ) { DBG_FN("CPTPCamera::InitiateCapture"); HRESULT hr = S_OK;
m_CommandBuffer.OpCode = PTP_OPCODE_INITIATECAPTURE; m_CommandBuffer.Params[0] = StorageId; m_CommandBuffer.Params[1] = FormatCode;
hr = ExecuteCommand(NULL, NULL, NULL, 0, 2, CAMERA_PHASE_RESPONSE); if (FAILED(hr)) { wiauDbgError("InitiateCapture", "ExecuteCommand failed"); return hr; }
return hr; }
//
// This function formats a store on the device
//
// Input:
// StorageId -- storage to format
// FilesystemFormat -- optional format to use
//
HRESULT CPTPCamera::FormatStore( DWORD StorageId, WORD FilesystemFormat ) { DBG_FN("CPTPCamera::FormatStore"); HRESULT hr = S_OK;
m_CommandBuffer.OpCode = PTP_OPCODE_FORMATSTORE; m_CommandBuffer.Params[0] = StorageId; m_CommandBuffer.Params[1] = FilesystemFormat;
hr = ExecuteCommand(NULL, NULL, NULL, 0, 2, CAMERA_PHASE_RESPONSE); if (FAILED(hr)) { wiauDbgError("FormatStore", "ExecuteCommand failed"); return hr; }
return hr; }
//
// This function resets the camera. A DeviceReset event will be sent and all open
// sessions will be closed.
//
HRESULT CPTPCamera::ResetDevice() { DBG_FN("CPTPCamera::ResetDevice"); HRESULT hr = S_OK;
hr = SendResetDevice(); if (FAILED(hr)) { wiauDbgError("ResetDevice", "SendResetDevice failed"); return hr; }
wiauDbgTrace("ResetDevice", "device reset successfully");
return hr; }
//
// This function tests the camera
//
HRESULT CPTPCamera::SelfTest(WORD SelfTestType) { DBG_FN("CPTPCamera::SelfTest"); HRESULT hr = S_OK;
m_CommandBuffer.OpCode = PTP_OPCODE_SELFTEST; m_CommandBuffer.Params[0] = SelfTestType;
hr = ExecuteCommand(NULL, NULL, NULL, 0, 0, CAMERA_PHASE_RESPONSE); if (FAILED(hr)) { wiauDbgError("SelfTest", "ExecuteCommand failed"); return hr; } return hr; }
//
// This function sets the protection status of an object
//
// Input:
// ObjectHandle -- handle of the object
// ProtectionStatus -- protection status
//
HRESULT CPTPCamera::SetObjectProtection( DWORD ObjectHandle, WORD ProtectionStatus ) { DBG_FN("CPTPCamera::SetObjectProtection"); HRESULT hr = S_OK;
m_CommandBuffer.OpCode = PTP_OPCODE_SETOBJECTPROTECTION; m_CommandBuffer.Params[0] = ObjectHandle; m_CommandBuffer.Params[1] = ProtectionStatus;
hr = ExecuteCommand(NULL, NULL, NULL, 0, 2, CAMERA_PHASE_RESPONSE); if (FAILED(hr)) { wiauDbgError("SetObjectProtection", "ExecuteCommand failed"); return hr; }
return hr; }
//
// This function will cause the device to turn off
//
HRESULT CPTPCamera::PowerDown() { DBG_FN("CPTPCamera::PowerDown"); HRESULT hr = S_OK;
m_CommandBuffer.OpCode = PTP_OPCODE_POWERDOWN;
hr = ExecuteCommand(NULL, NULL, NULL, 0, 0, CAMERA_PHASE_RESPONSE); if (FAILED(hr)) { wiauDbgError("PowerDown", "ExecuteCommand failed"); return hr; } return hr; }
//
// This function retrieves a property description structure from the camera, allocating
// the appropriate CPtpPropDesc structure.
//
// Input:
// PropCode -- property code to retrieve
// pPropDesc -- pointer property description object
//
HRESULT CPTPCamera::GetDevicePropDesc( WORD PropCode, CPtpPropDesc *pPropDesc ) { DBG_FN("CPtpCamera::GetDevicePropDesc");
HRESULT hr = S_OK; if (!PropCode || !pPropDesc) { wiauDbgError("GetDevicePropDesc", "invalid arg"); return E_INVALIDARG; } m_CommandBuffer.OpCode = PTP_OPCODE_GETDEVICEPROPDESC; m_CommandBuffer.Params[0] = PropCode;
UINT size = TRANSFER_BUFFER_SIZE; hr = ExecuteCommand(m_pTransferBuffer, &size, NULL, 0, 1, CAMERA_PHASE_DATAIN); if (FAILED(hr)) { wiauDbgError("GetDevicePropDesc", "ExecuteCommand failed"); return hr; }
hr = pPropDesc->Init(m_pTransferBuffer); if (FAILED(hr)) { wiauDbgError("GetDevicePropDesc", "couldn't parse property description"); return hr; }
if (g_dwDebugFlags & WIAUDBG_DUMP) pPropDesc->Dump();
return hr; }
//
// This function retrieves the current setting for a property.
//
// Input:
// PropCode -- property code to get value for
// pPropDesc -- pointer to property description object
//
HRESULT CPTPCamera::GetDevicePropValue( WORD PropCode, CPtpPropDesc *pPropDesc ) { DBG_FN("CPtpCamera::GetDevicePropValue");
HRESULT hr = S_OK; if (!PropCode || !pPropDesc) { wiauDbgError("GetDevicePropValue", "invalid arg"); return E_INVALIDARG; } m_CommandBuffer.OpCode = PTP_OPCODE_GETDEVICEPROPVALUE; m_CommandBuffer.Params[0] = PropCode;
UINT size = TRANSFER_BUFFER_SIZE; hr = ExecuteCommand(m_pTransferBuffer, &size, NULL, 0, 1, CAMERA_PHASE_DATAIN); if (FAILED(hr)) { wiauDbgError("GetDevicePropValue", "ExecuteCommand failed"); return hr; }
hr = pPropDesc->ParseValue(m_pTransferBuffer); if (FAILED(hr)) { wiauDbgError("GetDevicePropValue", "couldn't parse property value"); return hr; }
if (g_dwDebugFlags & WIAUDBG_DUMP) pPropDesc->DumpValue();
return hr; }
//
// This function sends a new setting for a property to the device
//
// Input:
// PropCode -- property code to set
// pPropDesc -- pointer to property description object
//
HRESULT CPTPCamera::SetDevicePropValue( WORD PropCode, CPtpPropDesc *pPropDesc ) { DBG_FN("CPtpCamera::SetDevicePropValue");
HRESULT hr = S_OK; if (!PropCode || !pPropDesc) { wiauDbgError("SetDevicePropValue", "invalid arg"); return E_INVALIDARG; }
if (g_dwDebugFlags & WIAUDBG_DUMP) pPropDesc->DumpValue();
m_CommandBuffer.OpCode = PTP_OPCODE_SETDEVICEPROPVALUE; m_CommandBuffer.Params[0] = PropCode;
BYTE *pRaw = m_pTransferBuffer; pPropDesc->WriteValue(&pRaw); UINT size = (UINT) (pRaw - m_pTransferBuffer);
hr = ExecuteCommand(NULL, NULL, m_pTransferBuffer, size, 1, CAMERA_PHASE_DATAOUT); if (FAILED(hr)) { wiauDbgError("SetDevicePropValue", "ExecuteCommand failed"); return hr; }
return hr; }
//
// This function resets the of a property
//
// Input:
// PropCode -- property code to set
//
HRESULT CPTPCamera::ResetDevicePropValue( WORD PropCode ) { DBG_FN("CPtpCamera::ResetDevicePropValue");
HRESULT hr = S_OK; if (!PropCode) { wiauDbgError("ResetDevicePropValue", "invalid arg"); return E_INVALIDARG; } m_CommandBuffer.OpCode = PTP_OPCODE_RESETDEVICEPROPVALUE; m_CommandBuffer.Params[0] = PropCode;
hr = ExecuteCommand(NULL, NULL, NULL, 0, 1, CAMERA_PHASE_RESPONSE); if (FAILED(hr)) { wiauDbgError("ResetDevicePropValue", "ExecuteCommand failed"); return hr; }
//
// WIAFIX-10/2/2000-davepar This function should reset the current value being held by the minidriver
//
return hr; }
//
// This function terminates an open capture
//
// Input:
// TransactionId -- transaction id of InitiateOpenCapture command
//
HRESULT CPTPCamera::TerminateCapture( DWORD TransactionId ) { DBG_FN("CPtpCamera::TerminateCapture");
HRESULT hr = S_OK; if (!TransactionId) { wiauDbgError("TerminateCapture", "invalid arg"); return E_INVALIDARG; } m_CommandBuffer.OpCode = PTP_OPCODE_TERMINATECAPTURE; m_CommandBuffer.Params[0] = TransactionId;
hr = ExecuteCommand(NULL, NULL, NULL, 0, 1, CAMERA_PHASE_RESPONSE); if (FAILED(hr)) { wiauDbgError("TerminateCapture", "ExecuteCommand failed"); return hr; }
return hr; }
//
// This function moves an object on the device
//
// Input:
// ObjectHandle -- handle of object to move
// StorageId -- storage id of new location for object
// ParentObjectHandle -- handle of new parent for object
//
HRESULT CPTPCamera::MoveObject( DWORD ObjectHandle, DWORD StorageId, DWORD ParentObjectHandle ) { DBG_FN("CPtpCamera::MoveObject");
HRESULT hr = S_OK; if (!ObjectHandle) { wiauDbgError("MoveObject", "invalid arg"); return E_INVALIDARG; } m_CommandBuffer.OpCode = PTP_OPCODE_MOVEOBJECT; m_CommandBuffer.Params[0] = ObjectHandle; m_CommandBuffer.Params[1] = StorageId; m_CommandBuffer.Params[2] = ParentObjectHandle;
hr = ExecuteCommand(NULL, NULL, NULL, 0, 3, CAMERA_PHASE_RESPONSE); if (FAILED(hr)) { wiauDbgError("MoveObject", "ExecuteCommand failed"); return hr; }
return hr; }
//
// This function copies an object to a new location on the device
//
// Input:
// ObjectHandle -- handle of object to copy
// StorageId -- storage id for new object
// ParentObjectHandle -- handle of parent for new object
// pResultObjectHandle -- pointer to location to receive new object's handle
//
HRESULT CPTPCamera::CopyObject( DWORD ObjectHandle, DWORD StorageId, DWORD ParentObjectHandle, DWORD *pResultObjectHandle ) { DBG_FN("CPtpCamera::CopyObject");
HRESULT hr = S_OK; if (!ObjectHandle || !pResultObjectHandle) { wiauDbgError("CopyObject", "invalid arg"); return E_INVALIDARG; } m_CommandBuffer.OpCode = PTP_OPCODE_COPYOBJECT; m_CommandBuffer.Params[0] = ObjectHandle; m_CommandBuffer.Params[1] = StorageId; m_CommandBuffer.Params[2] = ParentObjectHandle;
hr = ExecuteCommand(NULL, NULL, NULL, 0, 3, CAMERA_PHASE_RESPONSE); if (FAILED(hr)) { wiauDbgError("CopyObject", "ExecuteCommand failed"); return hr; }
*pResultObjectHandle = m_ResponseBuffer.Params[0];
wiauDbgTrace("CopyObject", "Object 0x%08x copied to 0x%08x", ObjectHandle, *pResultObjectHandle);
return hr; }
//
// This function retrieves a portion of an object
//
// Input:
// ObjectHandle -- the handle that represents the object
// pBuffer -- the buffer to use for transfer
// BufferLen -- the buffer size
//
HRESULT CPTPCamera::GetPartialObject( DWORD ObjectHandle, UINT Offset, UINT *pLength, BYTE *pBuffer, UINT *pResultLength, LPVOID pCallbackParam ) { DBG_FN("CPTPCamera::GetPartialObject"); HRESULT hr = S_OK;
if (!pBuffer || !pLength || *pLength == 0 || !pResultLength) { wiauDbgError("GetPartialObject", "invalid arg"); return E_INVALIDARG; }
m_CommandBuffer.OpCode = PTP_OPCODE_GETPARTIALOBJECT; m_CommandBuffer.Params[0] = ObjectHandle; m_CommandBuffer.Params[1] = Offset; m_CommandBuffer.Params[2] = *pLength;
m_pDataCallbackParam = pCallbackParam;
hr = ExecuteCommand(pBuffer, pLength, NULL, 0, 3, CAMERA_PHASE_DATAIN); if (FAILED(hr)) { wiauDbgError("GetPartialObject", "ExecuteCommand failed"); m_pDataCallbackParam = NULL; return hr; }
m_pDataCallbackParam = NULL;
*pResultLength = m_ResponseBuffer.Params[0]; return hr; }
//
// This function initiates an open capture
//
// Input:
// StorageId -- storage to use for new object(s)
// FormatCode -- format for new object(s)
//
HRESULT CPTPCamera::InitiateOpenCapture( DWORD StorageId, WORD FormatCode ) { DBG_FN("CPtpCamera::InitiateOpenCapture");
HRESULT hr = S_OK; m_CommandBuffer.OpCode = PTP_OPCODE_INITIATEOPENCAPTURE; m_CommandBuffer.Params[0] = StorageId; m_CommandBuffer.Params[1] = FormatCode;
hr = ExecuteCommand(NULL, NULL, NULL, 0, 2, CAMERA_PHASE_RESPONSE); if (FAILED(hr)) { wiauDbgError("InitiateOpenCapture", "ExecuteCommand failed"); hr = RecoverFromError(); if(FAILED(hr)) { wiauDbgError("InitiateOpenCapture", "RecoverFromError failed"); return hr; }
hr = ExecuteCommand(NULL, NULL, NULL, 0, 2, CAMERA_PHASE_RESPONSE); if (FAILED(hr)) { wiauDbgError("InitiateOpenCapture", "ExecuteCommand failed 2nd time"); return hr; } }
return hr; }
//
// This function executes a vendor command
//
HRESULT CPTPCamera::VendorCommand( PTP_COMMAND *pCommand, PTP_RESPONSE *pResponse, UINT *pReadDataSize, BYTE *pReadData, UINT WriteDataSize, BYTE *pWriteData, UINT NumCommandParams, int NextPhase ) { DBG_FN("CPTPCamera::VendorCommand");
HRESULT hr = S_OK;
memcpy(&m_CommandBuffer, pCommand, sizeof(m_CommandBuffer));
hr = ExecuteCommand(pReadData, pReadDataSize, pWriteData, WriteDataSize, NumCommandParams, (CAMERA_PHASE) NextPhase); if (FAILED(hr)) { wiauDbgError("VendorCommand", "ExecuteCommand failed"); return hr; }
memcpy(pResponse, &m_ResponseBuffer, sizeof(m_ResponseBuffer));
return hr; }
//
// This function increments the transaction ID, rolling over if necessary
//
// Output:
// next transaction ID
//
DWORD CPTPCamera::GetNextTransactionId() { // Valid transaction IDs range from PTP_TRANSACTIONID_MIN to
// PTP_TRANSACTIONID_MAX, inclusive.
//
if (PTP_TRANSACTIONID_MAX == m_NextTransactionId) { m_NextTransactionId = PTP_TRANSACTIONID_MIN; return PTP_TRANSACTIONID_MAX; } else { return m_NextTransactionId++; } }
//
// Set m_HackModel and m_HackVersion according to device info
//
HRESULT CPTPCamera::SetupHackInfo(CPtpDeviceInfo *pDeviceInfo) { DBG_FN("CWiaMiniDriver::SetupHackInfo");
if (pDeviceInfo == NULL) { wiauDbgError("SetupHackInfo", "Invalid device info"); return E_INVALIDARG; }
HRESULT hr = S_OK; m_HackModel = HACK_MODEL_NONE; m_HackVersion = 0.0;
//
// Kodak DC4800
//
if (wcscmp(pDeviceInfo->m_cbstrModel.String(), L"DC4800 Zoom Digital Camera") == 0) { m_HackModel = HACK_MODEL_DC4800; wiauDbgTrace("SetupHackInfo", "Detected Kodak DC4800 camera"); }
//
// Any Sony camera
//
else if (wcsstr(pDeviceInfo->m_cbstrModel.String(), L"Sony") != NULL) { //
// Sony cameras report version as "01.0004"
//
WCHAR *pszStopChar = NULL; double dbVersion = wcstod(pDeviceInfo->m_cbstrDeviceVersion.String(), &pszStopChar); if (dbVersion != 0.0) { m_HackModel = HACK_MODEL_SONY; m_HackVersion = dbVersion; wiauDbgTrace("SetupHackInfo", "Detected Sony camera, version = %f", m_HackVersion); } }
//
// Nikon E2500
//
else if (wcsstr(pDeviceInfo->m_cbstrManufacturer.String(), L"Nikon") != NULL && wcscmp(pDeviceInfo->m_cbstrModel.String(), L"E2500") == 0) { //
// Nikon E2500 reports version as "E2500v1.0"
//
WCHAR *pch = wcsrchr(pDeviceInfo->m_cbstrDeviceVersion.String(), L'v'); if (pch != NULL) { WCHAR *pszStopChar = NULL; double dbVersion = wcstod(pch + 1, &pszStopChar); if (dbVersion != 0) { m_HackModel = HACK_MODEL_NIKON_E2500; m_HackVersion = dbVersion; wiauDbgTrace("SetupHackInfo", "Detected Nikon E2500 camera, version = %f", m_HackVersion); } } } else { wiauDbgTrace("SetupHackInfo", "Not detected any hack model"); }
return hr; }
|