カタバミさんのプログラミングノート

日曜プログラマーがプログラミング関係のメモを記録するブログです。

C++&ATLでフォルダのファイル名の最大長を取得する

概要

Windows 10でC++&ATLでフォルダのファイル名の最大長を取得するには次の手順を踏みます。具体的なサンプルコード等は後に示します。

  1. COMを初期化する。
  2. デスクトップのIShellFolderインターフェイスを取得する。
  3. ファイル名の最大長を取得したいフォルダ(目的フォルダ)のLPITEMIDLISTを取得する。
  4. デスクトップのIShellFolderインターフェイスから目的フォルダのIShellFolderインターフェイスを取得する。
  5. 目的フォルダのIShellFolderインターフェイスをIItemNameLimitsインターフェイスに変換する。
  6. IItemNameLimitsインターフェイスのGetMaxLengthメソッドを呼び出す。

サンプルコード

C++言語で空のWindows デスクトッププロジェクト(またはコンソールプロジェクト)を作成して、適当なcppファイルに以下のコードを記述して実行してください。

#define STRICT
#include <Windows.h>
#include <ShlObj.h>
#include <atlbase.h>
#include <atlcom.h>

CComPtr<IItemNameLimits> CreateDesktopItemNameLimits()
{
    CComPtr<IShellFolder> desktop;
    auto hr = SHGetDesktopFolder(&desktop);
    if (FAILED(hr))
        throw new CAtlException(hr);
    return CComQIPtr<IItemNameLimits>(desktop);
}

CComPtr<IItemNameLimits> CreateKnownFolderItemNameLimits(
    const REFKNOWNFOLDERID knownFolderId)
{
    CComPtr<IShellFolder> desktop;
    auto hr = SHGetDesktopFolder(&desktop);
    if (FAILED(hr))
        throw new CAtlException(hr);

    CComHeapPtr<ITEMIDLIST> idl;
    hr = SHGetKnownFolderIDList(knownFolderId, 0, nullptr, &idl);
    if (FAILED(hr))
        throw new CAtlException(hr);

    CComPtr<IShellFolder> knownFolder;
    hr = desktop->BindToObject(idl, nullptr, IID_PPV_ARGS(&knownFolder));
    if (FAILED(hr))
        throw new CAtlException(hr);
    return CComQIPtr<IItemNameLimits>(knownFolder);
}

HRESULT Run()
{
    try
    {
        auto desktopItemNameLimits = CreateDesktopItemNameLimits();
        auto startMenuItemNameLimits = CreateKnownFolderItemNameLimits(
            FOLDERID_StartMenu);

        WCHAR name[1] = {L'\0'};
        int maxDesktopItemNameLen;
        int maxStartMenuItemNameLen;
        auto hr = desktopItemNameLimits->GetMaxLength(name, &maxDesktopItemNameLen);
        if (FAILED(hr))
            return hr;
        hr = startMenuItemNameLimits->GetMaxLength(name, &maxStartMenuItemNameLen);
        if (FAILED(hr))
            return hr;

        // TODO:ここでデスクトップとスタートメニューのファイル名の最大長を処理します。

        return S_OK;
    }
    catch (CAtlException& ex)
    {
        return ex.m_hr;
    }
}

int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
{
    auto hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
    if (SUCCEEDED(hr))
    {
        hr = Run();
        CoUninitialize();
    }
    return hr;
}

補足説明

デスクトップのIShellFolderインターフェイスをCComPtrクラスで受け取る

CComPtrクラスは&演算子オーバーロードしており、&<var>で内部に保持するポインタのポインタを返します。したがって、SHGetDesktopFolder関数に&<var>を渡すことでCComPtrクラスにデスクトップのIShellFolderインターフェイスを受け取ることができます。

特殊フォルダのIShellFolderインターフェイスを取得する方法

デスクトップのIShellFolderインターフェイスのBindToObjectメソッドにより取得することができます。

IShellFolderインターフェイスをIItemNameLimitsインターフェイスに変換する

素直に変換する場合はQueryInterfaceメソッドを使用します。ATLを使用する場合はCComQIPtrのコンストラクタに引数として渡すだけで変換できます。