
目次
サンプル・プログラム
searchoutletwin.msi | インストーラ |
bin/searchoutletwin.exe | 実行プログラム本体 |
bin/cwebpage.dll bin/libcurl.dll | 実行時に必要になるDLL |
bin/etc/help.chm | ヘルプ・ファイル |
sour/searchoutletwin.cpp | ソース・プログラム |
sour/resource.h | リソース・ヘッダ |
sour/resource.rc | リソース・ファイル |
sour/application.ico | アプリケーション・アイコン |
sour/mystrings.cpp | 汎用文字列処理関数など(ソース) |
sour/mystrings.h | 汎用文字列処理関数など(ヘッダ) |
sour/pahooGeocode.cpp | 住所・緯度・経度に関わるクラス(ソース) |
sour/pahooGeocode.hpp | 住所・緯度・経度に関わるクラス(ヘッダ) |
sour/apikey.cpp | APIキーの管理(ソース) |
sour/apikey.hpp | APIキーの管理(ヘッダ) |
sour/WebView2.h | WebView2に関わるヘッダ |
sour/event.h | WebView2用インターフェース(ヘッダ) |
sour/event.cpp | WebView2用インターフェース(ソース) |
sour/pahooWebView2.cpp | WebView2に関わる関数(ソース) |
sour/pahooWebView2.hpp | WebView2に関わる関数(ヘッダ) |
sour/makefile | ビルド |
バージョン | 更新日 | 内容 |
---|---|---|
2.2.0 | 2025/03/22 | Leafletアクセス可否チェック追加,使用ライブラリ更新 |
2.1.2 | 2024/11/30 | 使用ライブラリ更新 |
2.1.1 | 2024/08/24 | 使用ライブラリ更新 |
2.1.0 | 2024/05/03 | API入力処理を改良 |
2.0.0 | 2024/04/28 | Edgeブラウザ対応,64ビット対応 |
バージョン | 更新日 | 内容 |
---|---|---|
1.9.0 | 2025/03/16 | HTTPステータス・エラーをキャッチアップ |
1.8.1 | 2025/02/23 | setError() -- bug-fix |
1.8.0 | 2024/05/03 | getMyPath()をapikey.appのgetMyPath()関数に変更 |
1.7.0 | 2024/04/27 | Edge対応に伴いデバッグ用コードを廃棄 |
1.6.0 | 2023/07/02 | getPointsGSI()メソッド追加 |
バージョン | 更新日 | 内容 |
---|---|---|
1.3.1 | 2025/03/16 | readWebContents() リダイレクト有効に |
1.3.0 | 2025/03/16 | readWebContents() 引数httpStatus追加 |
1.2.0 | 2024/05/06 | getModulePath() 追加 |
1.12 | 2021/01/31 | readWebContents() 引数post追加 |
1.11 | 2020/10/17 | htmlspecialchars() 追加 |
バージョン | 更新日 | 内容 |
---|---|---|
1.0.0 | 2024/04/27 | 初版 |
バージョン | 更新日 | 内容 |
---|---|---|
2.0.0 | 2024/04/29 | createSetAPIkey, processSetAPIkey に統合 |
1.0 | 2020/09/30 | 初版 |
使用ライブラリ
また、地図表示にWebブラウザ・コントロールを利用するため "WebView2Loader.dll" を利用する。jchv / webview2-in-mingw からダウンロードできる。
リソースの準備
Eclipse を起動し、新規プロジェクト searchoutletwin を用意する。
ResEdit を起動し、resource.rc を用意する。
Eclipse に戻り、ソース・プログラム "searchoutletwin.cpp" を追加する。
リンカー・フラグを -Wl,--enable-stdcall-fixup -mwindows -lgdiplus -static -lstdc++ -lgcc -lwinpthread -lcurl -lssl "C:\(libcurl-x64.dllのフォルダ)\libcurl-x64.dll" "C:\(WebView2Loader.dllのフォルダ)\WebView2Loader.dll" に設定する。
また、コマンド行パターンを ${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS} -lole32 -loleaut32 -luuid にすること。

