2

我正在尝试使用 自动调整一些日期时间选择器控件的大小DTM_GETIDEALSIZE,但我不太了解如何正确使用此消息。如果将返回的宽度视为像素,则返回的宽度似乎很好,但高度似乎不仅相差甚远,而且有时会随着时间而改变!

下面的示例程序创建了三个日期时间选择器。第一个以自定义格式显示日期和时间,第二个仅使用 显示日期DTS_SHORTDATECENTURYFORMAT,第三个仅使用 显示时间DTS_TIMEFORMAT。调整窗口大小使用 调整所有三个选择器的大小DTM_GETIDEALSIZE。宽度似乎很好。但是,前两个的高度始终为 100,而最后一个(时间选择器)的高度似乎从 98 左右开始,每次调整大小都会减少 2,直到达到 16,此时它保持在 16。

这在 Windows Vista 和 Windows 7 上都进行了测试。以下程序中的错误检查不一致(但为了保持这个简单的测试示例,未检查某些错误)。但是,我会注意到 MSDN 明确记录DTM_GETIDEALSIZE了仅TRUE在没有指定错误条件的情况下返回。

谢谢。

// 3 june 2015
#define UNICODE
#define _UNICODE
#define STRICT
#define STRICT_TYPED_ITEMIDS
#define CINTERFACE
#define WINVER 0x0600
#define _WIN32_WINNT 0x0600
#define _WIN32_WINDOWS 0x0600
#define _WIN32_IE 0x0700
#define NTDDI_VERSION 0x06000000
#include <windows.h>
#include <commctrl.h>
#include <stdint.h>
#include <uxtheme.h>
#include <string.h>
#include <wchar.h>
#include <windowsx.h>
#include <vsstyle.h>
#include <vssym32.h>
#include <stdarg.h>
#include <oleacc.h>
#include <stdio.h>

void die(char *s)
{
    // TODO
}

HWND mainwin;
HWND dtp1, dtp2, dtp3;

void idealsize(HWND dtp, char *n, int *x, int *y)
{
    SIZE s;

    s.cx = 0;
    s.cy = 0;
    printf("%s | %I32d ", n, SendMessageW(dtp, DTM_GETIDEALSIZE, 0, (LPARAM) (&s)));
    printf("%I32d %I32d\n", s.cx, s.cy);
    MoveWindow(dtp, *x, *y, s.cx, s.cy, TRUE);
    *y += s.cy;
}

LRESULT CALLBACK wndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    int x, y;
    SIZE s;

    switch (uMsg) {
    case WM_CLOSE:
        PostQuitMessage(0);
        return 0;
    case WM_SIZE:
        x = 10;
        y = 10;
        idealsize(dtp1, "1", &x, &y);
        idealsize(dtp2, "2", &x, &y);
        idealsize(dtp3, "3", &x, &y);
        break;
    }
    return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}

static HWND makedtp(DWORD style, WCHAR *format)
{
    HWND hwnd;

    hwnd = CreateWindowExW(WS_EX_CLIENTEDGE,
        DATETIMEPICK_CLASSW, L"",
        style | WS_TABSTOP | WS_CHILD | WS_VISIBLE,
        0, 0, 100, 100,
        mainwin, NULL, GetModuleHandle(NULL), NULL);
    if (format != NULL)
        if (SendMessageW(hwnd, DTM_SETFORMAT, 0, (LPARAM) format) == 0)
            die("error applying format string to date/time picker in finishNewDateTimePicker()");
    return hwnd;
}

#define GLI(what, buf, n) GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, what, buf, n)

HWND makeDateTimePicker(void)
{
    WCHAR *date, *time, *datetime;
    int ndate, ntime;
    int n;
    HWND hwnd;

    // TODO verify that this always returns a century year
    ndate = GLI(LOCALE_SSHORTDATE, NULL, 0);
    if (ndate == 0)
        die("error getting date string length in uiNewDateTimePicker()");
    date = (WCHAR *) malloc(ndate * sizeof (WCHAR));
    if (GLI(LOCALE_SSHORTDATE, date, ndate) == 0)
        die("error geting date string in uiNewDateTimePicker()");

    ntime = GLI(LOCALE_STIMEFORMAT, NULL, 0);
    if (ndate == 0)
        die("error getting time string length in uiNewDateTimePicker()");
    time = (WCHAR *) malloc(ntime * sizeof (WCHAR));
    if (GLI(LOCALE_STIMEFORMAT, time, ntime) == 0)
        die("error geting time string in uiNewDateTimePicker()");

    n = _scwprintf(L"%s %s", date, time);
    datetime = (WCHAR *) malloc((n + 1) * sizeof (WCHAR));
    snwprintf(datetime, n + 1, L"%s %s", date, time);
    hwnd = makedtp(0, datetime);

    free(datetime);
    free(time);
    free(date);

    return hwnd;
}

HWND makeDatePicker(void)
{
    return makedtp(DTS_SHORTDATECENTURYFORMAT, NULL);
}

