Tuesday, May 10, 2011

Controlling a digital camera with Delphi (part 2)

As described in my previous post, I started coding with the Windows Portable Device (WPD) library. To do this in Delphi, you first need to create a TLB.PAS file that contains the declarations and other info from the library. I am using Delphi 2009, so the steps for this version are (assuming you have your project open):

1. menu: ‘Component -> Import Component…’
2. ‘Import a Type Library’, then click ‘Next’
3. From the list select: ‘PortableDeviceApi 1.0 Type Library’, then click ‘Next’
4. In the ‘Unit Dir Name’ box, enter the directory where you want the unit to be created, then click ‘Next’
5. Select ‘Create Unit’, then click ‘Finish’.
You should see the new Unit in Delphi. Add the unit to your project.

The library contains most of the information you need, but there are a few things we need to modify. First of all, add the following in the const declarations at the beginning of the unit (not necessary, but useful):

CLASS_PortableDeviceValues: TGUID = '{0c15d503-d017-47ce-9016-7b3f978721cc}';

Then, change the declarations for the following functions, which are not properly defined (I wasted a few days until I figured this out):
For ‘IEnumPortableDeviceObjectIDs’, change the ‘Next’ function to:

function Next(cObjects: LongWord;
pObjIDs: Pointer;
var pcFetched: LongWord): HResult; stdcall;

For ‘IPortableDeviceManager’, change the ‘GetDevices’ and ‘GetDeviceFriendlyName’ to:

function GetDevices(pPnPDeviceIDs: Pointer;
var pcPnPDeviceIDs: LongWord): HResult; stdcall;
function GetDeviceFriendlyName(pszPnPDeviceID: PWideChar;
pDeviceFriendlyName: Pointer;
var pcchDeviceFriendlyName: LongWord): HResult; stdcall;

There may be other functions that need editing but these are the ones I have discovered so far.
In addition, it is a good idea to define some constants, to make your life easier, especially when translating from c code. I created a new unit (named WPD) and added a long list of constants and some useful functions. I will post a link to the file once I clean it up a bit, so be patient for now. Most of the info can be found in the h files that are included in the Microsoft Windows Software Development Kit for Windows 7. This can be freely downloaded from the Microsoft web site. Also, be sure to visit and carefully study the Microsoft site for portable devices which contains examples of c code, upon which I based my implementation.

To end today’s post, here is code to look for wpd devices connected to your computer and list their names and device Ids to a Memo component:

procedure TMainForm.ListDevices;
var
aPortableDevManager: IPortableDeviceManager;
countDeviceIDs: Cardinal;
res: HResult;
deviceIDs: TArrayPWideChar;
i: integer;
pcchDeviceFriendlyName: Cardinal;
DeviceFriendlyName: PWideChar;
begin
aPortableDevManager := CoPortableDeviceManager.Create;
if VarIsClear(aPortableDevManager) then exit;
//get number of devices
countDeviceIDs := 0;
res := aPortableDevManager.GetDevices(nil, countDeviceIDs);
Memo1.Lines.Add('Devices found: ' + inttostr(countDeviceIDs));
if (res < 0) or (countDeviceIDs = 0) then exit;
//get all devices:
setLength(deviceIDs, countDeviceIDs);
res := aPortableDevManager.GetDevices(@deviceIDs[0], countDeviceIDs);
if res < 0 then exit; //failed
for i := 0 to countDeviceIDs - 1 do //enumerate the devices:
begin
Memo1.Lines.Add(deviceIDs[i]);
//get length of friendly name:
pcchDeviceFriendlyName := 0;
aPortableDevManager.GetDeviceFriendlyName(deviceIDs[i],
nil,
pcchDeviceFriendlyName);
DeviceFriendlyName := PWideChar(StringOfChar(' ', pcchDeviceFriendlyName));
//get name:
aPortableDevManager.GetDeviceFriendlyName(deviceIDs[i],
@DeviceFriendlyName[0],
pcchDeviceFriendlyName);
Memo1.Lines.Add(DeviceFriendlyName);
end;
end;

You will need these in your ‘uses’ list: Windows, ComObj, ActiveX, PortableDeviceApiLib_TLB, Variants, Classes
TArrayPWideChar was defined as:

type
pArrayPWideChar = ^TArrayPWideChar;
TArrayPWideChar = array of PWideChar;

In my next post I hope to show you how to shoot a picture.

2 comments:

  1. Anonymous1:34 PM

    Hi,

    Thanks for this post. Did you mange to take a photo using a webcam using the API, i cannot find much information on the web regarding this API.

    Thanks
    Rudy

    ReplyDelete
  2. Hi, Demetris,

    Any progress with WPD library?

    Kryvich

    ReplyDelete