質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

OpenGL

OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

マルチスレッド

マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

826閲覧

WinAPIマルチスレッドにおけるOpenGLのメッセージループ

Weapon

総合スコア106

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

OpenGL

OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

マルチスレッド

マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2018/08/14 13:20

前提・実現したいこと

C言語でシンプルにWinAPIでマルチスレッドを作成しOpenGLのメッセージループを回すというプログラムを書きたいと思ったのですが表示されません。スレッドをまたがるGLの書き方が間違っているのでしょうか

OpenGLのコードは青のバックに白線で連続の直線を表示させているものです。

該当のソースコード

C

1#define UNICODE 2 3#pragma comment(lib,"OpenGL32.lib") 4 5#include <windows.h> 6#include <gl/GL.h> 7#include <gl/GLU.h> 8 9const wchar_t CLASS_NAME[] = L"OpenGL window project"; 10 11 12HINSTANCE hInst; 13HDC hdc; 14HGLRC glrc; 15BOOL bRet; 16 17MSG msg = {}; 18 19DWORD WINAPI GLThread(void); 20 21const wchar_t WINDOW_NAME[] = L"Multi-thread OpenGL Window"; 22 23LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 24 25int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR lpwsCmdLine, int nCmdShow) { 26 27 hInst = hInstance; 28 29 WNDCLASSEX wc = { 30 sizeof(WNDCLASSEX), 31 CS_HREDRAW | CS_VREDRAW, 32 WindowProc, 33 0,0, 34 hInstance, 35 NULL,NULL, 36 (HBRUSH)GetStockObject(WHITE_BRUSH), 37 NULL, 38 CLASS_NAME, 39 NULL 40 }; 41 42 RegisterClassEx(&wc); 43 44 HWND hwnd = CreateWindowEx( 45 0, CLASS_NAME, WINDOW_NAME, WS_OVERLAPPEDWINDOW, 46 100, 100, 780, 540, 47 NULL, NULL, hInstance, NULL 48 ); 49 50 if (hwnd == NULL)return 0; 51 52 ShowWindow(hwnd, nCmdShow); 53 UpdateWindow(hwnd); 54 55 while ((bRet = GetMessage(&msg, NULL, 0, 0) != 0)) { 56 if (bRet == -1)break; 57 else { 58 TranslateMessage(&msg); 59 DispatchMessage(&msg); 60 } 61 } 62 63 return (int)msg.lParam; 64} 65 66LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { 67 68 static HANDLE hgl; 69 static DWORD dwID; 70 71 switch (uMsg) { 72 case WM_CREATE: 73 { 74 PIXELFORMATDESCRIPTOR pfd = { 75 sizeof(PIXELFORMATDESCRIPTOR), 76 1, 77 PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_TYPE_RGBA, 78 32, 79 0,0,0,0,0,0, 80 0,0,0, 81 0,0,0,0, 82 24, 83 8, 84 0, 85 PFD_MAIN_PLANE, 86 0, 87 0,0,0 88 }; 89 90 hdc = GetDC(hwnd); 91 92 int format = ChoosePixelFormat(hdc, &pfd); 93 94 if (format == 0) { 95 MessageBox(hwnd, L"pixel format error", L"Caution", MB_OK); 96 return 0; 97 } 98 99 if (!SetPixelFormat(hdc, format, &pfd)) { 100 MessageBox(hwnd, L"pixel format error", L"Caution", MB_OK); 101 return 0; 102 } 103 104 glrc = wglCreateContext(hdc); 105 106 hgl = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)GLThread, NULL, 0, &dwID); 107 108 if(hgl==NULL) { 109 MessageBox(hwnd, L"Thread error", L"Caution", MB_OK); 110 return 0; 111 } 112 113 break; 114 } 115 116 case WM_CLOSE: 117 118 wglMakeCurrent(NULL, NULL); 119 wglDeleteContext(glrc); 120 ReleaseDC(hwnd, hdc); 121 MessageBox(hwnd, L"Call WM_CLOSE Message", L"Caution", MB_OK); 122 123 DestroyWindow(hwnd); 124 break; 125 126 case WM_DESTROY: 127 PostQuitMessage(0); 128 break; 129 130 default: 131 return DefWindowProcW(hwnd, uMsg, wParam, lParam); 132 } 133 return 0; 134} 135 136DWORD WINAPI GLThread(void) { 137 if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { 138 wglMakeCurrent(hdc, glrc); 139 140 glClearColor(0.0f, 0.5f, 1.0f, 1.0f); 141 glClear(GL_COLOR_BUFFER_BIT); 142 glBegin(GL_LINE_STRIP); 143 144 glVertex2f(0, 0); 145 glVertex2f(0.2, 0.4); 146 glVertex2f(0.4, -0.9); 147 148 glEnd(); 149 150 glVertex2d(1.5f, 5.5f); 151 152 glFlush(); 153 SwapBuffers(hdc); 154 wglMakeCurrent(NULL, NULL); 155 } 156 157 return 0; 158}

