potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。はてなブログ無料版なので記事の上の方はたぶん広告です。記事中にも広告挿入されるみたいです。

Power Query M 型は比較方法により結果が異なる

要約

  • Power Query Mは型の比較に=Type.Is関数がある。
  • =は完全一致。Type.Isは互換性の判定。
  • (type number = type number) = true(type number = Int64.Type) = false

本文

[
    A=type number=type number,              // true
    B=type number=Int64.Type,               // false
    C=Type.Is(type number, type number),    // true
    D=Type.Is(type number, Int64.Type)      // true
]

C# 10&WinForms AutoScrollによるスクロールバーのスクロールを即座に反映する

ScrollableControlAutoScrollScrollイベントの組み合わせでスクロールを即座に反映できます。FlowLayoutPanelの縦スクロールであれば次のようになります。

private void flowLayoutPanel1_Scroll(object sender, ScrollEventArgs e)
{
    if (e.ScrollOrientation != ScrollOrientation.VerticalScroll)
        return;
    flowLayoutPanel1.VerticalScroll.Value = e.NewValue;
}

C++20&Win API WICコンポーネントの情報を取得する

Windowsイメージングコンポーネント(WIC、Windows Imaging Component)(Microsoft Docs)のWICコンポーネントの情報を取得するサンプルコードです。基本的な流れは「IWICImagingFactoryの作成→CreateComponentEnumeratorでIEnumUnknownを作成→IEnumUnknownで取得したIUnknownをIWICComponentInfoに変換→IWICComponentInfoから情報を取得」です。

すべてのWICコンポーネントの情報を取得する

#include <format>
#include <string>
#include <iostream>

#define STRICT
#define NOMINMAX
#include <Windows.h>
// https://docs.microsoft.com/en-us/windows/win32/api/wincodec/
#include <wincodec.h>
#pragma comment(lib, "WindowsCodecs.lib")

// 文字列から常にnullでない文字列ポインタを返します。
// 文字列がnullptrの場合は空文字列L""のポインタを返します。
constexpr const wchar_t* strptr_notnull(std::wstring_view s) noexcept
{
    return s.empty() ? L"" : s.data();
}

// GUIDからstd::wstringを返します。
// 変換に失敗した場合、空のstd::wstringを返します。
std::wstring GUIDToWString(REFGUID guid)
{
    std::wstring s(38, L'\0');
    if (StringFromGUID2(guid, s.data(), 39) == 0)
        return {};
    return std::move(s);
}

// IWICComponentInfo::GetFriendlyNameメソッドの結果をstd::wstringで返します。
// 失敗時は空のstd::wstringを返します。
std::wstring GetFriendlyName(IWICComponentInfo* info)
{
    UINT actualLen;
    if (SUCCEEDED(info->GetFriendlyName(0, nullptr, &actualLen)))
    {
        if (actualLen == 0) return L"";
        std::wstring s(actualLen - 1, L'\0');
        if (SUCCEEDED(info->GetFriendlyName(actualLen, s.data(), &actualLen)))
        {
            return std::move(s);
        }
    }
    return {};
}

// IWICComponentInfo::GetAuthorメソッドの結果をstd::wstringで返します。
// 失敗時は空のstd::wstringを返します。
std::wstring GetAuthor(IWICComponentInfo* info)
{
    UINT actualLen;
    if (SUCCEEDED(info->GetAuthor(0, nullptr, &actualLen)))
    {
        if (actualLen == 0) return L"";
        std::wstring s(actualLen - 1, L'\0');
        if (SUCCEEDED(info->GetAuthor(actualLen, s.data(), &actualLen)))
        {
            return std::move(s);
        }
    }
    return {};
}

// IWICComponentInfo::GetSpecVersionメソッドの結果をstd::wstringで返します。
// 失敗時は空のstd::wstringを返します。
std::wstring GetSpecVersion(IWICComponentInfo* info)
{
    UINT actualLen;
    if (SUCCEEDED(info->GetSpecVersion(0, nullptr, &actualLen)))
    {
        if (actualLen == 0) return L"";
        std::wstring s(actualLen - 1, L'\0');
        if (SUCCEEDED(info->GetSpecVersion(actualLen, s.data(), &actualLen)))
        {
            return std::move(s);
        }
    }
    return {};
}

