落書きノート

ふと自分が気になった事を書いてます

Win32API ドラッグアンドドロップとリソースメニューの実装

少し手間取りましたが、こんな感じです。

rsdnd.h

#define ID_BUTTON1 1000
#define ID_BUTTON2 1001
#define IDM_OPEN 1002
#define IDM_END 1003

dnd.rc

#include "rsdnd.h"

MYMENU MENU DISCARDABLE
BEGIN
    POPUP "ファイル(&F)"
    BEGIN
        MENUITEM "開く(&O)",  IDM_OPEN
        MENUITEM "終了(&X)",  IDM_END
    END
END

dnd.cpp

#pragma comment(lib, "user32.lib")
#pragma comment(lib, "gdi32.lib")
#pragma comment(lib, "shell32.lib")
#pragma comment(lib, "comdlg32.lib")
#define STRICT
#include <windows.h>
#include "rsdnd.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
ATOM InitApp(HINSTANCE);
BOOL InitInstance(HINSTANCE, int);
void openFile(HWND);

char szClassName[] = "sample01";
char szButtonName[] = "BUTTON";

int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst,
    LPSTR lpsCmdLine, int nCmdShow) {
    MSG msg;
    BOOL bRet;

    if (!InitApp(hCurInst))
        return FALSE;
    if (!InitInstance(hCurInst, nCmdShow))
        return FALSE;
    while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
        if (bRet == -1) {
            MessageBox(NULL, "GetMessageエラー", "Error", MB_OK);
            break;
        }
        else {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return (int)msg.wParam;
}

ATOM InitApp(HINSTANCE hInst) {
    WNDCLASSEX wc;
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInst;
    wc.hIcon = (HICON)LoadImage(NULL,
        MAKEINTRESOURCE(IDI_APPLICATION),
        IMAGE_ICON,
        0,
        0,
        LR_DEFAULTSIZE | LR_SHARED);
    wc.hCursor = (HCURSOR)LoadImage(NULL,
        MAKEINTRESOURCE(IDC_ARROW),
        IMAGE_CURSOR,
        0,
        0,
        LR_DEFAULTSIZE | LR_SHARED);
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName = "MYMENU";
    wc.lpszClassName = (LPCSTR)szClassName;
    wc.hIconSm = (HICON)LoadImage(NULL,
        MAKEINTRESOURCE(IDI_APPLICATION),
        IMAGE_ICON,
        0,
        0,
        LR_DEFAULTSIZE | LR_SHARED);

    return (RegisterClassEx(&wc));
}

BOOL InitInstance(HINSTANCE hInst, int nCmdShow) {
    HWND hWnd;

    hWnd = CreateWindow(szClassName,
        "Win32APIテスト",
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        NULL,
        NULL,
        hInst,
        NULL);
    CreateWindow(szButtonName,
        "Test",
        WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
        200,
        200,
        100,
        50,
        hWnd,
        (HMENU)ID_BUTTON1,
        hInst,
        NULL
    );
    CreateWindow(szButtonName,
        "Test2",
        WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
        300,
        200,
        100,
        50,
        hWnd,
        (HMENU)ID_BUTTON2,
        hInst,
        NULL);
    if (!hWnd)
        return FALSE;
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
    return TRUE;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
    HDC hdc;
    PAINTSTRUCT ps;
    static RECT rect;
    static LPTSTR str;
    static PCTSTR ctstr = "テスト";
    int id, i;
    HDROP hDrop;
    UINT uFileNo;
    char szFileName[256];

    switch (msg) {
    case WM_CREATE:
        DragAcceptFiles(hWnd, TRUE);
        break;
    case WM_DROPFILES:
        hDrop = (HDROP)wp;
        uFileNo = DragQueryFile((HDROP)wp, 0xFFFFFFFF, NULL, 0);
        for(i = 0; i < (int)uFileNo; i++) {
            DragQueryFile(hDrop, i, szFileName, sizeof(szFileName));
            if(ShellExecute(hWnd, NULL, szFileName, NULL, NULL, SW_SHOWNORMAL) <= (HINSTANCE)32)
            MessageBox(hWnd, "ファイルを開けませんでした", "失敗", MB_OK);
        }
        DragFinish(hDrop);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        GetClientRect(hWnd, &rect);
        DrawText(hdc, ctstr, -1, &rect,
            DT_CENTER | DT_BOTTOM | DT_WORDBREAK);
        EndPaint(hWnd, &ps);
        break;
    case WM_COMMAND:
        switch(LOWORD(wp)) {
            case IDM_END:
                SendMessage(hWnd, WM_CLOSE, 0, 0);
                break;
            case IDM_OPEN:
                openFile(hWnd);
                break;
        }
        if (HIWORD(wp) == BN_CLICKED) {
            if (LOWORD(wp) == ID_BUTTON1) {
                str = "あいうえお one two three four five";
                hdc = GetDC(hWnd);
                TextOut(hdc, 10, 10, str, lstrlen(str));
                ReleaseDC(hWnd, hdc);
            }
            if (LOWORD(wp) == ID_BUTTON2) {
                str = "かきくけこ kitty on your lap";
                hdc = GetDC(hWnd);
                TextOut(hdc, 10, 40, str, lstrlen(str));
                ReleaseDC(hWnd, hdc);
            }
        }
        break;
    case WM_CLOSE:
        id = MessageBox(hWnd,
        "終了してもよろしいですか。",
        "確認",
        MB_YESNO | MB_ICONQUESTION );
        if(id == IDYES)
            DestroyWindow(hWnd);
        break;
    default:
        return (DefWindowProc(hWnd, msg, wp, lp));
    }
    return 0L;
}

void openFile(HWND hWnd) {
    OPENFILENAME ofn;
    char szFileName[64];
    char szFile[MAX_PATH];

    memset(&ofn, 0, sizeof(OPENFILENAME));
    ofn.lStructSize = sizeof(OPENFILENAME);
    ofn.hwndOwner = hWnd;
    ofn.lpstrFilter = "All files(*.*)\0*.*\0\0";
    ofn.lpstrFile = szFileName;
    ofn.lpstrFileTitle = szFile;
    ofn.nMaxFile = MAX_PATH;
    ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
    ofn.lpstrTitle = "実行したいファイルを選択";
    if(GetOpenFileName(&ofn) == 0)
        return;
    if(ShellExecute(hWnd, NULL, szFile, NULL, NULL, SW_SHOWNORMAL) <= (HINSTANCE)32)
        MessageBox(hWnd, "実行に失敗しました", "失敗", MB_OK);
    return;
}
> rc.exe dnd.rc
> cl.exe dnd.cpp user32.lib gdi32.lib shell32.lib comdlg32.lib dnd.res

VS2015のファイル単位でのリソースファイル編集方法がなかったので、結局VSCodeを使うようになりました。文字コードさえ気をつければ良さそうです。入力補完は履歴を利用できるのである程度楽だと思います。

f:id:kh2n:20170422232211p:plain