IPortableDevice
COM公式ドキュメント
IPortableDevice インターフェイスは、ポータブルデバイスへのアクセスを提供します。
解説(Remarks)
クライアントインターフェイスは任意の WPD オブジェクトに対して使用できるように設計されており、アプリケーションが参照するオブジェクトごとに新しいインスタンスを作成する必要はありません。アプリケーションが IPortableDevice インターフェイスのインスタンスを開いた後は、必要となるその他の WPD クライアントインターフェイスも開いてキャッシュしておくとよいでしょう。
Windows 7 では、IPortableDevice は CoCreateInstance 用に 2 つの CLSID をサポートします。CLSID_PortableDevice は、フリースレッドマーシャラーを集約しない IPortableDevice ポインターを返します。CLSID_PortableDeviceFTM は新しい CLSID で、フリースレッドマーシャラーを集約する IPortableDevice ポインターを返します。それ以外の機能については、どちらのポインターも同じです。
シングルスレッドアパートメントで動作するアプリケーションでは、インターフェイスポインターのマーシャリングのオーバーヘッドを排除できるため、CLSID_PortableDeviceFTM を使用してください。CLSID_PortableDevice は、従来のアプリケーションのために引き続きサポートされています。
メソッド 9
vtbl = vtable インデックス(0始まり)。HSP等からCOMメソッドをインデックス指定で呼ぶ際に使用します。0〜2 は IUnknown。
Open メソッドは、アプリケーションとデバイスの間の接続を開きます。
| pszPnPDeviceID | LPWSTR | in | デバイスのプラグアンドプレイ ID 文字列を格納した、null で終わる文字列へのポインター。この文字列は IPortableDeviceManager::GetDevices を呼び出すことで取得できます。 |
| pClientInfo | IPortableDeviceValues* | in | デバイスに対してアプリケーションを識別する情報を保持する IPortableDeviceValues インターフェイスへのポインター。このインターフェイスは、アプリケーションを一意に識別するための PROPERTYKEY/値のペアを保持します。CoCreate されたインターフェイスの存在は必須ですが、アプリケーションがキー/値のペアを送信することは必須ではありません。ただし、データを送信するとパフォーマンスが向上する場合があります。代表的なキー/値のペアには、アプリケーション名、メジャーバージョンおよびマイナーバージョン、ビルド番号があります。 Properties セクションの "WPD_CLIENT_" で始まるプロパティを参照してください。 |
戻り値
このメソッドは HRESULT を返します。取り得る値には、次の表に示すものが含まれます (これらに限定されません)。
| 戻り値 | 説明 |
|---|---|
| メソッドは成功しました。 | |
| デバイス接続は既に開かれています。 | |
| 引数の少なくとも 1 つが NULL ポインターでした。 |
解説(Remarks)
デバイスに対してメソッドを呼び出す前に、そのデバイスを開いておく必要があります (ただし、IPortableDeviceManager のメソッドは、呼び出し前にデバイスを開く必要はありません)。一方で、通常 Close を呼び出す必要はありません。
管理者は、ネットワーク上で動作するコンピューターに対するポータブルデバイスのアクセスを制限できます。たとえば、すべての Guest ユーザーを読み取り専用アクセスに制限し、認証済みユーザーには読み取り/書き込みアクセスを与える、といった設定が可能です。
こうしたセキュリティ上の理由から、アプリケーションが書き込み操作を行わない場合は、pClientInfo パラメーターで指定する WPD_CLIENT_DESIRED_ACCESS プロパティに GENERIC_READ を指定して読み取り専用アクセスを要求し、Open メソッドを呼び出してください。
アプリケーションが書き込み操作を必要とする場合は、次のサンプルコードのように Open メソッドを呼び出してください。まず、pClientInfo パラメーターで既定の WPD_CLIENT_DESIRED_ACCESS プロパティを渡して読み取り/書き込みアクセスを要求します。この最初の呼び出しが失敗して E_ACCESSDENIED が返された場合は、pClientInfo パラメーターで指定する WPD_CLIENT_DESIRED_ACCESS プロパティに GENERIC_READ を指定し、読み取り専用アクセスを要求して Open メソッドをもう一度呼び出してください。
シングルスレッドアパートメントで動作するアプリケーションでは、インターフェイスポインターのマーシャリングのオーバーヘッドを排除できるため、CLSID_PortableDeviceFTM を使用してください。CLSID_PortableDevice は、従来のアプリケーションのために引き続きサポートされています。
例
#define CLIENT_NAME L"My WPD Application"
#define CLIENT_MAJOR_VER 1
#define CLIENT_MINOR_VER 0
#define CLIENT_REVISION 0
HRESULT OpenDevice(LPCWSTR wszPnPDeviceID, IPortableDevice** ppDevice)
{
HRESULT hr = S_OK;
IPortableDeviceValues* pClientInformation = NULL;
IPortableDevice* pDevice = NULL;
if ((wszPnPDeviceID == NULL) || (ppDevice == NULL))
{
hr = E_INVALIDARG;
return hr;
}
// クライアント情報を保持する IPortableDeviceValues インターフェイスを CoCreate する。
hr = CoCreateInstance(CLSID_PortableDeviceValues,
NULL,
CLSCTX_INPROC_SERVER,
IID_IPortableDeviceValues,
(VOID**) &pClientInformation);
if (SUCCEEDED(hr))
{
HRESULT ClientInfoHR = S_OK;
// クライアント情報のすべてのプロパティの設定を試みる。以下のいずれかの
// プロパティの設定に失敗しても問題ない。クライアント情報のプロパティ設定の
// 失敗は致命的なエラーではない。
ClientInfoHR = pClientInformation->SetStringValue(WPD_CLIENT_NAME, CLIENT_NAME);
if (FAILED(ClientInfoHR))
{
// WPD_CLIENT_NAME の設定に失敗
}
ClientInfoHR = pClientInformation->SetUnsignedIntegerValue(WPD_CLIENT_MAJOR_VERSION, CLIENT_MAJOR_VER);
if (FAILED(ClientInfoHR))
{
// WPD_CLIENT_MAJOR_VERSION の設定に失敗
}
ClientInfoHR = pClientInformation->SetUnsignedIntegerValue(WPD_CLIENT_MINOR_VERSION, CLIENT_MINOR_VER);
if (FAILED(ClientInfoHR))
{
// WPD_CLIENT_MINOR_VERSION の設定に失敗
}
ClientInfoHR = pClientInformation->SetUnsignedIntegerValue(WPD_CLIENT_REVISION, CLIENT_REVISION);
if (FAILED(ClientInfoHR))
{
// WPD_CLIENT_REVISION の設定に失敗
}
}
else
{
// クライアント情報用の CLSID_PortableDeviceValues の CoCreateInstance に失敗
}
ClientInfoHR = pClientInformation->SetUnsignedIntegerValue(WPD_CLIENT_SECURITY_QUALITY_OF_SERVICE, SECURITY_IMPERSONATION);
if (FAILED(ClientInfoHR))
{
// WPD_CLIENT_SECURITY_QUALITY_OF_SERVICE の設定に失敗
}
if (SUCCEEDED(hr))
{
// IPortableDevice インターフェイスを CoCreate する
hr = CoCreateInstance(CLSID_PortableDeviceFTM,
NULL,
CLSCTX_INPROC_SERVER,
IID_IPortableDevice,
(VOID**) &pDevice);
if (SUCCEEDED(hr))
{
// この関数に渡された PnPDeviceID 文字列と、新しく作成した
// クライアント情報を使ってデバイスを開くことを試みる。
// 最初は既定 (読み取り/書き込み) のアクセスでデバイスを
// 開こうとしている点に注意。これが E_ACCESSDENIED で
// 失敗した場合は、読み取り専用アクセスで 2 回目の
// オープンを試みる。
hr = pDevice->Open(wszPnPDeviceID, pClientInformation);
if (hr == E_ACCESSDENIED)
{
// 読み取り専用アクセスでのオープンを試みる
pClientInformation->SetUnsignedIntegerValue(
WPD_CLIENT_DESIRED_ACCESS,
GENERIC_READ);
hr = pDevice->Open(wszPnPDeviceID, pClientInformation);
}
if (SUCCEEDED(hr))
{
// デバイスのオープンに成功したので、呼び出し元に開かれた
// IPortableDevice を返せるよう、デバイスのインスタンスを
// ppDevice に取得する。
hr = pDevice->QueryInterface(IID_IPortableDevice, (VOID**)ppDevice);
if (FAILED(hr))
{
// 開かれた IPortableDevice の QueryInterface に失敗
}
}
}
else
{
// CLSID_PortableDevice の CoCreateInstance に失敗
}
}
// 処理が完了したら IPortableDevice を解放する
if (pDevice != NULL)
{
pDevice->Release();
pDevice = NULL;
}
// 処理が完了したら、クライアント情報を保持する IPortableDeviceValues を解放する
if (pClientInformation != NULL)
{
pClientInformation->Release();
pClientInformation = NULL;
}
return hr;
}
SendCommand メソッドは、デバイスにコマンドを送信し、その結果を同期的に取得します。
| dwFlags | DWORD | in | 現在使用されていません。0 を指定してください。 | ||||||
| pParameters | IPortableDeviceValues* | in | デバイスに対して呼び出すコマンドとそのパラメーターを指定する IPortableDeviceValues インターフェイスへのポインター。このインターフェイスには、コマンドを示す次の 2 つの値を含める必要があります。追加のパラメーターはコマンドによって異なります。各コマンドに必要なパラメーターの一覧については、Commands を参照してください。
| ||||||
| ppResults | IPortableDeviceValues** | out | コマンドの結果 (成功または失敗、およびデバイスから返されたコマンドの値を含む) を示す IPortableDeviceValues インターフェイスへのポインターを受け取る変数のアドレス。呼び出し元は、使用が終わったらこのインターフェイスを解放する必要があります。取得される値はコマンドによって異なります。各コマンド呼び出しでどのような値が返されるかについては、Commands の該当するコマンドのドキュメントを参照してください。 |
戻り値
戻り値は、ドライバーへのコマンド送信と結果の取得に成功したかどうかを示すものであり、ドライバーがそのコマンドをサポートしているかどうかや、コマンドの処理中にエラーが発生したかどうかを示すものではありません (詳細については「解説」を参照してください)。それらのエラーは、ppResults パラメーターの HRESULT 値として返されます。このメソッドが返す HRESULT 値には、次の表に示すものが含まれます (これらに限定されません)。
| 戻り値 | 説明 |
|---|---|
| コマンドはドライバーによって正常に受信されました。これはコマンド自体が成功したことを示すものではありません。コマンドの成功または失敗を判断するには ppResults を確認する必要があります。 | |
| 引数の少なくとも 1 つが NULL ポインターでした。 |
解説(Remarks)
この関数は、ドライバーに直接コマンドを送信するために使用します。コマンドとは、期待する動作を示すためにドライバーへ送信される PROPERTYKEY であり、必要なパラメーターの一覧を伴います。各コマンドには、ドライバーが要求された動作を実行するためにコマンドと共にパッケージ化する必要がある、必須および省略可能なパラメーターと結果の一覧があります。Windows ポータブルデバイスが定義するコマンドの一覧と、必要なパラメーターおよび戻り値については、Commands を参照してください。
Windows ポータブルデバイスのほとんどのメソッドは、実際には Windows ポータブルデバイスのコマンドを 1 つ以上送信し、パラメーターをラップすることで動作しています。一部のコマンドには対応する Windows ポータブルデバイスのメソッドがありません。それらのコマンドを呼び出す唯一の方法が SendCommand の使用です。次のコマンドには、対応するメソッドがありません。
- WPD_COMMAND_COMMON_RESET_DEVICE
- WPD_COMMAND_DEVICE_HINTS_GET_CONTENT_LOCATION
- WPD_COMMAND_SMS_SEND
- WPD_COMMAND_STILL_IMAGE_CAPTURE_INITIATE
- WPD_COMMAND_STORAGE_EJECT
一部のカスタムコマンドでは、特定の Input/Output Control Code (IOCTL) のアクセスレベルが必要になる場合があります。アプリケーションは、SendCommand メソッドに渡すコマンドパラメーターに対して IPortableDeviceValues::SetUnsignedIntegerValue メソッドを呼び出すことで、このアクセスレベルを設定します。たとえば、カスタムコマンドが読み取り専用アクセスを必要とする場合は、SetUnsignedIntegerValue を呼び出し、第 1 引数に WPD_API_OPTION_IOCTL_ACCESS、第 2 引数に FILE_READ_ACCESS を渡します。これらのコマンドパラメーターを更新することで、Windows ポータブルデバイス API が読み取り専用の IOCTL でコマンドを発行するようになります。
コマンドの処理中にドライバーで発生したエラーは、SendCommand の戻り値ではなく ppResults パラメーターから取得します。このメソッドの戻り値は、ドライバーへコマンドを送信する際に発生したエラー (または成功) のコードです。
ドライバーが指定されたコマンドをサポートしていない場合、このメソッドは成功しますが、返される ppResults パラメーターの中で保証される要素は WPD_PROPERTY_COMMON_HRESULT のみであり、その値は E_NOTIMPL になります。ドライバーがコマンドをサポートしているかどうかは、コマンドを呼び出す前に IPortableDeviceCapabilities::GetSupportedCommands を呼び出して確認できます。
コマンドがオプション (再帰的な削除、非再帰的な削除など) をサポートしている場合は、IPortableDeviceCapabilities::GetCommandOptions を呼び出してサポートされるオプションを照会できます。
SendCommand の呼び出しにタイムアウトを設定するオプションはありませんが、開発者は別のスレッドから IPortableDevice::Cancel を呼び出すことで、コマンドのキャンセルを試みることができます。
例
//
void ResetDevice(IPortableDevice* pDevice)
{
HRESULT hr = S_OK;
CComPtr<IPortableDeviceValues> pDevValues;
hr = CoCreateInstance(CLSID_PortableDeviceValues,
NULL,
CLSCTX_INPROC_SERVER,
IID_IPortableDeviceValues,
(VOID**) &pDevValues);
if (SUCCEEDED(hr))
{
if (pDevValues != NULL)
{
hr = pDevValues->SetGuidValue(WPD_PROPERTY_COMMON_COMMAND_CATEGORY,
WPD_COMMAND_COMMON_RESET_DEVICE.fmtid);
if (FAILED(hr))
{
printf("! IPortableDeviceValues::SetGuidValue failed, hr= 0x%lx\n", hr);
}
hr = pDevValues->SetUnsignedIntegerValue(WPD_PROPERTY_COMMON_COMMAND_ID,
WPD_COMMAND_COMMON_RESET_DEVICE.pid);
if (FAILED(hr))
{
printf("! IPortableDeviceValues::SetGuidValue failed, hr= 0x%lx\n", hr);
}
}
}
hr = pDevice->SendCommand(0, pDevValues, &pDevValues);
if (FAILED(hr))
{
printf("! Failed to reset the device, hr = 0x%lx\n",hr);
}
else
printf("Device successfully reset\n");
return;
}
//
Content メソッドは、デバイス上のオブジェクトにアクセスするために使用できるインターフェイスを取得します。
| ppContent | IPortableDeviceContent** | out | デバイス上のコンテンツにアクセスするために使用する IPortableDeviceContent インターフェイスへのポインターを受け取る変数のアドレス。呼び出し元は、使用が終わったらこのインターフェイスを解放する必要があります。 |
戻り値
このメソッドは HRESULT を返します。取り得る値には、次の表に示すものが含まれます (これらに限定されません)。
| 戻り値 | 説明 |
|---|---|
| メソッドは成功しました。 | |
| ppContent 引数が NULL ポインターでした。 |
Capabilities メソッドは、ポータブルデバイスの機能 (ケイパビリティ) を照会するために使用するインターフェイスを取得します。
| ppCapabilities | IPortableDeviceCapabilities** | out | デバイスの機能 (ケイパビリティ) を記述できる IPortableDeviceCapabilities インターフェイスへのポインターを受け取る変数のアドレス。呼び出し元は、使用が終わったらこのインターフェイスを解放する必要があります。 |
戻り値
このメソッドは HRESULT を返します。取り得る値には、次の表に示すものが含まれます (これらに限定されません)。
| 戻り値 | 説明 |
|---|---|
| メソッドは成功しました。 | |
| ppCapabilities 引数が NULL ポインターでした。 |
Cancel メソッドは、このインターフェイスで保留中の操作をキャンセルします。
戻り値
このメソッドは HRESULT を返します。取り得る値には、次の表に示すものが含まれます (これらに限定されません)。
| 戻り値 | 説明 |
|---|---|
| 操作は正常にキャンセルされました。 |
解説(Remarks)
アプリケーションが複数のスレッドから WPD API を呼び出す場合、各スレッドで IPortableDevice インターフェイスの新しいインスタンスを作成してください。こうすることで、キャンセル操作が該当スレッドの I/O にのみ影響するようになります。
Cancel メソッドを呼び出した時点で IStream の書き込み操作が進行中である場合、アプリケーションは IStream::Revert メソッドを呼び出してすべての変更を破棄してください。変更を破棄した後は、IUnknown::Release メソッドを呼び出してストリームも閉じる必要があります。
また、IStream::Write メソッドが完了する前に Cancel メソッドが呼び出された場合、書き込み中のデータが破損する可能性がある点にも注意してください。
Close メソッドは、デバイスとの接続を閉じます。
戻り値
このメソッドは HRESULT を返します。取り得る値には、次の表に示すものが含まれます (これらに限定されません)。
| 戻り値 | 説明 |
|---|---|
| メソッドは成功しました。 |
解説(Remarks)
通常、このメソッドを自分で呼び出す必要はありません。IPortableDevice インターフェイスへの最後の参照が解放されると、Windows ポータブルデバイスが代わりに Close を呼び出します。このメソッドを手動で呼び出すと、デバイスへの接続が強制的に閉じられ、このデバイス上でホストされている Windows ポータブルデバイスのオブジェクトはすべて機能しなくなります。接続を再度開くには Open を呼び出します。
Advise メソッドは、デバイスイベントを受け取るアプリケーション定義のコールバックを登録します。
| dwFlags | DWORD | in | オプションフラグを指定する DWORD。 |
| pCallback | IPortableDeviceEventCallback* | in | コールバックオブジェクトへのポインター。 |
| pParameters | IPortableDeviceValues* | in | このパラメーターは無視されます。NULL を設定してください。 |
| ppszCookie | LPWSTR* | out | 一意のコンテキスト ID を表す文字列。Unadvise を呼び出してコールバックの登録を解除する際に使用します。 |
戻り値
このメソッドは HRESULT を返します。取り得る値には、次の表に示すものが含まれます (これらに限定されません)。
| 戻り値 | 説明 |
|---|---|
| アプリケーション定義のコールバックが正常に登録されました。 |
Unadvise メソッドは、クライアントのコールバック通知の受信登録を解除します。以前に Advise を呼び出している場合は、このメソッドを呼び出す必要があります。
| pszCookie | LPWSTR | in | 一意のコンテキスト ID である、null で終わる文字列へのポインター。これは最初の IPortableDevice::Advise の呼び出しで取得したものです。 |
戻り値
このメソッドは HRESULT を返します。取り得る値には、次の表に示すものが含まれます (これらに限定されません)。
| 戻り値 | 説明 |
|---|---|
| メソッドは成功しました。 |
GetPnPDeviceID メソッドは、アプリケーションがデバイスを開く際に使用したプラグアンドプレイ (PnP) デバイス識別子を取得します。
| ppszPnPDeviceID | LPWSTR* | out | デバイスのプラグアンドプレイ ID 文字列を格納した、null で終わる文字列へのポインター。 |
戻り値
このメソッドは HRESULT を返します。取り得る値には、次の表に示すものが含まれます (これらに限定されません)。
| 戻り値 | 説明 |
|---|---|
| メソッドは成功しました。 | |
| このデバイスに対して IPortableDevice::Open メソッドがまだ呼び出されていません。 |
解説(Remarks)
アプリケーションは、このメソッドが返した文字列の使用が終わったら、CoTaskMemFree 関数を呼び出して文字列を解放する必要があります。
ppszPnPDeviceID 引数に NULL を設定してはいけません。
Microsoft 公式リファレンス: 英語 (en-us) · 日本語 (ja-jp) · 原文ソース (GitHub)
HSP用 COM定義
#usecom / #comfunc によるHSPのCOM呼び出し定義。数字は vtbl インデックス(0始まり)。クラスIDが無い場合 #usecom の末尾は "{}"、ある場合は "{CLSID}"。
#define global IID_IPortableDevice "{625E2DF8-6392-4CF0-9AD1-3CFA5F17775C}" #usecom global IPortableDevice IID_IPortableDevice "{728A21C5-3D9E-48D7-9810-864848F0F404}" #comfunc global IPortableDevice_Open 3 wstr,sptr #comfunc global IPortableDevice_SendCommand 4 int,sptr,sptr #comfunc global IPortableDevice_Content 5 sptr #comfunc global IPortableDevice_Capabilities 6 sptr #comfunc global IPortableDevice_Cancel 7 #comfunc global IPortableDevice_Close 8 #comfunc global IPortableDevice_Advise 9 int,sptr,sptr,var #comfunc global IPortableDevice_Unadvise 10 wstr #comfunc global IPortableDevice_GetPnPDeviceID 11 var ; ※数字は vtbl インデックス(0始まり)。0/1/2 は IUnknown(QueryInterface/AddRef/Release)。 ; ※#usecom 末尾は CoCreateInstance 用のクラスID(コクラスCLSID, SDKから自動取得)。 ; ※出力/バッファ引数は var(変数直渡し)。varptr 方式にも切替可。 ; ※ハンドル/void*等の不透明ポインタは IronHSP では intptr 指定が可能。#define global IID_IPortableDevice "{625E2DF8-6392-4CF0-9AD1-3CFA5F17775C}" #usecom global IPortableDevice IID_IPortableDevice "{728A21C5-3D9E-48D7-9810-864848F0F404}" #comfunc global IPortableDevice_Open 3 wstr,sptr #comfunc global IPortableDevice_SendCommand 4 int,sptr,sptr #comfunc global IPortableDevice_Content 5 sptr #comfunc global IPortableDevice_Capabilities 6 sptr #comfunc global IPortableDevice_Cancel 7 #comfunc global IPortableDevice_Close 8 #comfunc global IPortableDevice_Advise 9 int,sptr,sptr,sptr #comfunc global IPortableDevice_Unadvise 10 wstr #comfunc global IPortableDevice_GetPnPDeviceID 11 sptr ; ※数字は vtbl インデックス(0始まり)。0/1/2 は IUnknown(QueryInterface/AddRef/Release)。 ; ※#usecom 末尾は CoCreateInstance 用のクラスID(コクラスCLSID, SDKから自動取得)。 ; ※出力/バッファ引数はポインタ方式(token=sptr / 呼び出しは varptr(変数))。 ; ※ハンドル/void*等の不透明ポインタは IronHSP では intptr 指定が可能。