// IWICComponentInfo::GetVersionメソッドの結果をstd::wstringで返します。
// 失敗時は空のstd::wstringを返します。
std::wstring GetVersion(IWICComponentInfo* info)
{
    UINT actualLen;
    if (SUCCEEDED(info->GetVersion(0, nullptr, &actualLen)))
    {
        if (actualLen == 0) return L"";
        std::wstring s(actualLen - 1, L'\0');
        if (SUCCEEDED(info->GetVersion(actualLen, s.data(), &actualLen)))
        {
            return std::move(s);
        }
    }
    return {};
}

// WICComponentType型の値をstd::wstring_viewで返します。
// 対応する値が存在しない場合はdefaultString引数の値を返します。既定値は空のstd::wstringです。
std::wstring_view ToWStringView(
    WICComponentType value,
    std::wstring_view defaultString = {})
{
    switch (value) {
    case WICDecoder: return L"WICDecoder";
    case WICEncoder: return L"WICEncoder";
    case WICPixelFormatConverter: return L"WICPixelFormatConverter";
    case WICMetadataReader: return L"WICMetadataReader";
    case WICMetadataWriter: return L"WICMetadataWriter";
    case WICPixelFormat: return L"WICPixelFormat";
    case WICAllComponents: return L"WICAllComponents";
    default: return defaultString;
    }
}

// WICComponentSigning型の値をstd::wstring_viewで返します。
// 対応する値が存在しない場合はdefaultString引数の値を返します。既定値は空のstd::wstringです。
std::wstring_view ToWStringView(
    WICComponentSigning value,
    std::wstring_view defaultString = {})
{
    switch (value) {
    case WICComponentSigned: return L"WICComponentSigned";
    case WICComponentUnsigned: return L"WICComponentUnsigned";
    case WICComponentSafe: return L"WICComponentSafe";
    case WICComponentDisabled: return L"WICComponentDisabled";
    default: return defaultString;
    }
}

int wmain()
{
    // 日本語の出力設定(内部変換の設定)
    std::wcout.imbue(std::locale("", std::locale::ctype));

    // COMの初期化
    if (FAILED(::CoInitializeEx(nullptr, COINIT::COINIT_APARTMENTTHREADED)))
        return -1;

    // IWICImagingFactoryの作成
    // https://docs.microsoft.com/en-us/windows/win32/api/wincodec/nn-wincodec-iwicimagingfactory
    IWICImagingFactory* pWicImagingFactory;
    if (SUCCEEDED(::CoCreateInstance(
        CLSID_WICImagingFactory,
        nullptr,
        CLSCTX_INPROC_SERVER,
        IID_PPV_ARGS(&pWicImagingFactory))))
    {
        // WICコンポーネント列挙インターフェイス(IEnumUnknown)の作成
        IEnumUnknown* pEnumUnknown;
        if (SUCCEEDED(pWicImagingFactory->CreateComponentEnumerator(
            WICComponentType::WICAllComponents,
            WICComponentEnumerateOptions::WICComponentEnumerateDefault,
            &pEnumUnknown)))
        {
            std::wcout << L"FriendlyName, Author, Version, SpecVersion, CLSID, VendorGUID, SigningStatus" << std::endl;

            // コンポーネント情報の取得
            // IUnknownで取得後、IWICComponentInfoに変換します。
            IUnknown* punkWicComponentInfo;
            while (pEnumUnknown->Next(1, &punkWicComponentInfo, nullptr) == S_OK)
            {
                // https://docs.microsoft.com/en-us/windows/win32/api/wincodec/nn-wincodec-iwiccomponentinfo
                IWICComponentInfo* pWicComponentInfo;
                if (SUCCEEDED(punkWicComponentInfo->QueryInterface(IID_PPV_ARGS(&pWicComponentInfo))))
                {
                    // WICコンポーネント情報(IWICComponentInfo)の出力
                    auto friendlyName{ GetFriendlyName(pWicComponentInfo) };
                    auto author{ GetAuthor(pWicComponentInfo) };
                    auto version{ GetVersion(pWicComponentInfo) };
                    auto specVersion{ GetSpecVersion(pWicComponentInfo) };
                    std::wstring clsidStr;
                    std::wstring vendorGuidStr;
                    std::wstring componentTypeStr;
                    std::wstring signingStatusStr;
                    if (CLSID clsid; SUCCEEDED(pWicComponentInfo->GetCLSID(&clsid)))
                        clsidStr = GUIDToWString(clsid);
                    if (CLSID clsid; SUCCEEDED(pWicComponentInfo->GetVendorGUID(&clsid)))
                        vendorGuidStr = GUIDToWString(clsid);
                    if (WICComponentType type; SUCCEEDED(pWicComponentInfo->GetComponentType(&type)))
                        vendorGuidStr = ToWStringView(type);
                    if (DWORD status; SUCCEEDED(pWicComponentInfo->GetSigningStatus(&status)))
                        signingStatusStr = ToWStringView(static_cast<WICComponentSigning>(status));
                    std::wcout
                        << std::format(L"{}, {}, {}, {}, {}, {}, {}",
                            strptr_notnull(friendlyName),
                            strptr_notnull(author),
                            strptr_notnull(version),
                            strptr_notnull(specVersion),
                            strptr_notnull(clsidStr),
                            strptr_notnull(vendorGuidStr),
                            strptr_notnull(signingStatusStr))
                        << std::endl;
                }
            }

            pEnumUnknown->Release();
        }

        pWicImagingFactory->Release();
    }

    // COMの解放
    ::CoUninitialize();

    return 0;
}

