スポンサーリンク

Windowsでファイルからそれを開くアプリケーションを特定して開く

AssocQueryStringWを使ってファイルの拡張子または存在するファイルから関連付けられたアプリケーションを特定できる。

使用例

#include <iostream>

#include <windows.h>
#include <shlwapi.h>
#include <string>
#include <vector>

#pragma comment(lib, "shlwapi.lib")

std::wstring CallAssocQueryString(const std::wstring& filepath, ASSOCSTR str) {


    DWORD len = 0;
    // まずは、必要なバッファサイズを取得
    // lenにはnull終端を含む文字列の長さが返される
    HRESULT hr = AssocQueryStringW(
        ASSOCF_NONE,
        str,
        filepath.c_str(), // 拡張子".txt"等、 または存在するファイルパス
        nullptr,
        nullptr,// 結果を格納するバッファを指定するが、先にサイズを取得するためnullptrを指定
        &len    // 結果を格納するのに必要なバッファサイズを取得
    );

    if (hr != S_OK && hr != S_FALSE) {
        std::wcerr << L"AssocQueryStringW failed with error: " << hr << std::endl;
        return L"";
    }

    // バッファサイズがわかったので、結果を格納するバッファを確保
    std::vector<wchar_t> appPath(len , L'\0');

    hr = AssocQueryStringW(
        ASSOCF_NONE,
        str,
        filepath.c_str(),
        nullptr,
        &appPath[0],
        &len
    );

    return std::wstring(appPath.data());

}
int main() {


    std::wstring target = L".sln";

    // 拡張子から関連付けられたアプリケーションのパスを取得
    std::wstring appPath = CallAssocQueryString(target, ASSOCSTR_EXECUTABLE);
    std::wcout << appPath << std::endl;

    // 関連付けられたアプリケーションの表示名を取得。
    // ただし登録されていない場合も多いので、必ずしも取得できるとは限らない。
    std::wstring appName = CallAssocQueryString(target, ASSOCSTR_FRIENDLYAPPNAME);
    std::wcout << appName << std::endl;

    // 関連付けられたアプリケーションの実行コマンドを取得
    std::wstring appCommand = CallAssocQueryString(target, ASSOCSTR_COMMAND);
    std::wcout << appCommand << std::endl;

    return 0;
    
}

実行結果

C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\devenv.exe
Microsoft Visual Studio 2022
"C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\devenv.exe" "%1"

CreateProcessで関連付けられたアプリケーションを実行

windowsではアプリケーションの第一引数にファイルを与えるのが一般的らしいのでASSOCSTR_EXECUTABLEで取得した アプリケーションのパス + ファイルパスでもいいが、より確実にはASSOCSTR_COMMANDで取得した実行コマンドの %1 の部分をファイルパスに置換した方が確実。

#include <iostream>

#include <windows.h>
#include <shlwapi.h>
#include <string>
#include <vector>
#include <regex>

#pragma comment(lib, "shlwapi.lib")

std::wstring CallAssocQueryString(const std::wstring& filepath, ASSOCSTR str) {


    DWORD len = 0;
    // まずは、必要なバッファサイズを取得
    // lenにはnull終端を含む文字列の長さが返される
    HRESULT hr = AssocQueryStringW(
        ASSOCF_NONE,
        str,
        filepath.c_str(), // 拡張子".txt"等、 または存在するファイルパス
        nullptr,
        nullptr,// 結果を格納するバッファを指定するが、先にサイズを取得するためnullptrを指定
        &len    // 結果を格納するのに必要なバッファサイズを取得
    );

    if (hr != S_OK && hr != S_FALSE) {
        std::wcerr << L"AssocQueryStringW failed with error: " << hr << std::endl;
        return L"";
    }

    // バッファサイズがわかったので、結果を格納するバッファを確保
    std::vector<wchar_t> appPath(len , L'\0');

    hr = AssocQueryStringW(
        ASSOCF_NONE,
        str,
        filepath.c_str(),
        nullptr,
        &appPath[0],
        &len
    );

    return std::wstring(appPath.data());

}
int main() {


    std::wstring target = LR"(C:\test\test.txt)";

    // 関連付けられたアプリケーションの実行コマンドを取得
    std::wstring appCommand = CallAssocQueryString(target, ASSOCSTR_COMMAND);
    std::wcout << appCommand << std::endl;
    // appCommandは、"C:\Path\To\App.exe" "%1" のような形式

    // "%1"をファイルパスに置き換えるとApp.exeでファイルを開ける

    std::wregex percent1_pattern(LR"((\"?)%1(\"?))"); // %1 または "%1" にマッチ
    std::wstring quoted_path = L"\"" + target + L"\"";
    std::wstring command = std::regex_replace(appCommand, percent1_pattern, quoted_path);

    std::wcout << "Command: " << command << std::endl;

    STARTUPINFOW si = { sizeof(si) };
    PROCESS_INFORMATION pi;

    BOOL ret = CreateProcessW(
        nullptr,
        &command[0], // 開きたいファイルを含むコマンド
        nullptr,
        nullptr,
        FALSE,
        CREATE_UNICODE_ENVIRONMENT,
        nullptr,
        nullptr,
        &si,
        &pi
    );

    return 0;
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: