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

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

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

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

Win32 API

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

C++

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

Q&A

解決済

2回答

3102閲覧

WinAPI AlphaBlendの再描画

Weapon

総合スコア106

C

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

Win32 API

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

C++

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

0グッド

2クリップ

投稿2018/10/04 13:57

前提・実現したいこと

前回の質問:WinAPI AlphaBlendのDIB定義を参考に私なりに書いてみました。しかし背景の再描画がうまくいかない問題が解決できません。
下記のコードでWNDCLASSEXで背景を(HBRUSH)WHITE_BRUSHとすると初期表示は
初期表示
となりますがリサイズすると再描画後
周囲は再描画されないうえ、画像(透過の赤格子)がほかの画像(黄色の非透過)と重なっていない部分は背景の白ではなくおそらく黒とブレンドされます。
(HBRUSH)GRAY_BRUSHや(HBRUSH)BLACK_BRUSHの場合は正常にその背景色にブレンドされ、周囲の再描画もされます。
FillRect(hdc, &ps.rcPaint, WHITE_BRUSH);
でWM_PAINT内で塗れば正常には動きますが仕様等的に正しい使い方ではないのでしょうか?それともWM_PAINT内の解放等に誤りがあるのでしょうか?

コーディング上の指摘もありましたらお願いします。

該当のソースコード

C

1#define UNICODE 2 3#include <windows.h> 4#pragma comment(lib, "msimg32.lib") 5 6 7HINSTANCE hInst; 8 9LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM); 10 11const wchar_t CLASS_NAME[] = L"class name"; 12const wchar_t TITLE[] = L"Alpha transparent window"; 13 14struct ARGB 15{ 16 BYTE Blue; 17 BYTE Green; 18 BYTE Red; 19 BYTE Alpha; 20}; 21 22int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR nCmdline, int nCmdShow) { 23 UNREFERENCED_PARAMETER(hPrevInstance); 24 UNREFERENCED_PARAMETER(nCmdShow); 25 26 hInst = hInstance; 27 28 WNDCLASSEX wc = { 29 sizeof(WNDCLASSEX),CS_HREDRAW | CS_VREDRAW,WindowProc, 30 0,0,hInstance, 31 0,0,(HBRUSH)WHITE_BRUSH, 32 0,CLASS_NAME,0 }; 33 34 RegisterClassEx(&wc); 35 36 HWND hwnd = CreateWindowEx( 37 0, CLASS_NAME, TITLE, WS_OVERLAPPEDWINDOW, 38 CW_USEDEFAULT, CW_USEDEFAULT, 960, 540, 39 0, 0, hInstance, 0 40 ); 41 42 ShowWindow(hwnd, nCmdShow); 43 UpdateWindow(hwnd); 44 45 MSG msg = {}; 46 47 while (GetMessage(&msg, 0, 0, 0)) { 48 TranslateMessage(&msg); 49 DispatchMessageW(&msg); 50 } 51 52 return (int)msg.wParam; 53} 54 55LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { 56 switch (uMsg) { 57 case WM_CREATE: 58 break; 59 60 case WM_PAINT: 61 { 62 PAINTSTRUCT ps; 63 HDC hdc = BeginPaint(hwnd, &ps); 64 65 //FillRect(hdc, &ps.rcPaint, WHITE_BRUSH); 66 67 BITMAPINFO bmpio; 68 69 bmpio.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 70 bmpio.bmiHeader.biWidth = 160; 71 bmpio.bmiHeader.biHeight = 90; 72 bmpio.bmiHeader.biPlanes = 1; 73 bmpio.bmiHeader.biBitCount = 32; 74 bmpio.bmiHeader.biCompression = BI_RGB; 75 bmpio.bmiHeader.biSizeImage = 160 * 90 * sizeof(ARGB); 76 77 DWORD *dib = (DWORD*)calloc(sizeof(DWORD) * 160 * 90, sizeof(sizeof(DWORD) * 160 * 90)); 78 79 for (int i = 0; i < 160; i++)for (int j = 0; j < 90; j++)dib[i + j * 160] = 0xffff00; 80 StretchDIBits( 81 hdc, 10, 10, 160, 90, 0, 0, 160, 90, dib, &bmpio, DIB_RGB_COLORS, SRCCOPY 82 ); 83 84 StretchDIBits( 85 hdc, 200, 200, 160*2, 90*2, 0, 0, 160, 90, dib, &bmpio, DIB_RGB_COLORS, SRCCOPY 86 ); 87 88 BITMAPINFO bmpi; 89 void* pv; 90 91 bmpi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 92 bmpi.bmiHeader.biWidth = 160; 93 bmpi.bmiHeader.biHeight = 90; 94 bmpi.bmiHeader.biPlanes = 1; 95 bmpi.bmiHeader.biBitCount = 32; 96 bmpi.bmiHeader.biCompression = BI_RGB; 97 bmpi.bmiHeader.biSizeImage = 160 * 90 * sizeof(ARGB); 98 99 HDC hdcimg = CreateCompatibleDC(hdc); 100 HBITMAP hbmp = CreateDIBSection(hdc, &bmpi, DIB_RGB_COLORS, &pv, NULL, 0); 101 SelectObject(hdcimg, hbmp); 102 103 GdiFlush(); 104 105 BYTE* pbits = reinterpret_cast<BYTE*>(pv); 106 for (size_t x = 0; x < 160; x++) 107 { 108 for (size_t y = 0; y < 90; y++) 109 { 110 ARGB* line = reinterpret_cast<ARGB*>(pbits + y * 160 * sizeof(ARGB) + x * sizeof(ARGB)); 111 if ((x / 10) % 2 == 0) { 112 line->Alpha = 0x7f; 113 line->Red = 0xff; 114 line->Blue = 0x0; 115 line->Green = 0x0; 116 } 117 else 118 { 119 line->Alpha = 0x0; 120 line->Red = 0xff; 121 line->Blue = 0x0; 122 line->Green = 0x0; 123 } 124 } 125 } 126 127 128 BLENDFUNCTION bf; 129 bf.BlendOp = AC_SRC_OVER; 130 bf.BlendFlags = 0; 131 bf.SourceConstantAlpha = 0xff; 132 bf.AlphaFormat = AC_SRC_ALPHA; 133 134 AlphaBlend(hdc, 10, 10, 160*3, 90*3, hdcimg, 0, 0, 160, 60, bf); 135 136 SelectObject(hdcimg, hbmp); 137 DeleteDC(hdcimg); 138 DeleteObject(hbmp); 139 EndPaint(hwnd, &ps); 140 } 141 142 break; 143 144 case WM_COMMAND: 145 InvalidateRect(hwnd, NULL, TRUE); 146 break; 147 148 case WM_DESTROY: 149 PostQuitMessage(0); 150 break; 151 } 152 return DefWindowProcW(hwnd, uMsg, wParam, lParam); 153} 154

