Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1773 lines
43 KiB

/*++
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;
}