/* ParallelBuild.ab ビルドバッチ8つを同時実行、1つのウィンドウに8つエディットボックスを並べて、そこへ結果を出力します。 ほか、特徴的な点 Windows.UIでのコントロール(エディットボックス)のサブクラス化 DWM下におけるGDIを用いた半透明描画 (BufferedPaint系関数の使用) DWM下におけるタイトルバー上のアイコン・文字列の非表示 */ #require #require #require #resource "UI_Sample.rc" Imports ActiveBasic.Windows Imports ActiveBasic.Windows.UI Imports System.Collections.Generic Imports System.IO Imports System.Threading TypeDef HPAINTBUFFER = HANDLE Const Enum BP_BUFFERFORMAT BPBF_COMPATIBLEBITMAP = 0 BPBF_DIB = 1 BPBF_TOPDOWNDIB = 2 BPBF_TOPDOWNMONODIB = 3 End Enum Const BPBF_COMPOSITED = BPBF_TOPDOWNDIB Type BP_PAINTPARAMS cbSize As DWord dwFlags As DWord prcExclude As *RECT pBlendFunction As VoidPtr '*BLENDFUNCTION End Type Type MARGINS cxLeftWidth As Long cxRightWidth As Long cyTopHeight As Long cyBottomHeight As Long End Type Const Enum WINDOWTHEMEATTRIBUTETYPE WTA_NONCLIENT = 1 End Enum Type WTA_OPTIONS dwFlags As DWord dwMask As DWord End Type Const WTNCA_NODRAWCAPTION = 1 Const WTNCA_NODRAWICON = 2 'API宣言ここまで TypeDef PDwmExtendFrameIntoClientArea = *Function(hwnd As HWND, ByRef MarInset As MARGINS) As HRESULT TypeDef PSetWindowThemeAttribute = *Function(hwnd As HWND, eAttribute As WINDOWTHEMEATTRIBUTETYPE, ByRef pvAttribute As Any, cbAttribute As DWord) As HRESULT TypeDef PDwmIsCompositionEnabled = *Function(ByRef fEnabled As BOOL) As HRESULT TypeDef PBeginBufferedPaint = *Function(hdcTarget As HDC, ByRef rcTarget As RECT, dwFormat As BP_BUFFERFORMAT, pPaintParams As *BP_PAINTPARAMS, ByRef hdc As HDC) As HPAINTBUFFER TypeDef PBufferedPaintSetAlpha = *Function(hBufferedPaint As HPAINTBUFFER, ByRef rc As RECT, alpha As DWord) As HRESULT TypeDef PBufferedPaintInit = *Function() As HRESULT TypeDef PGetBufferedPaintBits = *Function(hBufferedPaint As HPAINTBUFFER, ByRef pbBuffer As *RGBQUAD, ByRef cxRow As Long) As HRESULT TypeDef PEndBufferedPaint = *Function(hBufferedPaint As HPAINTBUFFER, fUpdateTarget As BOOL) As HRESULT Const BorderWidth = 6 'コメントアウトを外すと、エディットボックス部分が不透明になる。 '#define OPAQUE_EDITBOX Class MyForm Inherits Form Public Sub MyForm() AddResize(AddressOf(onResize)) AddPaintBackground(AddressOf(onPaintBackground)) AddMessageEvent(WM_CTLCOLORSTATIC, AddressOf(onCtlColorEditBox)) AddMessageEvent(WM_DWMCOMPOSITIONCHANGED, AddressOf(onCompositionChanged)) edit = New List CreateForm() Text = "ParallelBuild" Dim hdc = GetDC() hfont = CreateFont(-MulDiv(9, GetDeviceCaps(hdc, LOGPIXELSY), 72), 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, SHIFTJIS_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, "MS ゴシック") ReleaseDC(hdc) Dim wpFont = hfont As WPARAM Dim i As Long For i = 0 To 7 Dim e = New EditBox e.AddMessageEvent(WM_PAINT, AddressOf(onPaintEditBox)) e.Create(This, ES_MULTILINE Or ES_AUTOHSCROLL Or ES_AUTOVSCROLL Or ES_READONLY Or WS_HSCROLL Or WS_VSCROLL Or WS_VISIBLE, WS_EX_CLIENTEDGE) e.SendMessage(WM_SETFONT, wpFont, 0) e.BeginSubclass() edit.Add(e) Next thread = New Thread(AddressOf(ControlProcess)) thread.Start() hmodUxTheme = LoadLibrary("uxtheme") hmodDwmApi = LoadLibrary("dwmapi") If hmodUxTheme <> 0 Then pSetWindowThemeAttribute = GetProcAddress(hmodUxTheme, ToMBStr("SetWindowThemeAttribute")) As PSetWindowThemeAttribute pBufferedPaintUnInit = GetProcAddress(hmodUxTheme, ToMBStr("BufferedPaintUnInit")) As PBufferedPaintInit pBeginBufferedPaint = GetProcAddress(hmodUxTheme, ToMBStr("BeginBufferedPaint")) As PBufferedPaintInit pBufferedPaintSetAlpha = GetProcAddress(hmodUxTheme, ToMBStr("BufferedPaintSetAlpha")) As PBufferedPaintSetAlpha pEndBufferedPaint = GetProcAddress(hmodUxTheme, ToMBStr("EndBufferedPaint")) As PEndBufferedPaint pGetBufferedPaintBits = GetProcAddress(hmodUxTheme, ToMBStr("GetBufferedPaintBits")) As PGetBufferedPaintBits Dim pBufferedPaintInit = GetProcAddress(hmodUxTheme, ToMBStr("BufferedPaintInit")) As PBufferedPaintInit If pBufferedPaintInit <> 0 Then Dim hr = pBufferedPaintInit() If FAILED(hr) Then Debug End If End If If hmodDwmApi <> 0 Then pDwmIsCompositionEnabled = GetProcAddress(hmodDwmApi, ToMBStr("DwmIsCompositionEnabled")) As PDwmIsCompositionEnabled pDwmExtendFrameIntoClientArea = GetProcAddress(hmodDwmApi, ToMBStr("DwmExtendFrameIntoClientArea")) As PDwmExtendFrameIntoClientArea SendMessage(WM_DWMCOMPOSITIONCHANGED) End If End Sub Private hmodUxTheme As HMODULE hmodDwmApi As HMODULE pDwmIsCompositionEnabled As PDwmIsCompositionEnabled pDwmExtendFrameIntoClientArea As PDwmExtendFrameIntoClientArea pSetWindowThemeAttribute As PSetWindowThemeAttribute pBufferedPaintUnInit As PBufferedPaintInit pBeginBufferedPaint As PBeginBufferedPaint pBufferedPaintSetAlpha As PBufferedPaintSetAlpha pEndBufferedPaint As PEndBufferedPaint pGetBufferedPaintBits As PGetBufferedPaintBits Sub onCompositionChanged(sender As Object, e As MessageArgs) e.Handled = True useDwm = False If pDwmIsCompositionEnabled <> 0 Then Dim enabled As BOOL If SUCCEEDED(pDwmIsCompositionEnabled(enabled)) And enabled Then useDwm = True 'クライアント領域全体にガラス効果をかける。 Dim m = [-1, 0, 0, 0] As MARGINS pDwmExtendFrameIntoClientArea(This, m) 'タイトルバーのアイコン・文字列を消す。 Dim wo As WTA_OPTIONS wo.dwFlags = WTNCA_NODRAWCAPTION Or WTNCA_NODRAWICON wo.dwMask = WTNCA_NODRAWCAPTION Or WTNCA_NODRAWICON pSetWindowThemeAttribute(hwnd, WTA_NONCLIENT, wo, Len(wo)) End If End If Invalidate() End Sub Sub onDestroy(sender As Object, e As Args) DeleteObject(hfont) pBufferedPaintUnInit() If hmodUxTheme <> 0 Then FreeLibrary(hmodUxTheme) End If If hmodDwmApi <> 0 Then FreeLibrary(hmodDwmApi) End If End Sub Sub onResize(sender As Object, e As ResizeArgs) Dim i As Long For i = 0 To 7 Dim t = edit[i] t.Move((i Mod 4) * (e.X \ 4) + BorderWidth, (i \ 4) * (e.Y \ 2) + BorderWidth, e.X \ 4 - BorderWidth * 2, e.Y \ 2 - BorderWidth * 2) Next End Sub Sub onPaintBackground(sender As Object, e As PaintBackgroundArgs) If useDwm Then Dim hdc = e.Handle SetBkColor(hdc, 0) ExtTextOut(hdc, 0, 0, ETO_OPAQUE, ClientRect, "", 0, 0) End If End Sub Static Const backgroundColor = RGB(255, 255, 255) Static Const textColor = RGB(0, 0, 0) Sub onCtlColorEditBox(sender As Object, e As MessageArgs) Dim hdc = e.WParam As HDC SetTextColor(hdc, textColor) SetBkColor(hdc, backgroundColor) e.LResult = GetStockObject(NULL_BRUSH) As LRESULT e.Handled = True End Sub Sub onPaintEditBox(sender As Object, e As MessageArgs) Dim alpha = &hcc As DWord Dim i As Long, j As Long If useDwm Then Dim edit = sender As EditBox Dim ps As PAINTSTRUCT BeginPaint(e.HWnd, ps) Dim hdcMem As HDC Dim hpb = pBeginBufferedPaint(ps.hdc, ps.rcPaint, BPBF_TOPDOWNDIB, 0, hdcMem) If hpb <> 0 Then FillRect(hdcMem, ps.rcPaint, GetStockObject(WHITE_BRUSH) As HBRUSH) edit.DefWndProc(WM_PRINTCLIENT, hdcMem As WPARAM, PRF_CLIENT) #ifdef OPAQUE_EDITBOX pBufferedPaintSetAlpha(hpb, ps.rcPaint, 255) #else Dim cxRow As Long Dim p As *RGBQUAD pGetBufferedPaintBits(hpb, p, cxRow) Dim pdw = p As *DWord For i = 0 To ELM(ps.rcPaint.bottom - ps.rcPaint.top) For j = 0 To ELM(ps.rcPaint.right - ps.rcPaint.left) Dim rgb = pdw[i * cxRow + j] And &h00ffffff If rgb = textColor Then 'ClearType下で試すと、rgb <> backgroundColorよりこのほうが綺麗。 pdw[i * cxRow + j] Or= &hff000000 Else With p[i * cxRow + j] .rgbReserved = alpha As Byte .rgbRed = ((.rgbRed * alpha) >> 8) As Byte .rgbGreen = ((.rgbGreen * alpha) >> 8) As Byte .rgbBlue = ((.rgbBlue * alpha) >> 8) As Byte End With End If Next Next #endif pEndBufferedPaint(hpb, TRUE) End If EndPaint(e.HWnd, ps) e.Handled = True Else e.Handled = False End If End Sub Sub ControlProcess() Dim buildCmd[7] As PCTSTR buildCmd[0] = "build_basic_static_library(32bit - debug - unicode).bat" buildCmd[1] = "build_basic_static_library(32bit - debug).bat" buildCmd[2] = "build_basic_static_library(32bit - release - unicode).bat" buildCmd[3] = "build_basic_static_library(32bit - release).bat" buildCmd[4] = "build_basic_static_library(64bit - debug - unicode).bat" buildCmd[5] = "build_basic_static_library(64bit - debug).bat" buildCmd[6] = "build_basic_static_library(64bit - release - unicode).bat" buildCmd[7] = "build_basic_static_library(64bit - release).bat" Dim pathBase = "P:\PROGRAMS\ablib\ab5.0\ablib\build_batch\" Dim hProcess[7] As HANDLE Dim hPipe[7] As HANDLE Dim i As Long For i = 0 To 7 CreateBuildProcess(hProcess[i], hPipe[i], pathBase, buildCmd[i]) Next Dim buf[4095] As CHAR For i = 0 To 7 WaitForSingleObject(hProcess[i], INFINITE) Dim readSize As DWord ReadFile(hPipe[i], buf, Len(buf), VarPtr(readSize), ByVal 0) Dim s = New String(buf, readSize As Long) edit[i].SendMessage(WM_SETTEXT, 0, ToTCStr(s) As LPARAM) CloseHandle(hProcess[i]) CloseHandle(hPipe[i]) Next End Sub Sub CreateBuildProcess(ByRef hProcess As HANDLE, ByRef hPipeOutput As HANDLE, cmdPath As String, cmdLine As PCSTR) Dim hPipeRead As HANDLE, hPipeWrite As HANDLE Dim sa As SECURITY_ATTRIBUTES sa.nLength = Len(sa) sa.lpSecurityDescriptor = 0 sa.bInheritHandle = TRUE If CreatePipe(hPipeRead, hPipeWrite, VarPtr(sa), 0) = FALSE Then ThrowWithLastError() End If Dim si As STARTUPINFO Dim pi As PROCESS_INFORMATION si.cb = Len(si) si.dwFlags = STARTF_USESTDHANDLES si.hStdInput = GetStdHandle(STD_INPUT_HANDLE) si.hStdOutput = hPipeWrite si.hStdError = hPipeWrite If CreateProcess(0, ToTCStr(Ex"\q" & cmdPath & cmdLine & Ex"\q"), ByVal 0, ByVal 0, TRUE, CREATE_NO_WINDOW, 0, ToTCStr(cmdPath), si, pi) = FALSE Then ThrowWithLastError() End If CloseHandle(pi.hThread) hPipeOutput = hPipeRead hProcess = pi.hProcess End Sub edit As List thread As Thread hfont As HFONT useDwm As Boolean End Class Control.Initialize(GetModuleHandle(0)) Dim f = New MyForm Application.Run(f)