MSYS2 コマンドラインからビルドするのであれば、"makefile" を利用してほしい。
解説:定数など
searchoutletwin.cpp
44: // 定数など ==================================================================
45: #define MAKER "pahoo.org" //作成者
46: #define APPNAME "searchoutletwin" //アプリケーション名
47: #define APPNAMEJP "電源・Wi-Fi利用可能\店舗を検索" //アプリケーション名(日本語)
48: #define APPVERSION "2.2.0" //バージョン
49: #define APPYEAR "2020-25" //作成年
50: #define REFERENCE "https://www.pahoo.org/e-soul/webtech/cpp01/cpp01-17-01.shtm" //参考サイト
51:
52: //ListViewItemの最大文字長:変更不可
53: #define MAX_LISTVIEWITEM 259
54:
55: //ヘルプ・ファイル
56: #define HELPFILE ".\\etc\\help.chm"
57:
58: //デフォルト保存ファイル名
59: #define SAVEFILE "stationsearchwin.csv"
60:
61: //マップID
62: #define MAP_ID "map_id"
63: //地図の大きさ
64: #define MAP_WIDTH 550 //地図の幅(ピクセル)
65: #define MAP_HEIGHT 320 //地図の高さ(ピクセル)
66: //経度・緯度(初期値)
67: #define DEF_LONGITUDE 139.766667
68: double Longitude = DEF_LONGITUDE;
69: #define DEF_LATITUDE 35.681111
70: double Latitude = DEF_LATITUDE;
71: //地図拡大率(初期値)
72: #define DEF_ZOOM 13
73: int Zoom = DEF_ZOOM;
74: //地図の種類(初期値)
75: #define DEF_MAPTYPE "GSISTD"
76: string Maptype = DEF_MAPTYPE;
解説:検索の流れ