デコーダーの対応拡張子を取得する

#include <format>
#include <string>
#include <iostream>

#define STRICT
#define NOMINMAX
#include <Windows.h>
// https://docs.microsoft.com/en-us/windows/win32/api/wincodec/
#include <wincodec.h>
#pragma comment(lib, "WindowsCodecs.lib")

// 文字列から常にnullでない文字列ポインタを返します。
// 文字列がnullptrの場合は空文字列L""のポインタを返します。
constexpr const wchar_t* strptr_notnull(std::wstring_view s) noexcept
{
    return s.empty() ? L"" : s.data();
}

// IWICComponentInfo::GetFriendlyNameメソッドの結果をstd::wstringで返します。
// 失敗時は空のstd::wstringを返します。
std::wstring GetFriendlyName(IWICComponentInfo* info)
{
    UINT actualLen;
    if (SUCCEEDED(info->GetFriendlyName(0, nullptr, &actualLen)))
    {
        if (actualLen == 0) return L"";
        std::wstring s(actualLen - 1, L'\0');
        if (SUCCEEDED(info->GetFriendlyName(actualLen, s.data(), &actualLen)))
        {
            return std::move(s);
        }
    }
    return {};
}

// IWICBitmapDecoderInfo::GetFileExtensionsメソッドの結果をstd::wstringで返します。
// 失敗時は空のstd::wstringを返します。
std::wstring GetFileExtensions(IWICBitmapDecoderInfo* info)
{
    UINT actualLen;
    if (SUCCEEDED(info->GetFileExtensions(0, nullptr, &actualLen)))
    {
        if (actualLen == 0) return L"";
        std::wstring s(actualLen - 1, L'\0');
        if (SUCCEEDED(info->GetFileExtensions(actualLen, s.data(), &actualLen)))
        {
            return std::move(s);
        }
    }
    return {};
}

// IWICComponentInfo::GetAuthorメソッドの結果をstd::wstringで返します。
// 失敗時は空のstd::wstringを返します。
std::wstring GetAuthor(IWICComponentInfo* info)
{
    UINT actualLen;
    if (SUCCEEDED(info->GetAuthor(0, nullptr, &actualLen)))
    {
        if (actualLen == 0) return L"";
        std::wstring s(actualLen - 1, L'\0');
        if (SUCCEEDED(info->GetAuthor(actualLen, s.data(), &actualLen)))
        {
            return std::move(s);
        }
    }
    return {};
}

