
目次
サンプル・プログラム
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.1 | 2025/07/26 | 使用ライブラリ更新 |
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入力処理を改良 |
バージョン | 更新日 | 内容 |
---|---|---|
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.1.0 | 2025/06/07 | TStrToWStr() -- C++17 対応 |
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.1" // バージョン
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
1277: // 検索
1278: case IDM_EXEC:
1279: case IDC_BUTTON_EXEC:
1280: // カーソルを砂時計に
1281: SetCursor(LoadCursor(NULL, IDC_WAIT));
1282: // 検索キーがあればジオコードAPI呼び出し
1283: Query = getStrEditBox(hDlg, IDC_EDIT_QUERY);
1284: if (Query.length() > 0) {
1285: if (pGC->searchPoints(_SW(Query), UserAgent, 0) > 0) {
1286: Longitude = pGC->Ppoints[0].longitude;
1287: Latitude = pGC->Ppoints[0].latitude;
1288: }
1289: // ブラウザ表示と一覧表示
1290: selectAction = eAction::GetZoomType;
1291: execScriptAndAction();
1292: } else {
1293: // ブラウザ表示と一覧表示
1294: selectAction = eAction::GetLatLongZoomType;
1295: execScriptAndAction();
1296: }
1297: // エラー・リセット
1298: ErrorMessage = "";
1299: pGC->resetError();
1300: 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: cout << httpStatus << endl;
412: if (res == FALSE) {
413: this->errmsg = _SW("モバイラーズオアシス電源情報APIの接続エラーが発生しました");
414: return (-1);
415: } else if ((httpStatus < 200) || (httpStatus > 299)) {
416: ErrorMessage = "モバイラーズオアシス電源情報APIの接続エラーが発生しました";
417: return (-1);
418: }
419:
420: // 配列の初期化
421: for (int i = 0; i < __SIZE_PPOINTS; i++) {
422: this->Poutlets[i].id = 0;
423: this->Poutlets[i].title = this->Poutlets[i].address = L"";
424: this->Poutlets[i].phone = L"";
425: this->Poutlets[i].url = this->Poutlets[i].mo_url = "";
426: this->Poutlets[i].latitude = this->Poutlets[i].longitude = 0.0;
427: }
428:
429: wregex re1(_SW("用途\\:充電"));
430: wregex re2(_SW("電源\\:"));
431: wregex re3(_SW("用途\\:"));
432: wregex re4(_SW("NG|ng"));
433: wsmatch mt1;
434:
435: // JSON読み込み
436: int cnt = 0;
437: try {
438: std::stringstream ss;
439: ss << contents;
440: ptree pt;
441: json_parser::read_json(ss, pt);
442:
443: // 応答チェック
444: if (optional<string>str = pt.get_optional<string>("status")) {
445: if (str.get() == "OK") {
446: } else {
447: this->errmsg = _SW("モバイラーズオアシス電源情報APIの応答エラーが発生しました");
448: return (-1);
449: }
450: } else {
451: this->errmsg = _SW("モバイラーズオアシス電源情報APIの応答エラーが発生しました");
452: return (-1);
453: }
454:
455: // JSON解釈
456: try {
457: for (auto it : pt.get_child("results")) {
458: if (cnt >= __SIZE_PPOINTS) {
459: break;
460: }
461: // 店名
462: if (optional<string>title = it.second.get_optional<string>("title")) {
463: this->Poutlets[cnt].title = _UW(title.get());
464: }
465: // 住所
466: if (optional<string>address = it.second.get_optional<string>("address")) {
467: this->Poutlets[cnt].address = _UW(address.get());
468: }
469: // 緯度
470: if (optional<string>lat = it.second.get_optional<string>("latitude")) {
471: this->Poutlets[cnt].latitude = stod(lat.get());
472: }
473: // 経度
474: if (optional<string>lng = it.second.get_optional<string>("longitude")) {
475: this->Poutlets[cnt].longitude = stod(lng.get());
476: }
477: // URL
478: if (optional<string>url = it.second.get_optional<string>("url")) {
479: this->Poutlets[cnt].url = url.get();
480: }
481: // moURL
482: if (optional<string>mo_url = it.second.get_optional<string>("mo_url")) {
483: this->Poutlets[cnt].mo_url = mo_url.get();
484: }
485: // 充電情報
486: this->Poutlets[cnt].charge = L"";
487: for (auto it2 : it.second.get_child("tags")) {
488: if (optional<string>name = it2.second.get_optional<string>("name")) {
489: wstring ws = _UW(name.get());
490: if (regex_search(ws, mt1, re1)) {
491: this->Poutlets[cnt].charge = _SW("可能\");
492: }
493: }
494: }
495: // 電源情報
496: this->Poutlets[cnt].powersupply = L"";
497: int key = 0;
498: for (auto it2 : it.second.get_child("tags")) {
499: if (optional<string>name = it2.second.get_optional<string>("name")) {
500: wstring ws = _UW(name.get());
501: if (regex_search(ws, mt1, re4)) {
502: this->Poutlets[cnt].powersupply = L"";
503: break;
504: }
505: if (regex_search(ws, mt1, re2)) {
506: wstring wstr;
507: if (key > 0) {
508: wstr = _SW(",");
509: } else {
510: wstr = L"";
511: }
512: wstr += regex_replace(ws, re2, L"");
513: this->Poutlets[cnt].powersupply += wstr;
514: key++;
515: }
516: }
517: }
518: // Wi-Fi情報
519: this->Poutlets[cnt].wireless = L"";
520: for (auto it2 : it.second.get_child("wireless")) {
521: if (optional<string>name = it2.second.get_optional<string>("name")) {
522: wstring ws = _UW(name.get());
523: wstring wstr;
524: if (key > 0) {
525: wstr = _SW(",");
526: } else {
527: wstr = L"";
528: }
529: wstr += regex_replace(ws, re3, L"");
530: this->Poutlets[cnt].wireless += wstr;
531: key++;
532: }
533: }
534: // 識別子
535: this->Poutlets[cnt].id = {(char)(65 + cnt)};
536: cnt++;
537: }
538: // JSON解釈エラー
539: } catch(ptree_bad_path& e) {
540: this->errmsg = _SW("モバイラーズオアシス電源情報APIの検索エラーが発生しました");
541: return (-1);
542: }
543:
544: // 読み込みエラー
545: } catch(json_parser_error& e) {
546: this->errmsg = _SW("モバイラーズオアシス電源情報APIの接続エラーが発生しました");
547: return (-1);
548: }
549: contents.clear();
550:
551: return cnt;
552: }
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年7月26日)使用ライブラリ更新
(2025年3月22日)ネット接続チェック強化,使用ライブラリ更新
(2024年11月30日)使用ライブラリ更新
(2024年8月24日)使用ライブラリ更新