補足情報

Windows10 Pro
VisualStudio2017 Community

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

修正してみました。
WM_PAINTで描画しない場合は別スレッドの内部でループ処理することになると思います。

cpp

1#include <windows.h> 2#include <process.h> 3#include <gl/GL.h> 4#include <gl/GLU.h> 5 6#pragma comment(lib,"OpenGL32.lib") 7 8const wchar_t CLASS_NAME[] = L"OpenGL window project"; 9 10 11HINSTANCE hInst; 12HDC hdc; 13HGLRC glrc; 14BOOL bRet; 15BOOL g_glthread_stop = FALSE; 16HANDLE g_glthread_sleep = NULL; 17unsigned WINAPI GLThread(void *p); 18 19const wchar_t WINDOW_NAME[] = L"Multi-thread OpenGL Window"; 20 21LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 22 23int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR lpwsCmdLine, int nCmdShow) { 24 25 hInst = hInstance; 26 27 WNDCLASSEX wc = { 28 sizeof(WNDCLASSEX), 29 CS_HREDRAW | CS_VREDRAW, 30 WindowProc, 31 0,0, 32 hInstance, 33 NULL,NULL, 34 (HBRUSH)GetStockObject(WHITE_BRUSH), 35 NULL, 36 CLASS_NAME, 37 NULL 38 }; 39 40 RegisterClassEx(&wc); 41 42 HWND hwnd = CreateWindowEx( 43 0, CLASS_NAME, WINDOW_NAME, WS_OVERLAPPEDWINDOW, 44 100, 100, 780, 540, 45 NULL, NULL, hInstance, NULL 46 ); 47 48 if (hwnd == NULL)return 0; 49 50 ShowWindow(hwnd, nCmdShow); 51 UpdateWindow(hwnd); 52 53 MSG msg = {}; 54 while ((bRet = GetMessage(&msg, NULL, 0, 0) != 0)) { 55 if (bRet == -1)break; 56 else { 57 TranslateMessage(&msg); 58 DispatchMessage(&msg); 59 } 60 } 61 62 return (int)msg.lParam; 63} 64 65LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { 66 67 static HANDLE hgl; 68 static unsigned int thId; 69 70 switch (uMsg) { 71 case WM_CREATE: 72 { 73 PIXELFORMATDESCRIPTOR pfd = { 74 sizeof(PIXELFORMATDESCRIPTOR), 75 1, 76 PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_TYPE_RGBA, 77 32, 78 0,0,0,0,0,0, 79 0,0,0, 80 0,0,0,0, 81 24, 82 8, 83 0, 84 PFD_MAIN_PLANE, 85 0, 86 0,0,0 87 }; 88 89 hdc = GetDC(hwnd); 90 91 int format = ChoosePixelFormat(hdc, &pfd); 92 93 if (format == 0) { 94 MessageBox(hwnd, L"pixel format error", L"Caution", MB_OK); 95 return -1;//エラー時は-1を返す 96 } 97 98 if (!SetPixelFormat(hdc, format, &pfd)) { 99 MessageBox(hwnd, L"pixel format error", L"Caution", MB_OK); 100 return -1; 101 } 102 103 glrc = wglCreateContext(hdc); 104 105 g_glthread_sleep = CreateEvent(NULL, FALSE, FALSE, NULL); 106 if (g_glthread_sleep == NULL) { 107 MessageBox(hwnd, L"CreateEvent error", L"Caution", MB_OK); 108 return -1; 109 } 110 //CreateTrehadはCランタイムの使用で問題となるので_beginthreadexが推奨 111 hgl = (HANDLE)_beginthreadex(NULL, 0, GLThread, NULL, 0, &thId); 112 113 if (hgl == NULL) { 114 CloseHandle(g_glthread_sleep); 115 MessageBox(hwnd, L"Thread error", L"Caution", MB_OK); 116 return -1; 117 } 118 119 break; 120 } 121 122 case WM_CLOSE: 123 g_glthread_stop = TRUE; 124 WaitForSingleObject(hgl, INFINITE); 125 CloseHandle(hgl); 126 CloseHandle(g_glthread_sleep); 127 wglMakeCurrent(NULL, NULL); 128 wglDeleteContext(glrc); 129 ReleaseDC(hwnd, hdc); 130 MessageBox(hwnd, L"Call WM_CLOSE Message", L"Caution", MB_OK); 131 132 DestroyWindow(hwnd); 133 break; 134 case WM_PAINT: 135 PAINTSTRUCT ps; 136 BeginPaint(hwnd, &ps); 137 EndPaint(hwnd, &ps); 138 //GLThreadのスリープを解除して描画させる 139 SetEvent(g_glthread_sleep); 140 break; 141 142 case WM_DESTROY: 143 PostQuitMessage(0); 144 break; 145 146 default: 147 return DefWindowProcW(hwnd, uMsg, wParam, lParam); 148 } 149 return 0; 150} 151 152unsigned WINAPI GLThread(void*p) { 153 while (!g_glthread_stop) { 154 155 wglMakeCurrent(hdc, glrc); 156 157 glClearColor(0.0f, 0.5f, 1.0f, 1.0f); 158 glClear(GL_COLOR_BUFFER_BIT); 159 glBegin(GL_LINE_STRIP); 160 161 glVertex2f(0, 0); 162 glVertex2f(0.2, 0.4); 163 glVertex2f(0.4, -0.9); 164 165 glEnd(); 166 167 glVertex2d(1.5f, 5.5f); 168 169 glFlush(); 170 SwapBuffers(hdc); 171 wglMakeCurrent(NULL, NULL); 172 173 WaitForSingleObject(g_glthread_sleep, 500); 174 } 175 176 return 0; 177}