補足情報

VisualStudio2017 Community
Windows10

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

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

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

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

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

guest

回答2

0

ベストアンサー

かなり混乱されているようですが、原因は一般的な GDI 関数の HBRUSH 値と RegisterClassEx で登録された HBRUSH 値の扱いが異なることにあります。

tagWNDCLASSEXW structure の説明にあるように hbrBackgroud には COLOR_??? 定数に +1 した値を指定することが可能です。

C

1#define COLOR_SCROLLBAR 0 2#define COLOR_BACKGROUND 1 3#define COLOR_ACTIVECAPTION 2 4#define COLOR_INACTIVECAPTION 3 5#define COLOR_MENU 4 6#define COLOR_WINDOW 5 7#define COLOR_WINDOWFRAME 6 8#define COLOR_MENUTEXT 7 9#define COLOR_WINDOWTEXT 8 10#define COLOR_CAPTIONTEXT 9 11#define COLOR_ACTIVEBORDER 10 12#define COLOR_INACTIVEBORDER 11 13#define COLOR_APPWORKSPACE 12 14#define COLOR_HIGHLIGHT 13 15#define COLOR_HIGHLIGHTTEXT 14 16#define COLOR_BTNFACE 15 17#define COLOR_BTNSHADOW 16 18#define COLOR_GRAYTEXT 17 19#define COLOR_BTNTEXT 18 20#define COLOR_INACTIVECAPTIONTEXT 19 21#define COLOR_BTNHIGHLIGHT 20 22#define COLOR_3DDKSHADOW 21 23#define COLOR_3DLIGHT 22 24#define COLOR_INFOTEXT 23 25#define COLOR_INFOBK 24 26#define COLOR_HOTLIGHT 26 27#define COLOR_GRADIENTACTIVECAPTION 27 28#define COLOR_GRADIENTINACTIVECAPTION 28 29#define COLOR_MENUHILIGHT 29 30#define COLOR_MENUBAR 30 31#define COLOR_DESKTOP COLOR_BACKGROUND 32#define COLOR_3DFACE COLOR_BTNFACE 33#define COLOR_3DSHADOW COLOR_BTNSHADOW 34#define COLOR_3DHIGHLIGHT COLOR_BTNHIGHLIGHT 35#define COLOR_3DHILIGHT COLOR_BTNHIGHLIGHT 36#define COLOR_BTNHILIGHT COLOR_BTNHIGHLIGHT