int wmain()
{
    // 日本語の出力設定(内部変換の設定)
    std::wcout.imbue(std::locale("", std::locale::ctype));

    // COMの初期化
    if (FAILED(::CoInitializeEx(nullptr, COINIT::COINIT_APARTMENTTHREADED)))
        return -1;

    // IWICImagingFactoryの作成
    // https://docs.microsoft.com/en-us/windows/win32/api/wincodec/nn-wincodec-iwicimagingfactory
    IWICImagingFactory* pWicImagingFactory;
    if (SUCCEEDED(::CoCreateInstance(
        CLSID_WICImagingFactory,
        nullptr,
        CLSCTX_INPROC_SERVER,
        IID_PPV_ARGS(&pWicImagingFactory))))
    {
        // WICコンポーネント列挙インターフェイス(IEnumUnknown)の作成
        // デコーダーのみ列挙
        IEnumUnknown* pEnumUnknown;
        if (SUCCEEDED(pWicImagingFactory->CreateComponentEnumerator(
            WICComponentType::WICDecoder,
            WICComponentEnumerateOptions::WICComponentEnumerateDefault,
            &pEnumUnknown)))
        {
            std::wcout << L"FriendlyName, Author, FileExts" << std::endl;

            // デコーダー情報の取得
            // IUnknownで取得後、IWICBitmapDecoderInfoに変換します。
            IUnknown* punkWicComponentInfo;
            while (pEnumUnknown->Next(1, &punkWicComponentInfo, nullptr) == S_OK)
            {
            https://docs.microsoft.com/en-us/windows/win32/api/wincodec/nn-wincodec-iwicbitmapdecoderinfo
                IWICBitmapDecoderInfo* pWicDecoderInfo;
                if (SUCCEEDED(punkWicComponentInfo->QueryInterface(IID_PPV_ARGS(&pWicDecoderInfo))))
                {
                    // デコーダー情報の出力
                    // このコードではIWICBitmapDecoderInfoの継承するIWICBitmapCodecInfoのメソッドしか使いません。
                    auto friendlyName{ GetFriendlyName(pWicDecoderInfo) };
                    auto author{ GetAuthor(pWicDecoderInfo) };
                    auto fileExts{GetFileExtensions(pWicDecoderInfo)};
                    std::wcout
                        << std::format(L"{}, {}, \"{}\"",
                            strptr_notnull(friendlyName),
                            strptr_notnull(author),
                            strptr_notnull(fileExts))
                        << std::endl;
                }
            }

            pEnumUnknown->Release();
        }

        pWicImagingFactory->Release();
    }

    // COMの解放
    ::CoUninitialize();

    return 0;
}

R アルファベットの文字列配列を得る

Rでアルファベットの文字列配列を得るには組み込み定数とstrsplit関数が使えます。タイプミスが防げるため、基本的には前者が推奨されます。以下にコードを示します。

#組み込み定数
#普通はこちらを使います。
LETTERS
letters

#strsplit
#2番めの引数に""を指定すると1文字単位で分割されます。
strsplit("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "")
strsplit("abcdefghijklmnopqtstuvwxyz", "")

JavaScript プロパティを追加できないクラスを作成する

JavaScriptではclassキーワードでクラスを作成できますが、クラスの実体はObjectなのでプロパティが追加できてしまいます。この動作はObject.seal()静的メソッドで無効化できるため、コンストラクタで自身に適用すればプロパティを追加できないクラスを作成できます。

class A {
    a = 0;
    constructor() {
        // 何もしない。
    }
}

class B {
    a = 0;
    constructor() {
        // 自身をシールする。
        Object.seal(this);
    }
}

const a = new A();
const b = new B();
a.x = 0;
b.x = 0;
console.log(a) // Object { a: 0, x: 0 }
console.log(b) // Object { a: 0 }

既存のプロパティも変更を許さない場合はObject.freeezeも使えますが、通常はget x()で使用するかと思います。