HWND makeTimePicker(void)
{
    return makedtp(DTS_TIMEFORMAT, NULL);
}

static void makeWindows(void)
{
    mainwin = CreateWindowExW(0,
        L"mainwin", L"Full Window",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        500, 500,
        NULL, NULL, GetModuleHandle(NULL), NULL);

    dtp1 = makeDateTimePicker();
    dtp2 = makeDatePicker();
    dtp3 = makeTimePicker();
}

void initCommonControls(BOOL);

int main(int argc, char *argv[])
{
    WNDCLASSW wc;
    MSG msg;
    HBRUSH b;

    initCommonControls(TRUE);

    ZeroMemory(&wc, sizeof (WNDCLASSW));
    wc.lpszClassName = L"mainwin";
    wc.lpfnWndProc = wndProc;
    wc.hInstance = GetModuleHandle(NULL);
    wc.hIcon = LoadIconW(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
    RegisterClassW(&wc);

    makeWindows();

    ShowWindow(mainwin, SW_SHOWDEFAULT);
    UpdateWindow(mainwin);

    while (GetMessageW(&msg, NULL, 0, 0) > 0) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}

static const char manifest[] = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n<assemblyIdentity\n    version=\"1.0.0.0\"\n    processorArchitecture=\"*\"\n    name=\"CompanyName.ProductName.YourApplication\"\n    type=\"win32\"\n/>\n<description>Your application description here.</description>\n<dependency>\n    <dependentAssembly>\n        <assemblyIdentity\n            type=\"win32\"\n            name=\"Microsoft.Windows.Common-Controls\"\n            version=\"6.0.0.0\"\n            processorArchitecture=\"*\"\n            publicKeyToken=\"6595b64144ccf1df\"\n            language=\"*\"\n        />\n    </dependentAssembly>\n</dependency>\n</assembly>\n";

static ULONG_PTR comctlManifestCookie;
static HMODULE comctl32;

void initCommonControls(BOOL comctl6)
{
    WCHAR temppath[MAX_PATH + 1];
    WCHAR filename[MAX_PATH + 1];
    HANDLE file;
    DWORD nExpected, nGot;
    ACTCTX actctx;
    HANDLE ac;
    INITCOMMONCONTROLSEX icc;
    FARPROC f;
    // this is listed as WINAPI in both Microsoft's and MinGW's headers, but not on MSDN for some reason
    BOOL (*WINAPI ficc)(const LPINITCOMMONCONTROLSEX);

    if (comctl6) {
        if (GetTempPathW(MAX_PATH + 1, temppath) == 0)
            die("getting temporary path for writing manifest file");
        if (GetTempFileNameW(temppath, L"manifest", 0, filename) == 0)
            die("getting temporary filename for writing manifest file");
        file = CreateFileW(filename, GENERIC_WRITE,
            0,          // don't share while writing
            NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
        if (file == NULL)
            die("creating manifest file");
        nExpected = (sizeof manifest / sizeof manifest[0]) - 1;     // - 1 to omit the terminating null character)
        if (WriteFile(file, manifest, nExpected, &nGot, NULL) == 0)
            die("writing manifest file");
        if (nGot != nExpected)
            die("short write to manifest file");
        if (CloseHandle(file) == 0)
            die("closing manifest file (this IS an error here because not doing so will prevent Windows from being able to use the manifest file in an activation context)");

        ZeroMemory(&actctx, sizeof (ACTCTX));
        actctx.cbSize = sizeof (ACTCTX);
        actctx.dwFlags = ACTCTX_FLAG_SET_PROCESS_DEFAULT;
        actctx.lpSource = filename;
        ac = CreateActCtx(&actctx);
        if (ac == INVALID_HANDLE_VALUE)
            die("creating activation context for synthesized manifest file");
        if (ActivateActCtx(ac, &comctlManifestCookie) == FALSE)
            die("activating activation context for synthesized manifest file");
    }

    ZeroMemory(&icc, sizeof (INITCOMMONCONTROLSEX));
    icc.dwSize = sizeof (INITCOMMONCONTROLSEX);
    icc.dwICC = ICC_STANDARD_CLASSES | ICC_PROGRESS_CLASS | ICC_TAB_CLASSES | ICC_LISTVIEW_CLASSES | ICC_UPDOWN_CLASS | ICC_BAR_CLASSES | ICC_DATE_CLASSES;

    comctl32 = LoadLibraryW(L"comctl32.dll");
    if (comctl32 == NULL)
        die("loading comctl32.dll");
    f = GetProcAddress(comctl32, "InitCommonControlsEx");
    if (f == NULL)
        die("loading InitCommonControlsEx()");
    ficc = (BOOL (*WINAPI)(const LPINITCOMMONCONTROLSEX)) f;
    if ((*ficc)(&icc) == FALSE)
        die("initializing Common Controls (comctl32.dll)");
}
4

0 回答 0