Monday, July 25, 2011

Controlling a digital camera with Delphi (part 3). How to shoot a picture

The following Delphi code can be used to shoot a picture. The camera must support the command, otherwise nothing happens. Note that the code needs better error checking but it should work.

procedure TMainForm.ShootPicture;
var
aPortableDevManager: IPortableDeviceManager;
deviceIDs: TArrayPWideChar;
countDeviceIDs: Cardinal;
res: HResult;
aPortableDevice: IPortableDevice;
aPortableDevValues: IPortableDeviceValues;
key: _tagpropertykey;
aCmdPortableDevValues, aCmdPortableDevValuesResult: IPortableDeviceValues;
aCmdGUID: TGUID;
begin
//for info see: http://msdn.microsoft.com/en-us/library/dd319331%28v=VS.85%29.aspx
aPortableDevManager := CoPortableDeviceManager.Create;
if VarIsClear(aPortableDevManager) then exit;
//get number of devices
countDeviceIDs := 0;
res := aPortableDevManager.GetDevices(nil, countDeviceIDs);
if (res < 0) or (countDeviceIDs = 0) then exit; //failed
//get all devices:
setLength(deviceIDs, countDeviceIDs);
res := aPortableDevManager.GetDevices(@deviceIDs[0], countDeviceIDs);
if res < 0 then exit; //failed
//get properties of the first device:
//create device:
aPortableDevice := CoPortableDevice.Create;
if VarIsClear(aPortableDevice) then exit;
//create device values:
aPortableDevValues := CreateComObject(CLASS_PortableDeviceValues) as IPortableDeviceValues;
if VarIsClear(aPortableDevValues) then exit;
//open the device (assume the camera is the first device):
res := aPortableDevice.Open(deviceIDs[0], aPortableDevValues);
if res < 0 then exit; //failed
//Note: when FAILED, we should Release the interfaces. (not implemented yet)
//shoot a picture:
//assume the camera supports this command, otherwise nothing happens.
//create device values:
aCmdPortableDevValues := CreateComObject(CLASS_PortableDeviceValues) as IPortableDeviceValues;
if VarIsClear(aCmdPortableDevValues) then exit;

key.fmtid := WPD_CATEGORY_COMMON;
key.pid := WPD_PROPERTY_COMMON_COMMAND_CATEGORY;
aCmdGUID := WPD_CATEGORY_STILL_IMAGE_CAPTURE;
res := aCmdPortableDevValues.SetGuidValue(key, aCmdGUID);
if res < 0 then exit; //failed

key.fmtid := WPD_CATEGORY_COMMON;
key.pid := WPD_PROPERTY_COMMON_COMMAND_ID;
res := aCmdPortableDevValues.SetUnsignedIntegerValue(key, WPD_COMMAND_STILL_IMAGE_CAPTURE_INITIATE);
if res < 0 then exit; //failed

//Shoot:
res := aPortableDevice.SendCommand(0, aCmdPortableDevValues, aCmdPortableDevValuesResult);
if res < 0 then exit; //failed
//I do not care about result:
aCmdPortableDevValuesResult := nil;
aCmdPortableDevValues := nil;
end;