C++によるBingデスクトップ壁紙自動取得と設定の実装

必要なライブラリと環境:

  • vcpkgパッケージマネージャー
  • libcurl(HTTP通信用)
  • cJSON(JSON解析用)
  • Visual Studio 2022

実装の流れ

Bingの毎日更新される壁紙を自動で取得し、Windowsのデスクトップ背景に設定するプログラムを作成する。まず、Bingが提供している画像取得APIにアクセスする。

APIエンドポイント: https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=zh-CN

このAPIにリクエストを送ると、画像のメタデータを含むJSONが返される。JSONの中からimages配列の最初の要素にあるurlフィールドを抽出し、ホスト名と結合すれば画像の完全URLが得られる。例: https://bing.com/th?id=OHR.HummingThistle_ZH-CN5057589905_1920x1080.jpg

その後、画像URLへリクエストを送りバイナリデータをファイルに保存し、最後にWindows APIを用いてデスクトップ壁紙を変更する。

実装コード

#include <iostream>
#include <string>
#include <ctime>
#include <curl/curl.h>
#include <cJSON/cJSON.h>
#include <Windows.h>
#include <direct.h>
#include <io.h>

// JSONレスポンスを収集するコールバック
size_t collectJsonData(void* contents, size_t elementSize, size_t elementCount, void* userData) {
    std::string* collectedStr = static_cast<std::string*>(userData);
    collectedStr->append(static_cast<char*>(contents), elementSize * elementCount);
    return elementSize * elementCount;
}

// 画像データをファイルに書き込むコールバック
size_t saveImageData(void* contents, size_t elementSize, size_t elementCount, void* fileHandle) {
    FILE* output = static_cast<FILE*>(fileHandle);
    fwrite(contents, elementSize, elementCount, output);
    return elementSize * elementCount;
}

// Bing APIから画像URLを抽出
std::string fetchWallpaperUrl() {
    const std::string apiEndpoint = "https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&uhd=1&uhdwidth=3840&uhdheight=2160&mkt=zh-CN";
    std::string jsonResponse;

    CURL* session = curl_easy_init();
    if (!session) return "";

    curl_easy_setopt(session, CURLOPT_URL, apiEndpoint.c_str());
    curl_easy_setopt(session, CURLOPT_WRITEFUNCTION, collectJsonData);
    curl_easy_setopt(session, CURLOPT_WRITEDATA, &jsonResponse);
    curl_easy_perform(session);
    curl_easy_cleanup(session);

    cJSON* root = cJSON_Parse(jsonResponse.c_str());
    cJSON* imageArr = cJSON_GetObjectItem(root, "images");
    cJSON* firstItem = cJSON_GetArrayItem(imageArr, 0);
    cJSON* urlField = cJSON_GetObjectItem(firstItem, "url");

    std::string fullUrl = "https://bing.com" + std::string(urlField->valuestring);
    cJSON_Delete(root);

    return fullUrl;
}

// 日付ベースのファイルパス生成
std::string generateFilePath() {
    time_t currentTime;
    time(&currentTime);
    struct tm localTime;
    localtime_s(&localTime, &currentTime);

    std::string fileName = "wallpapers/bing-"
        + std::to_string(localTime.tm_year + 1900) + "-"
        + std::to_string(localTime.tm_mon + 1) + "-"
        + std::to_string(localTime.tm_mday) + ".jpg";
    return fileName;
}

// 保存ディレクトリの準備とファイルオープン
FILE* prepareOutputFile() {
    std::string filePath = generateFilePath();

    if (_access("wallpapers", 0) == -1) {
        _mkdir("wallpapers");
        std::cout << "wallpapersディレクトリを作成しました" << std::endl;
    }

    FILE* filePtr;
    if (fopen_s(&filePtr, filePath.c_str(), "wb") != 0) {
        std::cout << "ファイルオープン失敗" << std::endl;
        return nullptr;
    }
    std::cout << "ファイルオープン成功、ダウンロード開始" << std::endl;
    return filePtr;
}

// 壁紙画像のダウンロード
bool downloadWallpaper(const std::string& imageUrl) {
    FILE* targetFile = prepareOutputFile();
    if (!targetFile) return false;

    CURL* session = curl_easy_init();
    curl_easy_setopt(session, CURLOPT_URL, imageUrl.c_str());
    curl_easy_setopt(session, CURLOPT_WRITEFUNCTION, saveImageData);
    curl_easy_setopt(session, CURLOPT_WRITEDATA, targetFile);
    curl_easy_perform(session);
    curl_easy_cleanup(session);

    fclose(targetFile);
    std::cout << "ダウンロード完了、壁紙設定開始" << std::endl;
    return true;
}

// デスクトップ壁紙の変更
void applyDesktopWallpaper() {
    char currentPath[MAX_PATH];
    getcwd(currentPath, MAX_PATH);
    std::string imagePath = std::string(currentPath) + "\\" + generateFilePath();

    std::cout << "画像パス: " << imagePath << std::endl;
    SystemParametersInfoA(SPI_SETDESKWALLPAPER, 0,
        (PVOID)imagePath.c_str(), SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
    std::cout << "壁紙設定完了" << std::endl;
}

int main() {
    std::string imgUrl = fetchWallpaperUrl();
    if (downloadWallpaper(imgUrl)) {
        applyDesktopWallpaper();
    }
    return 0;
}

タグ: C++ libcurl cJSON WindowsAPI BingWallpaper

7月27日 23:24 投稿