This post covers how to connect to a WPD device. We obtained a list of device paths in Enumerating WPD devices (Part 1) - ppszDeviceListArray - which we will end up using here.

Connecting to a device requires the client to identify itself. This is done by supplying a paired collection of property keys and values wrapped in a IPortableDeviceValues collection. The IPortableDeviceValues collection type is part of the WPD API along with some other types and will be discussed in a later post. For now, think of it as a map with the key corresponding to a GUID and the value corresponding to a PROPVARIANT.

HRESULT hr = S_OK;

// Create our client information collection
CComPtr<IPortableDeviceValues> spClientInfo;
hr = CoCreateInstance(CLSID_PortableDeviceValues, 
                      NULL,
                      CLSCTX_INPROC_SERVER,
                      IID_IPortableDeviceValues,
                      (VOID**)&spClientInfo);

// We have to provide at the least our name, version, revision
hr = spClientInfo->SetStringValue(WPD_CLIENT_NAME, L"Sample Client");
hr = spClientInfo->SetUnsignedIntegerValue(WPD_CLIENT_MAJOR_VERSION, 1);
hr = spClientInfo->SetUnsignedIntegerValue(WPD_CLIENT_MINOR_VERSION, 0);
hr = spClientInfo->SetUnsignedIntegerValue(WPD_CLIENT_REVISION, 1);

// A WPD device is represented by an IPortableDevice instance
CComPtr<IPortableDevice> spDevice;
hr = CoCreateInstance(CLSID_PortableDevice, 
                      NULL,
                      CLSCTX_INPROC_SERVER,
                      IID_IPortableDevice,
                      (VOID**)&spDevice);

// We are now ready to open a connection to the device
// We'll assume cdwDevices>0 and connect to the first device path
hr = spDevice->Open(ppszDeviceListArray[0], spClientInfo);

 At this point, (if hr==S_OK) we have successfully connected to the device. We can now retrieve other (more interesting) interfaces from IPortableDevice such as IPortableDeviceContent and IPortableDeviceProperties. IPortableDeviceContent will allow us to enumerate objects on the device and IPortableDeviceProperties will let us retrieve properties for these objects.

These other interfaces will be discussed again in a later post, for now we'll end with how to close the device connection :). This is relatively painless - IPortableDevice exposes the Close method which takes no parameters. Once called, all interfaces obtained through the IPortableDevice interface are invalid and calls on them will return E_WPD_DEVICE_NOT_OPEN.

// Close the connection to the device
hr = spDevice->Close();