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
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;
|
|
}
|
|
|