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;

6 comments:

  1. Anonymous5:10 PM

    Hi Mate,

    Thanks for the latest update. Can you please tell me where the definition for the contants e.g. WPD_CATEGORY_COMMON come from.

    Thanks
    Rudy

    ReplyDelete
  2. Anonymous1:01 AM

    any idea how to copy files from the wpd devices (e.g. android phone) ?

    ReplyDelete
  3. Would love to hear more about your WPD development. This page is actually the foremost resource on WPD dev in Delphi.

    Thanks

    ReplyDelete
  4. Thanks to DEMETRIS. I knew how to control a digital camera with delphi. I will visit your blog for more updates.

    ReplyDelete
  5. Hi Demetris,
    I know this is a very old post but I am interested in finding out how you actually made this thing work.
    I've tried your code, it doesn't do anything with my different devices but I think it may simply be due to the WPD constants I'm using. The code to detect and list the connected devices is fine. But as soon as I start trying to actually DO something with the devices, nothing happens.
    The Microsoft documentation is horribly confusing on that point: are we supposed to pass _tagpropertykey records, or just their properties (fmtid, pid), and then in which parameter are those specified in the SendCommand method... pffffffffffff... do you still recall how you did it?

    ReplyDelete
  6. The code is crashed. The constants is not encoutered: WPD_CATEGORY_COMMON, WPD_PROPERTY_COMMON_COMMAND_CATEGORY,
    WPD_CATEGORY_STILL_IMAGE_CAPTURE, WPD_PROPERTY_COMMON_COMMAND_ID
    and WPD_COMMAND_STILL_IMAGE_CAPTURE_INITIATE.

    Thank you.

    ReplyDelete