「VBA Edge制御 更新自動化コマンドプロンプトプログラム」の版間の差分
(→概要) |
|||
| 68行目: | 68行目: | ||
#include <winhttp.h> | #include <winhttp.h> | ||
#include <typeinfo> | #include <typeinfo> | ||
#include <zip.h> | #include <zip.h> | ||
#pragma comment(lib, "winhttp.lib") | #pragma comment(lib, "winhttp.lib") | ||
#pragma comment(lib, "Version.lib") | #pragma comment(lib, "Version.lib") | ||
#pragma comment(lib, "zip.lib") | #pragma comment(lib, "zip.lib") | ||
std::string GetVersion(const std::string& path) { | std::string GetVersion(const std::string& path) { | ||
DWORD handle; | DWORD handle; | ||
| 81行目: | 81行目: | ||
throw std::runtime_error("Failed to get version info size."); | throw std::runtime_error("Failed to get version info size."); | ||
} | } | ||
std::vector<char> data(size); | std::vector<char> data(size); | ||
if (!GetFileVersionInfoA(path.c_str(), handle, size, data.data())) { | if (!GetFileVersionInfoA(path.c_str(), handle, size, data.data())) { | ||
throw std::runtime_error("Failed to get version info."); | throw std::runtime_error("Failed to get version info."); | ||
} | } | ||
VS_FIXEDFILEINFO* versionInfo; | VS_FIXEDFILEINFO* versionInfo; | ||
UINT len; | UINT len; | ||
| 92行目: | 92行目: | ||
throw std::runtime_error("Failed to query version info."); | throw std::runtime_error("Failed to query version info."); | ||
} | } | ||
DWORD major = (versionInfo->dwFileVersionMS >> 16) & 0xffff; | DWORD major = (versionInfo->dwFileVersionMS >> 16) & 0xffff; | ||
DWORD minor = versionInfo->dwFileVersionMS & 0xffff; | DWORD minor = versionInfo->dwFileVersionMS & 0xffff; | ||
DWORD build = (versionInfo->dwFileVersionLS >> 16) & 0xffff; | DWORD build = (versionInfo->dwFileVersionLS >> 16) & 0xffff; | ||
DWORD revision = versionInfo->dwFileVersionLS & 0xffff; | DWORD revision = versionInfo->dwFileVersionLS & 0xffff; | ||
return std::to_string(major) + "." + | return std::to_string(major) + "." + | ||
std::to_string(minor) + "." + | std::to_string(minor) + "." + | ||
| 103行目: | 103行目: | ||
std::to_string(revision); | std::to_string(revision); | ||
} | } | ||
std::string GetHttpResponse(const std::wstring& host, const std::wstring& path) { | std::string GetHttpResponse(const std::wstring& host, const std::wstring& path) { | ||
HINTERNET session = WinHttpOpen(L"Downloader", WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, NULL, NULL, 0); | HINTERNET session = WinHttpOpen(L"Downloader", WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, NULL, NULL, 0); | ||
| 109行目: | 109行目: | ||
throw std::runtime_error("Failed to open WinHTTP session."); | throw std::runtime_error("Failed to open WinHTTP session."); | ||
} | } | ||
HINTERNET connect = WinHttpConnect(session, host.c_str(), INTERNET_DEFAULT_HTTPS_PORT, 0); | HINTERNET connect = WinHttpConnect(session, host.c_str(), INTERNET_DEFAULT_HTTPS_PORT, 0); | ||
if (!connect) { | if (!connect) { | ||
| 115行目: | 115行目: | ||
throw std::runtime_error("Failed to connect to host."); | throw std::runtime_error("Failed to connect to host."); | ||
} | } | ||
HINTERNET request = WinHttpOpenRequest(connect, L"GET", path.c_str(), NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE); | HINTERNET request = WinHttpOpenRequest(connect, L"GET", path.c_str(), NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE); | ||
if (!request) { | if (!request) { | ||
| 122行目: | 122行目: | ||
throw std::runtime_error("Failed to open HTTP request."); | throw std::runtime_error("Failed to open HTTP request."); | ||
} | } | ||
if (!WinHttpSendRequest(request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0)) { | if (!WinHttpSendRequest(request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0)) { | ||
WinHttpCloseHandle(request); | WinHttpCloseHandle(request); | ||
| 129行目: | 129行目: | ||
throw std::runtime_error("Failed to send HTTP request."); | throw std::runtime_error("Failed to send HTTP request."); | ||
} | } | ||
if (!WinHttpReceiveResponse(request, NULL)) { | if (!WinHttpReceiveResponse(request, NULL)) { | ||
WinHttpCloseHandle(request); | WinHttpCloseHandle(request); | ||
| 136行目: | 136行目: | ||
throw std::runtime_error("Failed to receive HTTP response."); | throw std::runtime_error("Failed to receive HTTP response."); | ||
} | } | ||
std::string response; | std::string response; | ||
DWORD downloaded = 0; | DWORD downloaded = 0; | ||
| 162行目: | 162行目: | ||
return response; | return response; | ||
} | } | ||
void Download(const std::wstring& url, const std::string& extractDir) { | void Download(const std::wstring& url, const std::string& extractDir) { | ||
HINTERNET session = WinHttpOpen(L"Downloader", WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, NULL, NULL, 0); | HINTERNET session = WinHttpOpen(L"Downloader", WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, NULL, NULL, 0); | ||
| 169行目: | 169行目: | ||
components.dwHostNameLength = -1; | components.dwHostNameLength = -1; | ||
components.dwUrlPathLength = -1; | components.dwUrlPathLength = -1; | ||
wchar_t host[256]; | wchar_t host[256]; | ||
wchar_t path[1024]; | wchar_t path[1024]; | ||
components.lpszHostName = host; | components.lpszHostName = host; | ||
components.lpszUrlPath = path; | components.lpszUrlPath = path; | ||
if (!WinHttpCrackUrl(url.c_str(), 0, 0, &components)) { | if (!WinHttpCrackUrl(url.c_str(), 0, 0, &components)) { | ||
throw std::runtime_error("Failed to parse URL."); | throw std::runtime_error("Failed to parse URL."); | ||
} | } | ||
HINTERNET connect = WinHttpConnect(session, components.lpszHostName, INTERNET_DEFAULT_HTTPS_PORT, 0); | HINTERNET connect = WinHttpConnect(session, components.lpszHostName, INTERNET_DEFAULT_HTTPS_PORT, 0); | ||
if (!connect) { | if (!connect) { | ||
| 185行目: | 185行目: | ||
throw std::runtime_error("Failed to connect to host."); | throw std::runtime_error("Failed to connect to host."); | ||
} | } | ||
HINTERNET request = WinHttpOpenRequest(connect, L"GET", components.lpszUrlPath, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE); | HINTERNET request = WinHttpOpenRequest(connect, L"GET", components.lpszUrlPath, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE); | ||
if (!request) { | if (!request) { | ||
| 192行目: | 192行目: | ||
throw std::runtime_error("Failed to open HTTP request."); | throw std::runtime_error("Failed to open HTTP request."); | ||
} | } | ||
if (!WinHttpSendRequest(request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0)) { | if (!WinHttpSendRequest(request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0)) { | ||
WinHttpCloseHandle(request); | WinHttpCloseHandle(request); | ||
| 199行目: | 199行目: | ||
throw std::runtime_error("Failed to send HTTP request."); | throw std::runtime_error("Failed to send HTTP request."); | ||
} | } | ||
if (!WinHttpReceiveResponse(request, NULL)) { | if (!WinHttpReceiveResponse(request, NULL)) { | ||
WinHttpCloseHandle(request); | WinHttpCloseHandle(request); | ||
| 206行目: | 206行目: | ||
throw std::runtime_error("Failed to receive HTTP response."); | throw std::runtime_error("Failed to receive HTTP response."); | ||
} | } | ||
DWORD size = 0; | DWORD size = 0; | ||
WinHttpQueryDataAvailable(request, &size); | WinHttpQueryDataAvailable(request, &size); | ||
std::vector<char> data; | std::vector<char> data; | ||
DWORD downloaded = 0; | DWORD downloaded = 0; | ||
| 224行目: | 224行目: | ||
downloaded += bytesRead; | downloaded += bytesRead; | ||
} while (true); | } while (true); | ||
std::filesystem::create_directory(extractDir); | std::filesystem::create_directory(extractDir); | ||
std::ofstream out(extractDir + "\\driver.zip", std::ios::binary); | std::ofstream out(extractDir + "\\driver.zip", std::ios::binary); | ||
out.write(data.data(), downloaded); | out.write(data.data(), downloaded); | ||
out.close(); | out.close(); | ||
WinHttpCloseHandle(request); | WinHttpCloseHandle(request); | ||
WinHttpCloseHandle(connect); | WinHttpCloseHandle(connect); | ||
WinHttpCloseHandle(session); | WinHttpCloseHandle(session); | ||
} | } | ||
std::string GetVersionFilePath(const std::string& browser, const std::string& version) { | std::string GetVersionFilePath(const std::string& browser, const std::string& version) { | ||
return browser + "_" + version; | return browser + "_" + version; | ||
} | } | ||
bool IsVersionDownloaded(const std::string& versionFilePath) { | bool IsVersionDownloaded(const std::string& versionFilePath) { | ||
return std::filesystem::exists(versionFilePath); | return std::filesystem::exists(versionFilePath); | ||
} | } | ||
void SaveVersionFile(const std::string& versionFilePath) { | void SaveVersionFile(const std::string& versionFilePath) { | ||
std::ofstream file(versionFilePath); | std::ofstream file(versionFilePath); | ||
| 250行目: | 250行目: | ||
} | } | ||
} | } | ||
void extractZip(const std::string& zipPath, const std::string& extractDir) { | void extractZip(const std::string& zipPath, const std::string& extractDir) { | ||
int zipError = 0; | int zipError = 0; | ||
// ZIPファイルを開く | // ZIPファイルを開く | ||
zip_t* zip = zip_open(zipPath.c_str(), 0, &zipError); | zip_t* zip = zip_open(zipPath.c_str(), 0, &zipError); | ||
| 259行目: | 260行目: | ||
return; | return; | ||
} | } | ||
// エントリ数を取得 | // エントリ数を取得 | ||
zip_int64_t num_entries = zip_get_num_entries(zip, 0); | zip_int64_t num_entries = zip_get_num_entries(zip, 0); | ||
| 269行目: | 270行目: | ||
continue; | continue; | ||
} | } | ||
// ファイル名をstd::stringに変換 | // ファイル名をstd::stringに変換 | ||
std::string entryName(name); | std::string entryName(name); | ||
// ファイル情報を取得 | // ファイル情報を取得 | ||
zip_stat_t stat; | zip_stat_t stat; | ||
| 279行目: | 280行目: | ||
continue; | continue; | ||
} | } | ||
// フルパスを作成 | // フルパスを作成 | ||
std::filesystem::path fullPath = std::filesystem::path(extractDir) / entryName; | std::filesystem::path fullPath = std::filesystem::path(extractDir) / entryName; | ||
// フォルダの場合、ディレクトリを作成 | // フォルダの場合、ディレクトリを作成 | ||
if (entryName.back() == '/') { // ZIP形式ではフォルダ名は末尾に'/'が付く | if (entryName.back() == '/') { // ZIP形式ではフォルダ名は末尾に'/'が付く | ||
| 288行目: | 289行目: | ||
continue; | continue; | ||
} | } | ||
// ファイルを開く | // ファイルを開く | ||
zip_file_t* zf = zip_fopen_index(zip, i, 0); | zip_file_t* zf = zip_fopen_index(zip, i, 0); | ||
| 295行目: | 296行目: | ||
continue; | continue; | ||
} | } | ||
// ファイル内容を読み込む | // ファイル内容を読み込む | ||
std::string contents(stat.size, '\0'); // std::stringでメモリ確保 | std::string contents(stat.size, '\0'); // std::stringでメモリ確保 | ||
| 303行目: | 304行目: | ||
continue; | continue; | ||
} | } | ||
// 親ディレクトリを作成(必要であれば) | // 親ディレクトリを作成(必要であれば) | ||
std::filesystem::create_directories(fullPath.parent_path()); | std::filesystem::create_directories(fullPath.parent_path()); | ||
// ファイルを保存 | // ファイルを保存 | ||
std::ofstream out(fullPath, std::ios::binary); | std::ofstream out(fullPath, std::ios::binary); | ||
| 316行目: | 317行目: | ||
out.write(contents.data(), contents.size()); | out.write(contents.data(), contents.size()); | ||
out.close(); | out.close(); | ||
// ファイルを閉じる | // ファイルを閉じる | ||
zip_fclose(zf); | zip_fclose(zf); | ||
} | } | ||
// ZIPファイルを閉じる | // ZIPファイルを閉じる | ||
zip_close(zip); | zip_close(zip); | ||
} | } | ||
void renameFile(const std::string& dirPath, const std::string& oldName, const std::string& newName) { | void renameFile(const std::string& dirPath, const std::string& oldName, const std::string& newName) { | ||
// 古いファイルのフルパス | // 古いファイルのフルパス | ||
std::filesystem::path oldFilePath = std::filesystem::path(dirPath) / oldName; | std::filesystem::path oldFilePath = std::filesystem::path(dirPath) / oldName; | ||
// 新しいファイルのフルパス | // 新しいファイルのフルパス | ||
std::filesystem::path newFilePath = std::filesystem::path(dirPath) / newName; | std::filesystem::path newFilePath = std::filesystem::path(dirPath) / newName; | ||
try { | try { | ||
// ファイル名を変更 | // ファイル名を変更 | ||
| 341行目: | 342行目: | ||
} | } | ||
} | } | ||
void deleteDirectory(const std::string& dirPath) { | void deleteDirectory(const std::string& dirPath) { | ||
try { | try { | ||
| 358行目: | 359行目: | ||
} | } | ||
} | } | ||
void copyAndRenameFile(const std::string& sourcePath, const std::string& destPath) { | void copyAndRenameFile(const std::string& sourcePath, const std::string& destPath) { | ||
try { | try { | ||
| 371行目: | 372行目: | ||
} | } | ||
} | } | ||
int main(int argc, char* argv[]) { | int main(int argc, char* argv[]) { | ||
if (argc < 2 || argv[1] == nullptr) { | if (argc < 2 || argv[1] == nullptr) { | ||
std::cerr << "起動引数1のブラウザの種別の指定がありません。edge or chrome" << std::endl; | std::cerr << "起動引数1のブラウザの種別の指定がありません。edge or chrome" << std::endl; | ||
return 1; | return 1; | ||
} | } | ||
if (argc < 3 || argv[2] == nullptr) { | if (argc < 3 || argv[2] == nullptr) { | ||
std::cerr << "起動引数2のWindowsユーザ名の指定がありません。" << std::endl; | std::cerr << "起動引数2のWindowsユーザ名の指定がありません。" << std::endl; | ||
| 386行目: | 387行目: | ||
std::string userId = argv[2]; | std::string userId = argv[2]; | ||
std::string baseDir = "C:\\Users\\" + userId + "\\AppData\\Local\\SeleniumBasic"; | std::string baseDir = "C:\\Users\\" + userId + "\\AppData\\Local\\SeleniumBasic"; | ||
std::string version; | std::string version; | ||
std::wstring driverUrl; | std::wstring driverUrl; | ||
std::string tempDir; | std::string tempDir; | ||
std::string outputPath; | std::string outputPath; | ||
try { | try { | ||
if (browser == "chrome") { | if (browser == "chrome") { | ||
| 404行目: | 405行目: | ||
//driverUrl = L"https://msedgedriver.azureedge.net/" + std::wstring(version.begin(), version.end()) + L"/edgedriver_win64.zip"; | //driverUrl = L"https://msedgedriver.azureedge.net/" + std::wstring(version.begin(), version.end()) + L"/edgedriver_win64.zip"; | ||
driverUrl = L"https://msedgedriver.microsoft.com/" + std::wstring(version.begin(), version.end()) + L"/edgedriver_win64.zip"; | driverUrl = L"https://msedgedriver.microsoft.com/" + std::wstring(version.begin(), version.end()) + L"/edgedriver_win64.zip"; | ||
tempDir = "edgedriver_temp"; | tempDir = "edgedriver_temp"; | ||
outputPath = baseDir + "\\edgedriver.exe"; | outputPath = baseDir + "\\edgedriver.exe"; | ||
| 413行目: | 414行目: | ||
return 1; | return 1; | ||
} | } | ||
std::string versionFilePath = GetVersionFilePath(browser, version); | std::string versionFilePath = GetVersionFilePath(browser, version); | ||
if (IsVersionDownloaded(versionFilePath)) { | if (IsVersionDownloaded(versionFilePath)) { | ||
std::cout << "Version " << version << " is already downloaded. Skipping download." << std::endl; | std::cout << "Version " << version << " is already downloaded. Skipping download." << std::endl; | ||
| 430行目: | 431行目: | ||
driverDir = tempDir + "\\driver"; | driverDir = tempDir + "\\driver"; | ||
extractZip(zipPath, driverDir); | extractZip(zipPath, driverDir); | ||
copyAndRenameFile(driverDir + (browser == "edge" ? "\\msedgedriver.exe" : "\\chromedriver.exe"), outputPath); | copyAndRenameFile(driverDir + (browser == "edge" ? "\\msedgedriver.exe" : "\\chromedriver.exe"), outputPath); | ||
FixFilename = browser + "driver_" + std::string(version.begin(), version.end()) + ".zip"; | FixFilename = browser + "driver_" + std::string(version.begin(), version.end()) + ".zip"; | ||
renameFile(tempDir, "driver.zip", FixFilename); | renameFile(tempDir, "driver.zip", FixFilename); | ||
| 442行目: | 443行目: | ||
return 1; | return 1; | ||
} | } | ||
return 0; | return 0; | ||
} | } | ||
2025年9月20日 (土) 01:16時点における版
VBA Edge制御 導入に戻る。
概要
msedgedriver.exeを自動で差し替えるコマンドプロンプトプログラムをC++言語でだらだら長めのコードになりましたが、作るには作りました。クラス化とかしてません。参考にして自分で組んでみて下さい。Chromeの対応はきっちりできていません。Chromeも同じようなやり方だと思うので、Chromeのdriverも答え合わせ的に直してみるといいかもしれない。つうかzlibとlibzipのビルドとかで手間取る。古いVisualStudio17 2022とかでやるとつまづく、最新のVisualStudio17 2022に更新した上でやるとうまく行く。
オープンソースのビルド zlib にビルド手順について記述があります。
からダウンロードして解凍して、zlibはフォルダ階層のトップ下のCMakeFile.txtのあるフォルダをVisual Studioで開いて、ビルドのインストールっていうのと(zlibのパス)\out\install\x64-Debug\includeの下のzconf.hを(zlibのパス)の直下にコピーして、あと、zlibvc.defファイルのVersionの記述の形式を3.1.3のようになっている場合は、3.13のように2個めのドットを外す形式に書き換えます。そしてビルドを実行するだけです。これで、zlibd.libとzlibd.dllとincludeディレクトリが生成されます。したらば次はlibzipも同じようにフォルダ階層のトップ下のCMakeFileをVisual Studioで開くんですけど、フォルダを開く前にCMakeFile.txtの中身を以下のように更新します。
cmake_minimum_required(VERSION 3.0.2)
set(ZLIB_ROOT C:/(zlibのパス)/)
set(LIB_INCLUDE_DIR C:/(zlibのパス)/out/install/x64-Debug/include)
set(ZLIB_LIBRARY_DEBUG C:/(zlibのパス)/out/install/x64-Debug/lib/zlibd.lib)
set(ZLIB_LIBRARY_RELEASE C:/(zlibのパス)/out/install/x64-Debug/lib/zlibd.lib)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
その上でフォルダを開いて、インストールとビルドをするとzip.libとzip.dllとインクルードディレクトリが生成されます。したらば、このzip.dllとzlibd.libを自分で作成するプロジェクトで実行ファイル.exeが生成されるフォルダに保存するのと、インクルードディレクトリに以下の追加します。
- インクルードディレクトリ
- C:\(libzipパス)\out\install\x64-Debug\include;
- ライブラリディレクトリ
- C:\(libzipパス)\out\install\x64-Debug\lib;
そして、以下のようにコードを作成します。
起動引数は第1がブラウザでedge or chromeです。第2がWindowsLoginUserIDを入れます。アドレスが変わったのと、最近のVisual Studioが新しくなって一部エラーになるようになったので、更新しました。
2025年09月中旬更新のプログラム
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <filesystem>
#include <windows.h>
#include <winhttp.h>
#include <typeinfo>
#include <zip.h>
#pragma comment(lib, "winhttp.lib")
#pragma comment(lib, "Version.lib")
#pragma comment(lib, "zip.lib")
std::string GetVersion(const std::string& path) {
DWORD handle;
DWORD size = GetFileVersionInfoSizeA(path.c_str(), &handle);
if (size == 0) {
throw std::runtime_error("Failed to get version info size.");
}
std::vector<char> data(size);
if (!GetFileVersionInfoA(path.c_str(), handle, size, data.data())) {
throw std::runtime_error("Failed to get version info.");
}
VS_FIXEDFILEINFO* versionInfo;
UINT len;
if (!VerQueryValueA(data.data(), "\\", (LPVOID*)&versionInfo, &len)) {
throw std::runtime_error("Failed to query version info.");
}
DWORD major = (versionInfo->dwFileVersionMS >> 16) & 0xffff;
DWORD minor = versionInfo->dwFileVersionMS & 0xffff;
DWORD build = (versionInfo->dwFileVersionLS >> 16) & 0xffff;
DWORD revision = versionInfo->dwFileVersionLS & 0xffff;
return std::to_string(major) + "." +
std::to_string(minor) + "." +
std::to_string(build) + "." +
std::to_string(revision);
}
std::string GetHttpResponse(const std::wstring& host, const std::wstring& path) {
HINTERNET session = WinHttpOpen(L"Downloader", WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, NULL, NULL, 0);
if (!session) {
throw std::runtime_error("Failed to open WinHTTP session.");
}
HINTERNET connect = WinHttpConnect(session, host.c_str(), INTERNET_DEFAULT_HTTPS_PORT, 0);
if (!connect) {
WinHttpCloseHandle(session);
throw std::runtime_error("Failed to connect to host.");
}
HINTERNET request = WinHttpOpenRequest(connect, L"GET", path.c_str(), NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
if (!request) {
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
throw std::runtime_error("Failed to open HTTP request.");
}
if (!WinHttpSendRequest(request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0)) {
WinHttpCloseHandle(request);
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
throw std::runtime_error("Failed to send HTTP request.");
}
if (!WinHttpReceiveResponse(request, NULL)) {
WinHttpCloseHandle(request);
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
throw std::runtime_error("Failed to receive HTTP response.");
}
std::string response;
DWORD downloaded = 0;
DWORD size = 0;
do {
if(!WinHttpQueryDataAvailable(request, &size) || size == 0){
break;
}
size_t oldSize = response.size();
response.resize(oldSize + size);
DWORD bytesRead = 0;
//std::string response(size, '\0');
//DWORD downloaded;
{
if (!WinHttpReadData(request, /*&response[0]*/ &response[oldSize], size, &bytesRead)){
WinHttpCloseHandle(request);
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
throw std::runtime_error("Failed to read HTTP response data.");
}
response.resize(oldSize + bytesRead);
downloaded += bytesRead;
}
} while (size > 0);
return response;
}
void Download(const std::wstring& url, const std::string& extractDir) {
HINTERNET session = WinHttpOpen(L"Downloader", WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, NULL, NULL, 0);
URL_COMPONENTS components = { 0 };
components.dwStructSize = sizeof(URL_COMPONENTS);
components.dwHostNameLength = -1;
components.dwUrlPathLength = -1;
wchar_t host[256];
wchar_t path[1024];
components.lpszHostName = host;
components.lpszUrlPath = path;
if (!WinHttpCrackUrl(url.c_str(), 0, 0, &components)) {
throw std::runtime_error("Failed to parse URL.");
}
HINTERNET connect = WinHttpConnect(session, components.lpszHostName, INTERNET_DEFAULT_HTTPS_PORT, 0);
if (!connect) {
WinHttpCloseHandle(session);
throw std::runtime_error("Failed to connect to host.");
}
HINTERNET request = WinHttpOpenRequest(connect, L"GET", components.lpszUrlPath, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
if (!request) {
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
throw std::runtime_error("Failed to open HTTP request.");
}
if (!WinHttpSendRequest(request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0)) {
WinHttpCloseHandle(request);
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
throw std::runtime_error("Failed to send HTTP request.");
}
if (!WinHttpReceiveResponse(request, NULL)) {
WinHttpCloseHandle(request);
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
throw std::runtime_error("Failed to receive HTTP response.");
}
DWORD size = 0;
WinHttpQueryDataAvailable(request, &size);
std::vector<char> data;
DWORD downloaded = 0;
do {
DWORD size = 0;
WinHttpQueryDataAvailable(request, &size);
if (size == 0) break;
std::vector<char> buffer(size);
DWORD bytesRead = 0;
if (!WinHttpReadData(request, buffer.data(), size, &bytesRead)) {
throw std::runtime_error("Failed to read HTTP response data.");
}
data.insert(data.end(), buffer.begin(), buffer.begin() + bytesRead);
downloaded += bytesRead;
} while (true);
std::filesystem::create_directory(extractDir);
std::ofstream out(extractDir + "\\driver.zip", std::ios::binary);
out.write(data.data(), downloaded);
out.close();
WinHttpCloseHandle(request);
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
}
std::string GetVersionFilePath(const std::string& browser, const std::string& version) {
return browser + "_" + version;
}
bool IsVersionDownloaded(const std::string& versionFilePath) {
return std::filesystem::exists(versionFilePath);
}
void SaveVersionFile(const std::string& versionFilePath) {
std::ofstream file(versionFilePath);
if (file) {
file << "Downloaded";
file.close();
}
}
void extractZip(const std::string& zipPath, const std::string& extractDir) {
int zipError = 0;
// ZIPファイルを開く
zip_t* zip = zip_open(zipPath.c_str(), 0, &zipError);
if (!zip) {
std::cerr << "Failed to open ZIP file. Error code: " << zipError << std::endl;
return;
}
// エントリ数を取得
zip_int64_t num_entries = zip_get_num_entries(zip, 0);
for (zip_int64_t i = 0; i < num_entries; i++) {
// ファイル名を取得
const char* name = zip_get_name(zip, i, 0);
if (!name) {
std::cerr << "Failed to get entry name for index " << i << std::endl;
continue;
}
// ファイル名をstd::stringに変換
std::string entryName(name);
// ファイル情報を取得
zip_stat_t stat;
if (zip_stat_index(zip, i, 0, &stat) == -1) {
std::cerr << "Failed to get entry stats for " << entryName << std::endl;
continue;
}
// フルパスを作成
std::filesystem::path fullPath = std::filesystem::path(extractDir) / entryName;
// フォルダの場合、ディレクトリを作成
if (entryName.back() == '/') { // ZIP形式ではフォルダ名は末尾に'/'が付く
std::filesystem::create_directories(fullPath);
continue;
}
// ファイルを開く
zip_file_t* zf = zip_fopen_index(zip, i, 0);
if (!zf) {
std::cerr << "Failed to open file inside ZIP: " << entryName << std::endl;
continue;
}
// ファイル内容を読み込む
std::string contents(stat.size, '\0'); // std::stringでメモリ確保
if (zip_fread(zf, &contents[0], stat.size) == -1) {
std::cerr << "Failed to read file: " << entryName << std::endl;
zip_fclose(zf);
continue;
}
// 親ディレクトリを作成(必要であれば)
std::filesystem::create_directories(fullPath.parent_path());
// ファイルを保存
std::ofstream out(fullPath, std::ios::binary);
if (!out) {
std::cerr << "Failed to write file: " << fullPath << std::endl;
zip_fclose(zf);
continue;
}
out.write(contents.data(), contents.size());
out.close();
// ファイルを閉じる
zip_fclose(zf);
}
// ZIPファイルを閉じる
zip_close(zip);
}
void renameFile(const std::string& dirPath, const std::string& oldName, const std::string& newName) {
// 古いファイルのフルパス
std::filesystem::path oldFilePath = std::filesystem::path(dirPath) / oldName;
// 新しいファイルのフルパス
std::filesystem::path newFilePath = std::filesystem::path(dirPath) / newName;
try {
// ファイル名を変更
std::filesystem::rename(oldFilePath, newFilePath);
std::cout << "File renamed from " << oldFilePath << " to " << newFilePath << std::endl;
}
catch (const std::filesystem::filesystem_error& e) {
std::cerr << "Error renaming file: " << e.what() << std::endl;
}
}
void deleteDirectory(const std::string& dirPath) {
try {
// 指定したディレクトリが存在するか確認
if (std::filesystem::exists(dirPath)) {
// 再帰的に削除
std::filesystem::remove_all(dirPath);
std::cout << "Deleted directory and contents: " << dirPath << std::endl;
}
else {
std::cerr << "Directory does not exist: " << dirPath << std::endl;
}
}
catch (const std::filesystem::filesystem_error& e) {
std::cerr << "Error deleting directory: " << e.what() << std::endl;
}
}
void copyAndRenameFile(const std::string& sourcePath, const std::string& destPath) {
try {
// コピー先の親ディレクトリを作成(存在しない場合)
std::filesystem::create_directories(std::filesystem::path(destPath).parent_path());
// ファイルをコピー
std::filesystem::copy_file(sourcePath, destPath, std::filesystem::copy_options::overwrite_existing);
std::cout << "File copied from " << sourcePath << " to " << destPath << std::endl;
}
catch (const std::filesystem::filesystem_error& e) {
std::cerr << "Error copying file: " << e.what() << std::endl;
}
}
int main(int argc, char* argv[]) {
if (argc < 2 || argv[1] == nullptr) {
std::cerr << "起動引数1のブラウザの種別の指定がありません。edge or chrome" << std::endl;
return 1;
}
if (argc < 3 || argv[2] == nullptr) {
std::cerr << "起動引数2のWindowsユーザ名の指定がありません。" << std::endl;
return 1;
}
std::string browser = argv[1];
std::string userId = argv[2];
std::string baseDir = "C:\\Users\\" + userId + "\\AppData\\Local\\SeleniumBasic";
std::string version;
std::wstring driverUrl;
std::string tempDir;
std::string outputPath;
try {
if (browser == "chrome") {
version = GetVersion("C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe");
std::wstring driverUrl = L"https://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_" + std::wstring(version.begin(), version.end());
tempDir = "chromedriver_temp";
outputPath = baseDir + "\\chromedriver.exe";
//DownloadAndExtract(driverUrl, tempDir, baseDir + "\\chromedriver.exe");
}
else if (browser == "edge") {
version = GetVersion("C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe");
//driverUrl = L"https://msedgedriver.azureedge.net/" + std::wstring(version.begin(), version.end()) + L"/edgedriver_win64.zip";
driverUrl = L"https://msedgedriver.microsoft.com/" + std::wstring(version.begin(), version.end()) + L"/edgedriver_win64.zip";
tempDir = "edgedriver_temp";
outputPath = baseDir + "\\edgedriver.exe";
//DownloadAndExtract(driverUrl, tempDir, baseDir + "\\edgedriver.exe", "msedgedriver.exe");
}
else {
std::cerr << "Unsupported browser: edge or chrome" << browser << std::endl;
return 1;
}
std::string versionFilePath = GetVersionFilePath(browser, version);
if (IsVersionDownloaded(versionFilePath)) {
std::cout << "Version " << version << " is already downloaded. Skipping download." << std::endl;
}
else {
Download(driverUrl, tempDir);
std::cout << "Download and extraction complete for version: " << version << std::endl;
SaveVersionFile(versionFilePath);
std::string zipPath;
std::string FixFilename;
std::string driverDir;
zipPath = tempDir + "\\driver.zip";
driverDir = tempDir + "\\driver";
extractZip(zipPath, driverDir);
copyAndRenameFile(driverDir + (browser == "edge" ? "\\msedgedriver.exe" : "\\chromedriver.exe"), outputPath);
FixFilename = browser + "driver_" + std::string(version.begin(), version.end()) + ".zip";
renameFile(tempDir, "driver.zip", FixFilename);
deleteDirectory(driverDir);
}
}
catch (const std::exception& ex) {
std::cerr << "Error: " << ex.what() << std::endl;
return 1;
}
return 0;
}
旧スクリプト
古いスクリプトはコチラ。すぐにはうごかない。
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <filesystem>
#include <windows.h>
#include <winhttp.h>
#include <typeinfo>
#include <zip.h>
#pragma comment(lib, "winhttp.lib")
#pragma comment(lib, "Version.lib")
#pragma comment(lib, "zip.lib")
std::string GetVersion(const std::string& path) {
DWORD handle;
DWORD size = GetFileVersionInfoSizeA(path.c_str(), &handle);
if (size == 0) {
throw std::runtime_error("Failed to get version info size.");
}
std::vector<char> data(size);
if (!GetFileVersionInfoA(path.c_str(), handle, size, data.data())) {
throw std::runtime_error("Failed to get version info.");
}
VS_FIXEDFILEINFO* versionInfo;
UINT len;
if (!VerQueryValueA(data.data(), "\\", (LPVOID*)&versionInfo, &len)) {
throw std::runtime_error("Failed to query version info.");
}
DWORD major = (versionInfo->dwFileVersionMS >> 16) & 0xffff;
DWORD minor = versionInfo->dwFileVersionMS & 0xffff;
DWORD build = (versionInfo->dwFileVersionLS >> 16) & 0xffff;
DWORD revision = versionInfo->dwFileVersionLS & 0xffff;
return std::to_string(major) + "." +
std::to_string(minor) + "." +
std::to_string(build) + "." +
std::to_string(revision);
}
std::string GetHttpResponse(const std::wstring& host, const std::wstring& path) {
HINTERNET session = WinHttpOpen(L"Downloader", WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, NULL, NULL, 0);
if (!session) {
throw std::runtime_error("Failed to open WinHTTP session.");
}
HINTERNET connect = WinHttpConnect(session, host.c_str(), INTERNET_DEFAULT_HTTPS_PORT, 0);
if (!connect) {
WinHttpCloseHandle(session);
throw std::runtime_error("Failed to connect to host.");
}
HINTERNET request = WinHttpOpenRequest(connect, L"GET", path.c_str(), NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
if (!request) {
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
throw std::runtime_error("Failed to open HTTP request.");
}
if (!WinHttpSendRequest(request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0)) {
WinHttpCloseHandle(request);
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
throw std::runtime_error("Failed to send HTTP request.");
}
if (!WinHttpReceiveResponse(request, NULL)) {
WinHttpCloseHandle(request);
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
throw std::runtime_error("Failed to receive HTTP response.");
}
DWORD size = 0;
WinHttpQueryDataAvailable(request, &size);
std::string response(size, '\0');
DWORD downloaded;
WinHttpReadData(request, /*&response[0]*/ response.data(), size, &downloaded);
WinHttpCloseHandle(request);
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
return response;
}
void Download(const std::wstring& url, const std::string& extractDir) {
HINTERNET session = WinHttpOpen(L"Downloader", WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, NULL, NULL, 0);
URL_COMPONENTS components = { 0 };
components.dwStructSize = sizeof(URL_COMPONENTS);
components.dwHostNameLength = -1;
components.dwUrlPathLength = -1;
wchar_t host[256];
wchar_t path[1024];
components.lpszHostName = host;
components.lpszUrlPath = path;
if (!WinHttpCrackUrl(url.c_str(), 0, 0, &components)) {
throw std::runtime_error("Failed to parse URL.");
}
HINTERNET connect = WinHttpConnect(session, components.lpszHostName, INTERNET_DEFAULT_HTTPS_PORT, 0);
if (!connect) {
WinHttpCloseHandle(session);
throw std::runtime_error("Failed to connect to host.");
}
HINTERNET request = WinHttpOpenRequest(connect, L"GET", components.lpszUrlPath, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
if (!request) {
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
throw std::runtime_error("Failed to open HTTP request.");
}
if (!WinHttpSendRequest(request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0)) {
WinHttpCloseHandle(request);
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
throw std::runtime_error("Failed to send HTTP request.");
}
if (!WinHttpReceiveResponse(request, NULL)) {
WinHttpCloseHandle(request);
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
throw std::runtime_error("Failed to receive HTTP response.");
}
DWORD size = 0;
WinHttpQueryDataAvailable(request, &size);
std::vector<char> data;
DWORD downloaded = 0;
do {
DWORD size = 0;
WinHttpQueryDataAvailable(request, &size);
if (size == 0) break;
std::vector<char> buffer(size);
DWORD bytesRead = 0;
if (!WinHttpReadData(request, buffer.data(), size, &bytesRead)) {
throw std::runtime_error("Failed to read HTTP response data.");
}
data.insert(data.end(), buffer.begin(), buffer.begin() + bytesRead);
downloaded += bytesRead;
} while (true);
std::filesystem::create_directory(extractDir);
std::ofstream out(extractDir + "\\driver.zip", std::ios::binary);
out.write(data.data(), downloaded);
out.close();
WinHttpCloseHandle(request);
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
}
std::string GetVersionFilePath(const std::string& browser, const std::string& version) {
return browser + "_" + version;
}
bool IsVersionDownloaded(const std::string& versionFilePath) {
return std::filesystem::exists(versionFilePath);
}
void SaveVersionFile(const std::string& versionFilePath) {
std::ofstream file(versionFilePath);
if (file) {
file << "Downloaded";
file.close();
}
}
void extractZip(const std::string& zipPath, const std::string& extractDir) {
int zipError = 0;
// ZIPファイルを開く
zip_t* zip = zip_open(zipPath.c_str(), 0, &zipError);
if (!zip) {
std::cerr << "Failed to open ZIP file. Error code: " << zipError << std::endl;
return;
}
// エントリ数を取得
zip_int64_t num_entries = zip_get_num_entries(zip, 0);
for (zip_int64_t i = 0; i < num_entries; i++) {
// ファイル名を取得
const char* name = zip_get_name(zip, i, 0);
if (!name) {
std::cerr << "Failed to get entry name for index " << i << std::endl;
continue;
}
// ファイル名をstd::stringに変換
std::string entryName(name);
// ファイル情報を取得
zip_stat_t stat;
if (zip_stat_index(zip, i, 0, &stat) == -1) {
std::cerr << "Failed to get entry stats for " << entryName << std::endl;
continue;
}
// フルパスを作成
std::filesystem::path fullPath = std::filesystem::path(extractDir) / entryName;
// フォルダの場合、ディレクトリを作成
if (entryName.back() == '/') { // ZIP形式ではフォルダ名は末尾に'/'が付く
std::filesystem::create_directories(fullPath);
continue;
}
// ファイルを開く
zip_file_t* zf = zip_fopen_index(zip, i, 0);
if (!zf) {
std::cerr << "Failed to open file inside ZIP: " << entryName << std::endl;
continue;
}
// ファイル内容を読み込む
std::string contents(stat.size, '\0'); // std::stringでメモリ確保
if (zip_fread(zf, &contents[0], stat.size) == -1) {
std::cerr << "Failed to read file: " << entryName << std::endl;
zip_fclose(zf);
continue;
}
// 親ディレクトリを作成(必要であれば)
std::filesystem::create_directories(fullPath.parent_path());
// ファイルを保存
std::ofstream out(fullPath, std::ios::binary);
if (!out) {
std::cerr << "Failed to write file: " << fullPath << std::endl;
zip_fclose(zf);
continue;
}
out.write(contents.data(), contents.size());
out.close();
// ファイルを閉じる
zip_fclose(zf);
}
// ZIPファイルを閉じる
zip_close(zip);
}
void renameFile(const std::string& dirPath, const std::string& oldName, const std::string& newName) {
// 古いファイルのフルパス
std::filesystem::path oldFilePath = std::filesystem::path(dirPath) / oldName;
// 新しいファイルのフルパス
std::filesystem::path newFilePath = std::filesystem::path(dirPath) / newName;
try {
// ファイル名を変更
std::filesystem::rename(oldFilePath, newFilePath);
std::cout << "File renamed from " << oldFilePath << " to " << newFilePath << std::endl;
}
catch (const std::filesystem::filesystem_error& e) {
std::cerr << "Error renaming file: " << e.what() << std::endl;
}
}
void deleteDirectory(const std::string& dirPath) {
try {
// 指定したディレクトリが存在するか確認
if (std::filesystem::exists(dirPath)) {
// 再帰的に削除
std::filesystem::remove_all(dirPath);
std::cout << "Deleted directory and contents: " << dirPath << std::endl;
}
else {
std::cerr << "Directory does not exist: " << dirPath << std::endl;
}
}
catch (const std::filesystem::filesystem_error& e) {
std::cerr << "Error deleting directory: " << e.what() << std::endl;
}
}
void copyAndRenameFile(const std::string& sourcePath, const std::string& destPath) {
try {
// コピー先の親ディレクトリを作成(存在しない場合)
std::filesystem::create_directories(std::filesystem::path(destPath).parent_path());
// ファイルをコピー
std::filesystem::copy_file(sourcePath, destPath, std::filesystem::copy_options::overwrite_existing);
std::cout << "File copied from " << sourcePath << " to " << destPath << std::endl;
}
catch (const std::filesystem::filesystem_error& e) {
std::cerr << "Error copying file: " << e.what() << std::endl;
}
}
int main(int argc, char* argv[]) {
if (argc < 2 || argv[1] == nullptr) {
std::cerr << "起動引数1のブラウザの種別の指定がありません。edge or chrome" << std::endl;
return 1;
}
if (argc < 3 || argv[2] == nullptr) {
std::cerr << "起動引数2のWindowsユーザ名の指定がありません。" << std::endl;
return 1;
}
std::string browser = argv[1];
std::string userId = argv[2];
std::string baseDir = "C:\\Users\\" + userId + "\\AppData\\Local\\SeleniumBasic";
std::string version;
std::wstring driverUrl;
std::string tempDir;
std::string outputPath;
try {
if (browser == "chrome") {
version = GetVersion("C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe");
std::wstring driverUrl = L"https://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_" + std::wstring(version.begin(), version.end());
tempDir = "chromedriver_temp";
outputPath = baseDir + "\\chromedriver.exe";
//DownloadAndExtract(driverUrl, tempDir, baseDir + "\\chromedriver.exe");
}
else if (browser == "edge") {
version = GetVersion("C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe");
driverUrl = L"https://msedgedriver.azureedge.net/" + std::wstring(version.begin(), version.end()) + L"/edgedriver_win64.zip";
tempDir = "edgedriver_temp";
outputPath = baseDir + "\\edgedriver.exe";
//DownloadAndExtract(driverUrl, tempDir, baseDir + "\\edgedriver.exe", "msedgedriver.exe");
}
else {
std::cerr << "Unsupported browser: edge or chrome" << browser << std::endl;
return 1;
}
std::string versionFilePath = GetVersionFilePath(browser, version);
if (IsVersionDownloaded(versionFilePath)) {
std::cout << "Version " << version << " is already downloaded. Skipping download." << std::endl;
}
else {
Download(driverUrl, tempDir);
std::cout << "Download and extraction complete for version: " << version << std::endl;
SaveVersionFile(versionFilePath);
std::string zipPath;
std::string FixFilename;
std::string driverDir;
zipPath = tempDir + "\\driver.zip";
driverDir = tempDir + "\\driver";
extractZip(zipPath, driverDir);
copyAndRenameFile(driverDir + (browser == "edge" ? "\\msedgedriver.exe" : "\\chromedriver.exe"), outputPath);
FixFilename = browser + "driver_" + std::string(version.begin(), version.end()) + ".zip";
renameFile(tempDir, "driver.zip", FixFilename);
deleteDirectory(driverDir);
}
}
catch (const std::exception& ex) {
std::cerr << "Error: " << ex.what() << std::endl;
return 1;
}
return 0;
}
VBA Edge制御 導入に戻る。