投稿2018/08/14 14:35

hmmm

総合スコア818

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Weapon

2018/08/15 08:00

CreateThreadは非推奨だったんですか。なかなかWinAPI本は新しいものがないので気付きませんでした。参考にさせていただきます。ありがとうございます。
guest

0

ベストアンサー

GLThread関数のこの部分

if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {

PeekMessage関数はメッセージキューにメッセージがあれば0以外、なければ0を返します。GLThread関数に入っていきなりPeekMessage関数を呼んでもメッセージがポストされているわけがないので、PeekMessage関数は必ず0を返します。
結果、ifブロック内は実行されることなくスレッドが終了します。
とりあえず、無意味なif文を削除すれば何か表示されると思います。

なぜif文なのかは判りませんが、メッセージループのつもりならループになるように実装してください。その際、PeekMessage関数の戻り値で判定するのではなく、何か特定のメッセージを受信したら終了するようなコードを書いてください。ループの継続(終了)条件がメッセージの有無ではないはずですから。

また、これは重要なことなのですが、変数msgがグローバルで定義されています。異なるスレッドで同じ変数を使い回すと予想もつかないバグを引き起こすので、msgはローカル変数にしてください。同様にbRetもグローバルに定義する意味はないのでローカルで定義してください。

投稿2018/08/14 14:05

catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Weapon

2018/08/14 14:21

Multi-threadのサンプルに、if文にPeekMessageを条件にTranslateMessage+DispatchMessageかOpenGLのループかを無限ループするSingle-Thread OpenGLのコードを移植して練習してたための間違いでした。 グローバル定義にも気を付けます。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問