Я хочу использовать GDI + со сценариями Pascal, которые изначально не предоставляют GDI +, но я не знаю, почему. При использовании dll (shared) процесс не завершится, даже когда окно разрушено, я имею в виду, что явсе еще может видеть процесс, запущенный из диспетчера задач, хотя у него нет никакого окна, чтобы видеть.Процесс остается бездействующим, т.е. без использования ресурсов
В моем dll для каждого нового hwnd я перехватываю свой собственный wndproc, а в сообщении WM_Paint я рисую указанные объекты, которые до сих пор просят нарисовать
Я экспортирую символ DrawRectangle для рисования и компиляции для 32-битного
моего 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
void msg(const char *str) { MessageBoxA(nullptr, str, "Message", 0); }
void msg(const wchar_t *str) { MessageBoxW(nullptr, str, L"Message", 0); }
class _GdiManager {
public:
_GdiManager() {
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr);
}
~_GdiManager() { 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);
}
LRESULT CallOriginalWndProc(HWND hwnd, UINT uMsg, WPARAM wParam,
LPARAM lParam) {
return CallWindowProcW(m_OriginalWindowProc, hwnd, uMsg, wParam, lParam);
}
LRESULT Paint(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
if (uMsg == WM_PAINT) {
for (auto &o : m_Objects)
o->draw(m_Graphics);
} else if (uMsg == WM_DESTROY) {
PostQuitMessage(0);
}
return 0;
}
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];
auto r = p->CallOriginalWndProc(hwnd, uMsg, wParam, lParam);
p->Paint(hwnd, uMsg, wParam, lParam);
return r;
}
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;
}
хост-программы:
//#include "gdi.cpp"
#include <ObjIdl.h>
#include <Windows.h>
#include <cassert>
#include <gdiplus.h>
using namespace Gdiplus;
#pragma comment(lib, "Gdiplus.lib")
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, INT iCmdShow) {
HWND hWnd;
MSG msg;
WNDCLASS wndClass;
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WndProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = TEXT("GettingStarted");
RegisterClass(&wndClass);
hWnd = CreateWindow(TEXT("GettingStarted"), // window class name
TEXT("Getting Started"), // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL); // creation parameters
ShowWindow(hWnd, iCmdShow);
UpdateWindow(hWnd);
auto dll = LoadLibraryW(L"isGDI.dll");
assert(dll);
auto DrawRectangle = (int(__stdcall *)(
HWND, DWORD, int, int, int, int))GetProcAddress(dll, "DrawRectangle");
assert(DrawRectangle);
DrawRectangle(hWnd, 0xffff0000, 0, 0, 100, 100);
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
FreeLibrary(dll);
return msg.wParam;
} // WinMain
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
LPARAM lParam) {
return DefWindowProc(hWnd, message, wParam, lParam);
} // WndProc
также, программабудет работать как положено, если я вызову DrawRectangle напрямую через исходный код (без использования DLL)