GDI 関数のうち HBRUSH を受け取るものも基本的にはこの動作(COLOR_??? + 1を指定可能)になります。
FillRect

COLOR_定数は 0 から始まるため、+1 したものを指定するため、一番最小の値は 1 となります。一方、Stock Object の定数は以下のようになっており

C

1#define WHITE_BRUSH 0 2#define LTGRAY_BRUSH 1 3#define GRAY_BRUSH 2 4#define DKGRAY_BRUSH 3 5#define BLACK_BRUSH 4 6```WHITE_BRUSH が最小の 0 となります。WNDCLASSEX の hbrBackground に 0 つまりは NULL を指定した場合、先ほどのページに以下のように記載されています。 7> When this member is NULL, an application must paint its own background whenever it is requested to paint in its client area. To determine whether the background must be painted, an application can either process the WM_ERASEBKGND message or test the fErase member of the PAINTSTRUCT structure filled by the BeginPaint function. 8 9この場合、WM_ERASEBKGND によって背景が再描画されないため、提示されている事象が発生しています。**一方、ドキュメントには記載されていませんが、FillRect の HBRSUH に NULL を指定すると白で塗りつぶされます。**この動作の差が WHITE_BRUSH 値を指定した際の動作の差となって表れています。 10 11自動的に背景色を白く塗りつぶすには yominet さんが挙げられているように GetStockObject を使用するか、(HBRUSH)(COLOR_WINDOW + 1) を指定するようにしてください。 12 13--- 14他の指摘点としては・・・ 15 16 17### 1.メモリリーク 18> DWORD *dib = (DWORD*)calloc(sizeof(DWORD) * 160 * 90, sizeof(sizeof(DWORD) * 160 * 90)); 19 20calloc で割り当てた dib を free していません。 21 22 23### 2.GdiFlush の使い方 24 25GdiFlush が必要なのは GDI 操作が完了していることを保証するためです。 26今回の場合、作成した DIB セクションに対して GDI の描画処理を呼び出していないので、 27このタイミングで呼び出すことは不要です。 28 29 30### 3.呼び出す関数が統一されていない 31 32> DispatchMessageW 33> DefWindowProcW 34 35UNICODE 版の関数を直接呼び出している部分とそうではない部分があります。 36ネットに公開されているソースでは W を付けないことが多いかと思いますが、それに合わせる必要はなく自分のルールとして付けるか付けないかのどちらかに統一するようにすることをお勧めします。VC++ のコード補完では A 付、W 付、何もなしの 3 種類が候補に挙がるはずですので、選択するのはそれほど難しくはないと思います。

投稿2018/10/06 06:31

編集2018/10/06 06:55
atata0319

総合スコア881

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

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

0

WM_PAINTの前にウィンドウの生成に変なところがあります

WNDCLASSEX wc = { sizeof(WNDCLASSEX),CS_HREDRAW | CS_VREDRAW,WindowProc, 0,0,hInstance, 0,0,(HBRUSH)WHITE_BRUSH, 0,CLASS_NAME,0 };

ここの
(HBRUSH)WHITE_BRUSH

(HBRUSH)::GetStockObject(WHITE_BRUSH)
に変えてみてください

#「WHITE_BRUSH」はただの数値であって、HBRUSHではない

投稿2018/10/05 15:56

yominet

総合スコア187

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問