完璧!

#include <windows.h>
#include <vector>
#include <sstream>

const int WINDOW_WIDTH = 200;
const int WINDOW_HEIGHT = 400;
const int LINE_HEIGHT = 20;
const int TOTAL_LINES = 20;
const int VISIBLE_LINES = 10;

HWND g_hWnd;
int g_scrollPosition = 0;
int g_selectedIndex = 0;

void ShowSelectedMessage(HWND hWnd, int selectedIndex) {
    std::wstring message = L"Selected Line: " + std::to_wstring(selectedIndex + 1);
    MessageBox(hWnd, message.c_str(), L"Selected Line", MB_OK | MB_ICONINFORMATION);
}

LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message) {
    case WM_CREATE: {
        // スクロールバーをウィンドウに追加
        SetScrollRange(hWnd, SB_VERT, 0, TOTAL_LINES - VISIBLE_LINES, TRUE);
        return 0;
    }
    case WM_PAINT: {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hWnd, &ps);
        RECT rect;
        GetClientRect(hWnd, &rect);

        // 表示する行数を計算
        int startIndex = g_scrollPosition;
        int endIndex = min(startIndex + VISIBLE_LINES, TOTAL_LINES);

        // 行ごとに描画
        for (int i = startIndex; i < endIndex; ++i) {
            rect.top = (i - g_scrollPosition) * LINE_HEIGHT;
            rect.bottom = rect.top + LINE_HEIGHT;

            // テキストを描画
            wchar_t text[16];
            swprintf_s(text, L"%d", i + 1); // 番号を文字列に変換
            DrawText(hdc, text, -1, &rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);

            // 選択された行は色で示す
            if (i == g_selectedIndex) {
                // 選択された行は黄色で描画
                FillRect(hdc, &rect, (HBRUSH)GetStockObject(LTGRAY_BRUSH));
            }
        }

        EndPaint(hWnd, &ps);
        return 0;
    }
    case WM_KEYDOWN: {
        switch (wParam) {
        case VK_UP:
            if (g_selectedIndex > 0)
                --g_selectedIndex;
            if (g_selectedIndex < g_scrollPosition)
                --g_scrollPosition;
            InvalidateRect(hWnd, NULL, TRUE);
            return 0;
        case VK_DOWN:
            if (g_selectedIndex < TOTAL_LINES - 1)
                ++g_selectedIndex;
            if (g_selectedIndex >= g_scrollPosition + VISIBLE_LINES)
                ++g_scrollPosition;
            InvalidateRect(hWnd, NULL, TRUE);
            return 0;
        case VK_RETURN:
            ShowSelectedMessage(hWnd, g_selectedIndex);
            return 0;
        }
        break;
    }
    case WM_DESTROY: {
        PostQuitMessage(0);
        return 0;
    }
    }
    return DefWindowProc(hWnd, message, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    WNDCLASS wc = { 0 };
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszClassName = L"WindowClass";

    RegisterClass(&wc);

    g_hWnd = CreateWindowEx(0, L"WindowClass", L"Selectable Window", WS_OVERLAPPEDWINDOW | WS_VSCROLL,
        CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL);

    ShowWindow(g_hWnd, nCmdShow);

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}