delphi - Inno.TLabel 在使用 GDI+ 时未显示
问题描述
我正在尝试通过 DLL 将 GDI+ 与 Inno 一起使用,以获得抗锯齿和其他好处。
但我无法将 Inno 自己的 Tlabel 与 DLL 一起使用。通过 GDI+ 创建任何对象时。TLabel 不会出现。虽然我能够绘制 TPanel,但 TLabel 似乎根本不起作用(出现)。
主办国际空间站:
[Defines]
#define AppName "AppName"
#define AppVersion "0.1"
#define Color "$d03a1d"
[Setup]
AppName={#AppName}
AppVersion={#AppVersion}
DefaultDirName=./
Compression=none
[Code]
#define GDIDLLPATH "E:\Cpp\Projects\Build\build-GDI\build-GDI-msvc_x32-Release\MinimalGID.dll"
type
ARGB = DWORD;
var
l :TLabel;
function DrawRectangle(h : HWND; LineColor: ARGB;startX: integer;startY: integer; width,
height: integer): integer;
external 'DrawRectangle@{#GDIDLLPATH} stdcall delayload';
procedure gdishutdown();
external 'gdishutdown@{#GDIDLLPATH} stdcall delayload';
function Createlabel(hParent:TWInControl; hAutoSize,hWordwrap:Boolean;l,t,w,h:Integer; FSize,FColor:TColor;hCaption,hFontName:String;hAlignment: TAlignment):TLabel;
begin
Result := TLAbel.Create(hParent);
with Result do
begin
Parent:=hParent;
AutoSize:=hAutoSize;
SetBounds(l,t,w,h);
WordWrap := hWordWrap;
with Font do
begin
Name:= hFontName;
Size:=Fsize;
Color:=FColor;
end;
Alignment:=hAlignment;
Caption:= hCaption;
BringToFront;
end;
end;
function CreateDefaultTxt(hParent :TWinControl; hLeft, hTop,hFontSize : Integer;hColor: TColor; hTxt : String): TLabel;
begin
Result := Createlabel(hParent,true,false,hLeft,hTop,0,0,hFontSize,hColor,hTxt,'Segoe UI',taLeftJustify);
end;
procedure InitializeWizard();
begin
with WizardForm do
begin
BorderStyle := bsNone;
ClientWidth:=800;
ClientHeight:=480;
Center;
OuterNotebook.Hide;
InnerNotebook.Hide;
Bevel.Hide;
PageNameLabel.Hide;
PageDescriptionLabel.Hide;
MainPanel.Hide;
BackButton.SetBounds(0,0,0,0);
NextButton.SetBounds(0,0,0,0);
CancelButton.SetBounds(0,0,0,0);
DirBrowseButton.SetBounds(0,0,0,0);
GroupBrowseButton.SetBounds(0,0,0,0);
l := CreateDefaultTxt(WizardForm,500,10,98,clRed,'Txt');
DrawRectangle(Handle,$23000000,0,-6,Width,40);
end;
end;
procedure DeinitializeSetup();
begin
gdishutdown;
end;
如果 DrawRectangle() 被删除,TLabel 将正确显示。
我的 DLL:
#include <Windows.h>
#include <gdiplus.h>
using namespace Gdiplus;
#include <objidl.h>
#pragma comment(lib, "Gdiplus.lib")
#include <functional>
#include <map>
#include <memory>
#include <vector>
#define DLL_EXPORT(RETURN_TYPE) \
extern "C" __declspec(dllexport) RETURN_TYPE __stdcall
class _GdiManager {
public:
_GdiManager() {
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr);
}
void shutdown() { GdiplusShutdown(gdiplusToken); }
private:
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
} GdiManager;
class DrawableObject {
public:
virtual void draw(Gdiplus::Graphics &Graphics) = 0;
virtual ~DrawableObject() = default;
};
namespace DrawableObjects {
class Rectangle : public DrawableObject {
public:
Rectangle(ARGB Color, int X, int Y, int Width, int Height)
: m_X{X}, m_Y{Y}, m_Width{Width}, m_Height{Height}, m_Brush{Color} {}
void draw(Gdiplus::Graphics &graphics) override {
graphics.FillRectangle(&m_Brush, m_X, m_Y, m_Width, m_Height);
}
private:
int m_X, m_Y, m_Width, m_Height;
Gdiplus::SolidBrush m_Brush;
};
} // namespace DrawableObjects
LRESULT MasterWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
class Painter {
public:
Painter(HWND hWnd) : m_WindowHandle{hWnd}, m_Graphics{hWnd} {
m_OriginalWindowProc = (WNDPROC)GetWindowLongW(m_WindowHandle, GWL_WNDPROC);
SetWindowLongW(m_WindowHandle, GWL_WNDPROC, (LONG)MasterWindowProc);
}
~Painter() {
SetWindowLongW(m_WindowHandle, GWL_WNDPROC, (LONG)m_OriginalWindowProc);
}
LRESULT CallOriginalWndProc(HWND hwnd, UINT uMsg, WPARAM wParam,
LPARAM lParam) {
return CallWindowProcW(m_OriginalWindowProc, hwnd, uMsg, wParam, lParam);
}
void Paint(LPPAINTSTRUCT ps) {
for (auto &o : m_Objects)
o->draw(m_Graphics);
}
std::vector<std::unique_ptr<DrawableObject>> &Objects() { return m_Objects; }
private:
HWND m_WindowHandle;
Gdiplus::Graphics m_Graphics;
WNDPROC m_OriginalWindowProc;
std::vector<std::unique_ptr<DrawableObject>> m_Objects;
};
std::map<HWND, std::unique_ptr<Painter>> windowPaint;
LRESULT MasterWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
auto &p = windowPaint[hwnd];
if (uMsg == WM_PAINT) {
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
p->Paint(&ps);
EndPaint(hwnd, &ps);
} else if (uMsg == WM_DESTROY)
PostQuitMessage(0);
return p->CallOriginalWndProc(hwnd, uMsg, wParam, lParam);
}
auto &insertPainter(HWND hwnd) {
auto &my_painter = windowPaint[hwnd];
if (!my_painter)
my_painter = std::make_unique<Painter>(hwnd);
return my_painter;
}
DLL_EXPORT(int)
DrawRectangle(HWND hwnd, ARGB LineColor, int startX, int startY, int width,
int height) {
auto &my_painter = insertPainter(hwnd);
my_painter->Objects().push_back(std::make_unique<DrawableObjects::Rectangle>(
LineColor, startX, startY, width, height));
return 0;
}
DLL_EXPORT(void) gdishutdown() {
windowPaint.clear();
GdiManager.shutdown();
}
在 DLL 中,对于每个要绘制的对象,我捕获父级的 WndProc 以在 WM_PAINT 上绘图,并在 WM_PAINT 上绘图后调用其原始 WndProc。这样我就不需要主机手动捕获父级的 WndProc 进行绘图
解决方案
推荐阅读
- akka - 为什么 Flink 使用 Akka 进行 rpc?
- sql - 使用 CASE stmt 的 SQL 查询中不针对其他值的字段的 1 个值的计数
- python - Python:使用“import csv”从 S3 存储桶读取 CSV
- sql-server - 代码循环遍历列,但不将结果添加到新表中
- java - 如何获得通用类型的列表,或者如果不可能解决提供的任务?
- reactjs - 如何在酶测试用例中传递 Redirect 的道具
- css - React 组件和 CSS:对同一元素中的项目进行不同的样式设置
- oracle - 如何在 Oracle 中使用非 Ascii 字符在 Oracle 中插入 Blob 列?
- reactjs - 在 npm run 弹出后我们可以使用外部 css 文件吗?
- kerberos - 如何将 keytab 文件传递给正在部署在 pcf 上的应用程序