Windows Sensor and Location APIでGPSデバイスから座標を取得 - torutkの日記 の続きです。
Javaから、Windows Sensor and Location APIを利用する方法を探ります。
Javaからネイティブのライブラリを呼び出す方法
まずは、Java SE Development Kit(JDK)標準の機構であるJNI があります。これは、ネイティブのライブラリを呼び出すためにC/C++でラッパーを記述する必要があり、Javaの開発に加えてC/C++の開発が必要になります。
一方、世の中にはC/C++でラッパーを記述しなくてもJavaだけでネイティブのライブラリを呼び出す便利なライブラリがあります。代表的なものに JNAライブラリ があります。ただし、C言語インタフェースの利用に限られます。
ところで、Location APIは、COMインタフェースとなっています。COMインタフェースを利用するライブラリがいくつか存在しています。代表的なものに com4jライブラリ があります。
JNAも標準ではなくcontribにCOMインタフェース呼び出しの機能があるようです(jna-platform.jar)。
com4j を使ってみる
ビルド済みライブラリ(com4jとtlbimp)をmavenリポジトリより入手します。現時点ではv2.1が最新のようです。
以下に入手とCOMインタフェースの型をJavaで生成するところまでの作業を記述しました。
http://www.torutk.com/projects/swe/wiki/Com4j
COMタイプライブラリから型情報を取得し対応するJavaクラスを生成
利用したいCOMライブラリファイル(DLLやOCXなど)から型情報を取得して、対応するJavaクラスを自動生成します。
com4jのtlbimpライブラリ(実行可能JARファイル)を実行し、対象COMライブラリファイル、生成するJavaクラスのパッケージ名、生成先ディレクトリをコマンドラインオプションで指定します。
(上述URL参照)
COMライブラリの初期化
Visual C++(ATL)では、最初にCOMライブラリの初期化(CoInitializeEx)を、COMを呼び出すスレッドごとに実行するのですが、com4jでは初期化らしきものを見かけないので内部で行われているのかと思います。
- Visual C++(ATL)
CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
- Java com4j
不要(?)
ILocationオブジェクトのインスタンス生成
- Visual C++(ATL)
CComPtr<ILocation> pLocation; if (FAILED(pLocation.CoCreateInstance(CLSID_Location))) { return 1; }
- Java com4j
ILocation location = ClassFactory.createLocation();
権限の取得
- Visual C++(ATL)
IID REPORT_TYPES[] = { IID_ILatLongReport }; if (FAILED(pLocation->RequestPermissions(nullptr, REPORT_TYPES, ARRAYSIZE(REPORT_TYPES), TRUE))) { return 1; }
ここで、IID型の配列で指定しているIID_ILatLongReportの正体を調べると、locationapi.hに次のように定義されています。
EXTERN_C const IID IID_ILatLongReport;
実行して内容を確認すると、インタフェースILatLongReportのIIDと一致しました。
7FED806D-0EF8-4F07-80AC-36A0BEAE3134
- Java com4j
GUID reportType = new GUID("7FED806D-0EF8-4F07-80AC-36A0BEAE3134"); // IID_ILatLongReport location.requestPermissions(0, reportType, 1, 1);
requestPermissionsのシグニチャは、次のように生成されています。
void requestPermissions(int hParent, GUID pReportTypes, int count, int fModal);
第2引数がGUID[]ではなくGUIDとなっているのが微妙です(バグ?)
位置情報のステータスの取得
- Visual C++(ATL)
LOCATION_REPORT_STATUS status; if (FAILED(pLocation->GetReportStatus(IID_ILatLongReport, &status))) { return 1; }
- Java com4j
LOCATION_REPORT_STATUS status = location.getReportStatus(reportType);
位置情報(ILocationReport)の取得
- Visual C++(ATL)
CComPtr<ILocationReport> pLocationReport; hr = pLocation->GetReport(IID_ILatLongReport, &pLocationReport); if (FAILED(hr)) { return 1; }
- Java com4j
ILocationReport report = location.getReport(reportType);
位置情報(ILocationReport)を緯度経度情報(ILatLongReport)へ
- Visual C++(ATL)
CComQIPtr<ILatLongReport> pLatLongReport(pLocationReport);
- Java com4j
ILatLongReport latLongReport = report.queryInterface(ILatLongReport.class);
緯度経度情報から緯度経度の値を取得
- Visual C++(ATL)
double latitude = 0.0; double longitude = 0.0; if (FAILED(pLatLongReport->GetLatitude(&latitude))) { return 1; } if (FAILED(pLatLongReport->GetLongitude(&longitude))) { return 1; }
- Java com4j
double latitude = latLongReport.getLatitude(); double longitude = latLongReport.getLongitude();