Windowsプログラムのスレッドだって、DOS窓でWin32API

|

Windowsは一時、マルチタスクが死に掛けましたが(高々携帯電話機、i何チャラに引き摺られて)、Ver.10に格下げ?されてマルチタスクが息を吹き返しました。

Windowsには「プロセス」と「スレッド」の2種類のタスクが有りますが、プログラム起動時にはプロセスで、プログラム内ではスレッドでと使い分けると簡単な気が・・・、プロセスは複数のスレッドを持てるようですし。

試しに、Win32APIでスレッドを呼び出すだけのサンプルを作ってみました。


<注意点>

・前回のサンプルに、スレッド部分を追加しただけです。

・通常プロセスを起動すると、その中に一つスレッドが自動的に生成されるので、メインスレッド、サブスレッド1、サブスレッド2、サブスレッド3とあります。

「stdio.h」を「cstdio」に変更することで、.cppファイルとしてもコンパイル出来ます。


【_beginthreadexの引数】

_beginthreadex APIのパラメータ
パラメータ名説明
thrdAttr void * 新しいスレッドのセキュリティ属性。NULLの場合は実行元と同じになる
stackSize unsigned 新しいスレッドのスタックサイズ。0の場合は作成元と同じになる
thrdProc unsigned (*)(void *) スレッド・プロシージャのアドレス
param void * スレッド・プロシージャへのパラメータ
createFlag unsigned CREATE_SUSPENDED を指定すると、実行を開始せずに作成。0は作成して即実行 *1
thrdId unsigned * 新しいスレッドのスレッドIDを受け取る


 *1:CREATE_SUSPENDED を指定した場合、実行開始するには ResumeThread API を呼び出す必要があります。


お試し環境
  WindowsXP 32bit Edition
  Visual C++ 2008


/*---- Win32API スレッド 追加 --------------- コマンドライン ---------------*/

D:\vc2008\dllchk>cl test.c user32.lib  gdi32.lib

/*----------------------------------------------------------------------------*/


/*---- test.c ------------------------ お試しソース ------------------------*/

#include <stdio.h>
#include <windows.h>
#include <process.h>  // _beginthreadex 関数

#define WINCLASS_NAME "Form.003"
#define ID_BUTTON1 1001
#define ID_BUTTON2 1002
#define ID_BUTTON3 1003
#define ID_EDITBOX 1011

unsigned WINAPI subThread1(void *hCtr)
{
    int i, len;
    char s[] = ", i =   ";

    for(i = 0; i < 5; i++) {
        len = SendMessage((HWND)hCtr, WM_GETTEXTLENGTH, 0, 0);
        SendMessage((HWND)hCtr, EM_SETSEL, (WPARAM)len, (LPARAM)len);
        sprintf(s, ", i = %d", i);
        SendMessage((HWND)hCtr, EM_REPLACESEL, 0, (LPARAM)s);
        Sleep(1000);
    }
    return(0);
}

unsigned WINAPI subThread2(void *hCtr)
{
    int j, len;
    char s[] = ", j =    ";

    for(j = 5; j < 15; j++) {
        len = SendMessage((HWND)hCtr, WM_GETTEXTLENGTH, 0, 0);
        SendMessage((HWND)hCtr, EM_SETSEL, (WPARAM)len, (LPARAM)len);
        sprintf(s, ", j = %d", j);
        SendMessage((HWND)hCtr, EM_REPLACESEL, 0, (LPARAM)s);
        Sleep(500);
    }
    return(0);
}

unsigned WINAPI subThread3(void *hCtr)
{
    int k, len;
    char s[] = ", k =    ";

    _beginthreadex(NULL, 0, subThread2, hCtr, 0, NULL);

    for(k = 15; k < 19; k++) {
        len = SendMessage((HWND)hCtr, WM_GETTEXTLENGTH, 0, 0);
        SendMessage((HWND)hCtr, EM_SETSEL, (WPARAM)len, (LPARAM)len);
        sprintf(s, ", k = %d", k);
        SendMessage((HWND)hCtr, EM_REPLACESEL, 0, (LPARAM)s);
        Sleep(1500);
    }
    return(0);
}