searchoutletwin.cpp
1276: //検索
1277: case IDM_EXEC:
1278: case IDC_BUTTON_EXEC:
1279: //カーソルを砂時計に
1280: SetCursor(LoadCursor(NULL, IDC_WAIT));
1281: //検索キーがあればジオコードAPI呼び出し
1282: Query = getStrEditBox(hDlg, IDC_EDIT_QUERY);
1283: if (Query.length() > 0) {
1284: if (pGC->searchPoints(_SW(Query), UserAgent, 0) > 0) {
1285: Longitude = pGC->Ppoints[0].longitude;
1286: Latitude = pGC->Ppoints[0].latitude;
1287: }
1288: //ブラウザ表示と一覧表示
1289: selectAction = eAction::GetZoomType;
1290: execScriptAndAction();
1291: } else {
1292: //ブラウザ表示と一覧表示
1293: selectAction = eAction::GetLatLongZoomType;
1294: execScriptAndAction();
1295: }
1296: //エラー・リセット
1297: ErrorMessage = "";
1298: pGC->resetError();
1299: break;
モバイラーズオアシスAPI
URL |
---|
https://oasis.mogya.com/api/v1/spots.json |
フィールド名 | 要否 | 内 容 |
---|---|---|
n | 必須 | 検索範囲の北端の緯度(世界測地系) |
s | 必須 | 検索範囲の南端の緯度(世界測地系) |
e | 必須 | 検索範囲の東端の経度(世界測地系) |
w | 必須 | 検索範囲の西端の経度(世界測地系) |
lat | 任意 | 検索中心の緯度(世界測地系) |
lng | 任意 | 検索中心の経度(世界測地系) |
解説:モバイラーズオアシスAPIの呼び出し
searchoutletwin.cpp
383: /**
384: * モバイラーズオアシス電源情報API から必要な情報を配列に格納する
385: * @param double latitude 緯度(世界測地系)
386: * @param double longitude 経度(世界測地系)
387: * @param double distance 範囲(メートル)
388: * @return int ヒット数/(-1):エラー発生
389: */
390: int pahooOasisMogya::getResults_OasisMogya(double latitude, double longitude, double distance) {
391: //モバイラーズオアシス電源情報API呼び出し
392: char sn[SIZE_BUFF + 1], ss[SIZE_BUFF + 1];
393: char se[SIZE_BUFF + 1], sw[SIZE_BUFF + 1];
394: double n, w, s, e;
395:
396: pGC->getPointDistance(longitude, latitude, distance, 0 - distance, &w, &n);
397: pGC->getPointDistance(longitude, latitude, 0 - distance, distance, &e, &s);
398:
399: snprintf(sn, SIZE_BUFF, "%.5f", n);
400: snprintf(ss, SIZE_BUFF, "%.5f", s);
401: snprintf(se, SIZE_BUFF, "%.5f", e);
402: snprintf(sw, SIZE_BUFF, "%.5f", w);
403: this->webapi = "https://oasis.mogya.com/api/v1/spots.json?n=" + (string)sn + "&w=" + (string)sw + "&s=" + (string)ss + "&e=" + (string)se;
404:
405: //モバイラーズオアシス電源情報API応答
406: static string contents = "";
407: static wstring ucontents = L"";
408:
409: int httpStatus = 0;
410: bool res = readWebContents(this->webapi, UserAgent, &contents, &httpStatus);
411: if (res == FALSE) {
412: this->errmsg = _SW("モバイラーズオアシス電源情報APIの接続エラーが発生しました");
413: return (-1);
414: } else if ((httpStatus < 200) || (httpStatus > 299)) {
415: ErrorMessage = "モバイラーズオアシス電源情報APIの接続エラーが発生しました";
416: return (-1);
417: }
418:
419: //配列の初期化
420: for (int i = 0; i < __SIZE_PPOINTS; i++) {
421: this->Poutlets[i].id = 0;
422: this->Poutlets[i].title = this->Poutlets[i].address = L"";
423: this->Poutlets[i].phone = L"";
424: this->Poutlets[i].url = this->Poutlets[i].mo_url = "";
425: this->Poutlets[i].latitude = this->Poutlets[i].longitude = 0.0;
426: }
427:
428: wregex re1(_SW("用途\\:充電"));
429: wregex re2(_SW("電源\\:"));
430: wregex re3(_SW("用途\\:"));
431: wregex re4(_SW("NG|ng"));
432: wsmatch mt1;
433:
434: //JSON読み込み
435: int cnt = 0;
436: try {
437: std::stringstream ss;
438: ss << contents;
439: ptree pt;
440: json_parser::read_json(ss, pt);
441:
442: //応答チェック
443: if (optional<string>str = pt.get_optional<string>("status")) {
444: if (str.get() == "OK") {
445: } else {
446: this->errmsg = _SW("モバイラーズオアシス電源情報APIの応答エラーが発生しました");
447: return (-1);
448: }
449: } else {
450: this->errmsg = _SW("モバイラーズオアシス電源情報APIの応答エラーが発生しました");
451: return (-1);
452: }
453:
454: //JSON解釈
455: try {
456: for (auto it : pt.get_child("results")) {
457: if (cnt >= __SIZE_PPOINTS) {
458: break;
459: }
460: //店名
461: if (optional<string>title = it.second.get_optional<string>("title")) {
462: this->Poutlets[cnt].title = _UW(title.get());
463: }
464: //住所
465: if (optional<string>address = it.second.get_optional<string>("address")) {
466: this->Poutlets[cnt].address = _UW(address.get());
467: }
468: //緯度
469: if (optional<string>lat = it.second.get_optional<string>("latitude")) {
470: this->Poutlets[cnt].latitude = stod(lat.get());
471: }
472: //経度
473: if (optional<string>lng = it.second.get_optional<string>("longitude")) {
474: this->Poutlets[cnt].longitude = stod(lng.get());
475: }
476: //URL
477: if (optional<string>url = it.second.get_optional<string>("url")) {
478: this->Poutlets[cnt].url = url.get();
479: }
480: //moURL
481: if (optional<string>mo_url = it.second.get_optional<string>("mo_url")) {
482: this->Poutlets[cnt].mo_url = mo_url.get();
483: }
484: //充電情報
485: this->Poutlets[cnt].charge = L"";
486: for (auto it2 : it.second.get_child("tags")) {
487: if (optional<string>name = it2.second.get_optional<string>("name")) {
488: wstring ws = _UW(name.get());
489: if (regex_search(ws, mt1, re1)) {
490: this->Poutlets[cnt].charge = _SW("可能\");
491: }
492: }
493: }
494: //電源情報
495: this->Poutlets[cnt].powersupply = L"";
496: int key = 0;
497: for (auto it2 : it.second.get_child("tags")) {
498: if (optional<string>name = it2.second.get_optional<string>("name")) {
499: wstring ws = _UW(name.get());
500: if (regex_search(ws, mt1, re4)) {
501: this->Poutlets[cnt].powersupply = L"";
502: break;
503: }
504: if (regex_search(ws, mt1, re2)) {
505: wstring wstr;
506: if (key > 0) {
507: wstr = _SW(",");
508: } else {
509: wstr = L"";
510: }
511: wstr += regex_replace(ws, re2, L"");
512: this->Poutlets[cnt].powersupply += wstr;
513: key++;
514: }
515: }
516: }
517: //Wi-Fi情報
518: this->Poutlets[cnt].wireless = L"";
519: for (auto it2 : it.second.get_child("wireless")) {
520: if (optional<string>name = it2.second.get_optional<string>("name")) {
521: wstring ws = _UW(name.get());
522: wstring wstr;
523: if (key > 0) {
524: wstr = _SW(",");
525: } else {
526: wstr = L"";
527: }
528: wstr += regex_replace(ws, re3, L"");
529: this->Poutlets[cnt].wireless += wstr;
530: key++;
531: }
532: }
533: //識別子
534: this->Poutlets[cnt].id = {(char)(65 + cnt)};
535: cnt++;
536: }
537: //JSON解釈エラー
538: } catch(ptree_bad_path& e) {
539: this->errmsg = _SW("モバイラーズオアシス電源情報APIの検索エラーが発生しました");
540: return (-1);
541: }
542:
543: //読み込みエラー
544: } catch(json_parser_error& e) {
545: this->errmsg = _SW("モバイラーズオアシス電源情報APIの接続エラーが発生しました");
546: return (-1);
547: }
548: contents.clear();
549:
550: return cnt;
551: }
C++で json形式データを扱うことは希だが、幸いなことに、Boost C++ライブラリ の property_tree にある json_parser は xml_parser とほぼ同じ使い方ができる。
今回も、cURL を使って応答情報を変数に代入し、ストリーミングを使ってjsonパーサーに流し込んでやる。

充電情報、電源情報、Wi-Fi情報は配列になっているため、これらをシリアライズしつつ、余計な文字列を正規表現の置換関数 regex_replace を使って省いている。
共通手順、モジュールなど
- C++ 開発環境の準備:ぱふぅ家のホームページ
- C++ 開発環境の準備 -MSYS2編-
- WiX によるWindowsインストーラー作成:ぱふぅ家のホームページ
- C++ でダイアログボックスを使う
- C++ でイベント駆動型アプリを作る
- 解説:ニュース一覧作成 | C++ で Googleニュース検索
- 解説:検索結果をCSVファイルに保存 | C++ で Googleニュース検索
- 解説:クリップボード | C++ でパスワード生成機を作る
- 解説:APIキーの管理 | C++ で直近の地震情報を取得する
- 解説:WebView2 | C++ で直近の地震情報を取得する
- 解説:解説:マップ表示用HTML生成 | C++ で直近の地震情報を取得する
参考サイト
- モバイラーズオアシスAPI
- PHPで電源・WiFi利用可能店舗を検索する:ぱふぅ家のホームページ
「PHPで電源・WiFi利用可能店舗を検索する」で作ったPHPプログラムをC++に移植したものである。
(2025年3月22日)ネット接続チェック強化,使用ライブラリ更新
(2024年11月30日)使用ライブラリ更新
(2024年8月24日)使用ライブラリ更新
(2024年5月3日)API入力処理を改良
(2024年4月27日)Edgeブラウザ対応,64ビット対応
(2024年4月7日)使用ライブラリ更新