LRESULT CALLBACK WinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static HWND hLbl1, hBtn1, hBtn2, hBtn3, hEdit;
    static unsigned short x, y, z;
    HINSTANCE hInstance;
    int wmid, wmevent;
    PAINTSTRUCT ps;
    HDC hdc;
    char str[] = "X =       , Y =       , Button =       ";

    switch(uMsg) {
    case WM_CREATE :
        hInstance = ((LPCREATESTRUCT)lParam)->hInstance;

        if((hLbl1 = CreateWindowEx(WS_EX_LEFT, "STATIC", "ラベル1", WS_CHILD | WS_VISIBLE, 200, 120, 150, 20, hWnd, NULL, hInstance, NULL)) == NULL) {
            printf("ラベル1コントロールを作成出来ませんでした。\n");
            return(FALSE);
        }
        if((hBtn1 = CreateWindowEx(WS_EX_LEFT, "BUTTON", "ボタン1", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 75, 220, 70, 20, hWnd, (HMENU)ID_BUTTON1, hInstance, NULL)) == NULL) {
            printf("ボタン1コントロールを作成出来ませんでした。\n");
            return(FALSE);
        }
        if((hBtn2 = CreateWindowEx(WS_EX_LEFT, "BUTTON", "ボタン2", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 160, 220, 70, 20, hWnd, (HMENU)ID_BUTTON2, hInstance, NULL)) == NULL) {
            printf("ボタン2コントロールを作成出来ませんでした。\n");
            return(FALSE);
        }
        if((hBtn3 = CreateWindowEx(WS_EX_LEFT, "BUTTON", "ボタン3", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 245, 220, 70, 20, hWnd, (HMENU)ID_BUTTON3, hInstance, NULL)) == NULL) {
            printf("ボタン3コントロールを作成出来ませんでした。\n");
            return(FALSE);
        }
        if((hEdit = CreateWindowEx(WS_EX_LEFT, "EDIT", "エディットボックス1", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | ES_AUTOVSCROLL | ES_LEFT | ES_MULTILINE, 50, 50, 100, 150, hWnd, (HMENU)ID_EDITBOX, hInstance, NULL)) == NULL) {
            printf("エディットボックスコントロールを作成出来ませんでした。\n");
            return(FALSE);
        }
        break;
    case WM_COMMAND :
        wmid = LOWORD(wParam);
        wmevent = HIWORD(wParam);
        switch(wmevent) {
        case BN_CLICKED :
            switch(wmid) {
            case ID_BUTTON1 :
                EnableWindow(hBtn1, FALSE);
                SetWindowText(hBtn1, "押下1");
                SetWindowText(hLbl1, "コンパイルエラーが来たぁ!");
                break;
            case ID_BUTTON2 :
                EnableWindow(hBtn2, FALSE);
                SetWindowText(hBtn2, "押下2");
                SetWindowText(hEdit, "修正漏れが見つかったぞぉ!");
                break;
            case ID_BUTTON3 :
                EnableWindow(hBtn3, FALSE);
                SetWindowText(hBtn3, "スレッド");
                _beginthreadex(NULL, 0, subThread1, hEdit, 0, NULL);
                _beginthreadex(NULL, 0, subThread3, hEdit, 0, NULL);
                break;
            default :
                break;
            }
            break;
        default :
            break;
        }
        break;
    case WM_LBUTTONDOWN :
    case WM_RBUTTONDOWN :
        x = LOWORD(lParam);
        y = HIWORD(lParam);
        z = LOWORD(wParam);
        InvalidateRect(hWnd, NULL, TRUE);
        break;
    case WM_PAINT :
        hdc = BeginPaint(hWnd, &ps);
        sprintf(str, "X = %d, Y = %d, Button = %s", x, y, (z == 1 ? "Left" : "Right") );
        TextOut(hdc, 30, 10, str, (int)strlen(str));
        EndPaint(hWnd, &ps);
        break;
    case WM_CLOSE :
        if(MessageBox(hWnd, "ウィンドウを閉じます。\nよろしいですか?", "確認", MB_OKCANCEL | MB_ICONWARNING) == IDOK) {
            DestroyWindow(hWnd);
        } else {
            SetWindowText(hLbl1, "ラベル1");
            SetWindowText(hBtn1, "ボタン1");
            EnableWindow(hBtn1, TRUE);
            SetWindowText(hBtn2, "ボタン2");
            EnableWindow(hBtn2, TRUE);
            SetWindowText(hBtn3, "ボタン3");
            EnableWindow(hBtn3, TRUE);
        }
        break;
    case WM_DESTROY :
        PostQuitMessage(0);
        break;
    default :
        return DefWindowProc(hWnd , uMsg , wParam , lParam);
    }

    return(0);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    HWND hWnd;
    WNDCLASSEX wcx;
    MSG msg;
    int ret;

    /* ウィンドウクラスの登録 */
    wcx.cbSize = sizeof(WNDCLASSEX);
    wcx.style = CS_HREDRAW | CS_VREDRAW;
    wcx.lpfnWndProc = WinProc;
    wcx.cbClsExtra = 0;
    wcx.cbWndExtra = 0;
    wcx.hInstance = hInstance;
    wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcx.lpszMenuName = NULL;
    wcx.lpszClassName = WINCLASS_NAME;
    wcx.hIconSm = NULL;

    if(!RegisterClassEx(&wcx)) {
        printf("ウィンドウクラスの登録が出来ませんでした。\n");
        return(0);
    }

    /* 登録したクラスのウィンドウを生成 */
    hWnd = CreateWindowEx(WS_EX_LEFT, WINCLASS_NAME, "ウインドウタイトル3", WS_OVERLAPPEDWINDOW, 50, 50, 400, 300, NULL, NULL, hInstance ,NULL);
    if(hWnd == NULL) {
        printf("ウィンドウが作成出来ませんでした。\n");
        return(FALSE);
    }

    /* ウィンドウの表示 */
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    /* メッセージループ */
    while((ret = GetMessage(&msg, NULL, 0, 0)) > 0 ) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    if(ret == -1) {
        printf("メッセージの取得に失敗しました。\n");
        return(FALSE);
    }
    return((int)msg.wParam);
}

/*----------------------------------------------------------------------------*/
/*============================================================================*/