Inno.TLabel not showing on using GDI+ - delphi

I am trying to use GDI+ with Inno through DLL for antialiasing and other benefits.
But I can't able to use Inno's own Tlabel with DLL. When creating any object through GDI+. The TLabel will not show up. Though I am able to draw TPanel but TLabel doesn't seems to work at all(show up).
Host ISS:
[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;
TLabel will show up correctly if DrawRectangle() is removed.
My 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();
}
in DLL, for every Object to draw, I capture the Parent's WndProc for Drawing on WM_PAINT and call its original WndProc after Drawing on WM_PAINT. This way I don't need host to Manually Capture Parent's WndProc for Drawing

Related

Screenshot not show mouse cursor when is moved to second monitor

I have been doing a lot of work lately with taking screenshots (for a remote desktop system) and just stumbled across a problem while I'm trying to implement support for multiple monitors. While taking the screenshot is OK, the method I'm using to draw the cursor only presumes 1 screen. If I position the pointer on an additional screen (when taking a screenshot of that additional screen), the cursor does NOT show. I move the pointer to the main screen and it shows (of course in the wrong spot because it's the wrong screen).
My code is entirely below.
program Test;
{$APPTYPE CONSOLE}
{$R *.res}
uses
Windows,
vcl.Graphics,
SysUtils;
function GetCursorInfo2: TCursorInfo;
var
hWindow: HWND;
pt: TPoint;
dwThreadID, dwCurrentThreadID: DWORD;
begin
Result.hCursor := 0;
ZeroMemory(#Result, SizeOf(Result));
if GetCursorPos(pt) then
begin
Result.ptScreenPos := pt;
hWindow := WindowFromPoint(pt);
if IsWindow(hWindow) then
begin
dwThreadID := GetWindowThreadProcessId(hWindow, nil);
dwCurrentThreadID := GetCurrentThreadId;
if (dwCurrentThreadID <> dwThreadID) then
begin
if AttachThreadInput(dwCurrentThreadID, dwThreadID, True) then
begin
Result.hCursor := GetCursor;
AttachThreadInput(dwCurrentThreadID, dwThreadID, False);
end;
end
else
Result.hCursor := GetCursor;
end;
end;
end;
procedure TakeScreenshot(var Bmp: TBitmap; WndHdc: HDC; Width, Height, Left, Top: Integer);
const
CAPTUREBLT = $40000000;
var
DesktopCanvas: TCanvas;
MyCursor: TIcon;
CursorInfo: TCursorInfo;
IconInfo: TIconInfo;
DC: HDC;
begin
DC := GetDC(WndHdc);
try
if (DC = 0) then
Exit;
Bmp.Width := Width;
Bmp.Height := Height;
DesktopCanvas := TCanvas.Create;
try
DesktopCanvas.Handle := DC;
BitBlt(Bmp.Canvas.Handle, 0, 0, Bmp.Width, Bmp.Height, DesktopCanvas.Handle, Left, Top, SRCCOPY or CAPTUREBLT);
MyCursor := TIcon.Create;
try
CursorInfo := GetCursorInfo2;
if CursorInfo.hCursor <> 0 then
begin
MyCursor.Handle := CursorInfo.hCursor;
GetIconInfo(CursorInfo.hCursor, IconInfo);
Bmp.Canvas.Draw(CursorInfo.ptScreenPos.X - IconInfo.xHotspot, CursorInfo.ptScreenPos.Y - IconInfo.yHotspot, MyCursor);
end;
finally
MyCursor.ReleaseHandle;
MyCursor.Free;
end;
finally
DesktopCanvas.Free;
end;
finally
if (DC <> 0) then
ReleaseDC(0, DC);
end;
end;
function EnumDisplayMonitors(dc: HDC; rect: PRect; EnumProc: pointer; lData: Integer): Boolean; stdcall; external user32 name 'EnumDisplayMonitors';
type
TMonInfo = record
h: THandle;
DC: HDC;
R: TRect;
end;
var
MonList: array of TMonInfo;
function MonitorEnumProc(hMonitor: THandle; hdcMonitor: HDC; lprcMonitor: DWORD; dwData: Integer): Boolean; stdcall;
var
I, Width, Height, Left, Top: Integer;
Bmp: TBitmap;
begin
I := High(MonList) + 1;
SetLength(MonList, I + 1);
MonList[I].h := hMonitor;
MonList[I].DC := hdcMonitor;
MonList[I].R := PRect(lprcMonitor)^;
Left := PRect(lprcMonitor)^.Left;
Top := PRect(lprcMonitor)^.Top;
Width := PRect(lprcMonitor)^.Width;
Height := PRect(lprcMonitor)^.Height;
Bmp := TBitmap.Create;
try
TakeScreenshot(Bmp, hdcMonitor, Width, Height, Left, Top);
Bmp.SaveToFile('C:\Screen' + IntToStr(I + 1) + '.bmp');
finally
Bmp.Free;
end;
Result := True;
end;
procedure Main;
var
S: string;
I: Integer;
begin
Writeln('Number of monitors: ' + IntToStr(High(MonList) + 1) + #13#10);
Writeln('-----------------');
for I := 0 to High(MonList) do
with MonList[I] do
begin
S := #13#10 + 'Handle: ' + IntToStr(h) + #13#10 + 'Dc: ' + IntToStr(DC) + #13#10 + 'Size: ' + IntToStr(R.Right) + 'x' + IntToStr(R.Bottom) + #13#10;
Writeln(S);
Writeln('-----------------');
end;
end;
begin
try
EnumDisplayMonitors(0, nil, Addr(MonitorEnumProc), 0);
Main;
Writeln(#13#10 + 'Connected: ' + IntToStr(GetSystemMetrics(SM_CMONITORS)) + #13#10);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
The issue was that the cursor coordinates you get from GetCursorInfo2 are not the correct coordinates relative to your Bitmap.
First, determine whether the cursor point is in the lprcMonitor, you ccould use PtInRect, and then use DrawIcon to draw the hcursor into the bitmap, if it returns true.
Here is an C++ sample convert from your code(since I am not familiar with delphi):
#include <windows.h>
#include <iostream>
#include <string>
#include <string.h>
#include <stdlib.h>
#include <gdiplus.h>
#include <stdio.h>
using namespace Gdiplus;
using namespace std;
#pragma comment(lib, "Gdiplus.lib")
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
UINT num = 0; // number of image encoders
UINT size = 0; // size of the image encoder array in bytes
ImageCodecInfo* pImageCodecInfo = NULL;
GetImageEncodersSize(&num, &size);
if (size == 0)
return -1; // Failure
pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
if (pImageCodecInfo == NULL)
return -1; // Failure
GetImageEncoders(num, size, pImageCodecInfo);
for (UINT j = 0; j < num; ++j)
{
if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0)
{
*pClsid = pImageCodecInfo[j].Clsid;
free(pImageCodecInfo);
return j; // Success
}
}
free(pImageCodecInfo);
return -1; // Failure
}
//HCURSOR GetCursorInfo2(POINT * pt)
//{
// POINT p = { 0 };
// HWND hWindow = NULL;
// HCURSOR hCursor = NULL;
// if (GetCursorPos(&p))
// {
// pt->x = p.x;
// pt->y = p.y;
// hWindow = WindowFromPoint(*pt);
// if (IsWindow(hWindow))
// {
// DWORD dwThreadID = GetWindowThreadProcessId(hWindow, NULL);
// DWORD dwCurrentThreadID = GetCurrentThreadId();
// if (dwCurrentThreadID != dwThreadID)
// {
// if (AttachThreadInput(dwCurrentThreadID, dwThreadID, TRUE))
// {
// hCursor = GetCursor();
// AttachThreadInput(dwCurrentThreadID, dwThreadID, FALSE);
// }
// }
// }
// }
// return hCursor;
//}
void TakeScreenshot(HDC hdcbmp, HDC WndHdc, int Width, int Height, int Left, int Top)
{
HDC hdc = GetDC(NULL);
if (hdc == 0) exit(-1);
BitBlt(hdcbmp, 0, 0, Width, Height, hdc, Left, Top, SRCCOPY | CAPTUREBLT);
CURSORINFO cursorinfo = { 0 };
cursorinfo.cbSize = sizeof(CURSORINFO);
if (GetCursorInfo(&cursorinfo))
{
RECT rc = { Left ,Top,Left + Width ,Top + Height };
if (PtInRect(&rc, cursorinfo.ptScreenPos))
{
DrawIcon(hdcbmp, cursorinfo.ptScreenPos.x - Left, cursorinfo.ptScreenPos.y - Top, cursorinfo.hCursor);
}
}
/*ICONINFO IconInfo = { 0 };
GetIconInfo(hCursor, &IconInfo);*/
}
BOOL CALLBACK Monitorenumproc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
{
static int count = 0;
int Left = lprcMonitor->left;
int Top = lprcMonitor->top;
int Width = lprcMonitor->right - lprcMonitor->left;
int Height = lprcMonitor->bottom - lprcMonitor->top;
HDC dev = GetDC(NULL);
HDC CaptureDC = CreateCompatibleDC(dev);
HBITMAP CaptureBitmap = CreateCompatibleBitmap(dev, Width, Height);
HGDIOBJ old_obj = SelectObject(CaptureDC, CaptureBitmap);
TakeScreenshot(CaptureDC, dev, Width, Height, Left, Top);
Gdiplus::Bitmap bitmap(CaptureBitmap, NULL);
CLSID pngClsid;
GetEncoderClsid(L"image/bmp", &pngClsid);
wstring BmpNameString = L"C:\\screen";
BmpNameString = BmpNameString + std::to_wstring(count) + L".bmp";
count++;
bitmap.Save(BmpNameString.c_str(), &pngClsid, NULL);
SelectObject(CaptureDC, old_obj);
DeleteDC(CaptureDC);
ReleaseDC(NULL, dev);
DeleteObject(CaptureBitmap);
return TRUE;
}
int main(void)
{
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
EnumDisplayMonitors(0, NULL, Monitorenumproc, 0);
GdiplusShutdown(gdiplusToken);
return 0;
}
And attention to these lines in function TakeScreenshot:
CURSORINFO cursorinfo = { 0 };
cursorinfo.cbSize = sizeof(CURSORINFO);
if (GetCursorInfo(&cursorinfo))
{
RECT rc = { Left ,Top,Left + Width ,Top + Height };
if (PtInRect(&rc, cursorinfo.ptScreenPos))
{
DrawIcon(hdcbmp, cursorinfo.ptScreenPos.x - Left, cursorinfo.ptScreenPos.y - Top, cursorinfo.hCursor);
}
}

How to eliminate header artifacts during tracking - HDN_TRACK?

When doing "real time" tracking, the header control occasionally leaves artifacts behind, as the image below shows:
The first two images are from the attached program. The third image (without the blue coloring) is from Windows Explorer.
To get the artifacts, simply drag the separator off the right side of program's window right edge and bring it back quickly into view. It may take a couple of tries, depending on how quickly you bring the separator back into the window.
Windows Explorer avoids the problem by having the header not paint that black vertical bar when dragging.
EDIT: As Sertac below pointed out, Windows Explorer uses a different control, which is why it does not exhibit the problem.
I have two (2) questions:
How does one tell the header control not to paint that vertical black bar? I couldn't find anything in the documentation on that.
If getting rid of the black bar is not possible without "owner-drawing" the header, is there some way to prevent the artifact from appearing?
The program I am using to test the header control is below.
{$LONGSTRINGS OFF}
{$WRITEABLECONST ON}
{$ifdef WIN32} { tell Windows we want v6 of commctrl }
{$R Manifest32.res}
{$endif}
{$ifdef WIN64}
{$R Manifest64.res}
{$endif}
program _Header_Track;
uses Windows, Messages, CommCtrl;
const
ProgramName = 'Header_Track';
{-----------------------------------------------------------------------------}
{$ifdef VER90} { Delphi 2.0 }
type
ptrint = longint;
ptruint = dword;
const
ICC_WIN95_CLASSES = $000000FF; { missing in Delphi 2 }
type
TINITCOMMONCONTROLSEX = packed record
dwSize : DWORD;
dwICC : DWORD;
end;
PINITCOMMONCONTROLSEX = ^TINITCOMMONCONTROLSEX;
function InitCommonControlsEx(var InitClasses : TINITCOMMONCONTROLSEX)
: BOOL; stdcall; external comctl32;
{$endif}
{$ifdef VER90}
// for Delphi 2.0 define GetWindowLongPtr and SetWindowLongPtr as synonyms of
// GetWindowLong and SetWindowLong respectively.
function GetWindowLongPtr(Wnd : HWND;
Index : ptrint)
: ptruint; stdcall; external 'user32' name 'GetWindowLongA';
function SetWindowLongPtr(Wnd : HWND;
Index : ptrint;
NewLong : DWORD)
: ptruint; stdcall; external 'user32' name 'SetWindowLongA';
function GetClassLongPtr(Wnd : HWND;
Index : ptrint)
: ptruint; stdcall; external 'user32' name 'GetClassLongA';
function SetClassLongPtr(Wnd : HWND;
Index : ptrint;
NewLong : ptruint)
: ptruint; stdcall; external 'user32' name 'SetClassLongA';
{$endif}
{$ifdef FPC}
{ make the FPC definitions match Delphi's }
type
THDLAYOUT = record
Rect : PRECT;
WindowPos : PWINDOWPOS;
end;
PHDLAYOUT = ^THDLAYOUT;
function Header_Layout(Wnd : HWND; Layout : PHDLAYOUT) : WINBOOL; inline;
begin
Header_Layout := WINBOOL(SendMessage(Wnd, HDM_LAYOUT, 0, ptruint(Layout)));
end;
{$endif}
{-----------------------------------------------------------------------------}
function WndProc (Wnd : HWND; Msg : UINT; wParam, lParam : ptrint)
: ptrint; stdcall;
{ main application/window handler function }
const
HEADER_ID = 1000;
HEADER_ITEMS_WIDTH = 100;
Header : HWND = 0;
HeaderText : packed array[0..2] of pchar =
(
'Name',
'Date modified',
'Type'
);
var
ControlsInit : TINITCOMMONCONTROLSEX;
HeaderPos : TWINDOWPOS;
HeaderRect : TRECT;
HeaderNotification : PHDNOTIFY absolute lParam; { note overlay on lParam }
HeaderLayout : THDLAYOUT;
HeaderItem : THDITEM;
ClientRect : TRECT;
Style : ptruint;
i : integer;
begin
WndProc := 0;
case Msg of
WM_CREATE:
begin
{ initialize the common controls library }
with ControlsInit do
begin
dwSize := sizeof(ControlsInit);
dwICC := ICC_WIN95_CLASSES; { includes headers }
end;
InitCommonControlsEx(ControlsInit);
{ create the header control }
Header := CreateWindowEx(0,
WC_HEADER, { class name }
nil, { caption }
HDS_BUTTONS or
WS_CHILD or
WS_VISIBLE or
WS_CLIPCHILDREN or
WS_CLIPSIBLINGS,
0, { at parent x = 0 }
0, { y = 0 }
0, { width }
0, { height }
Wnd, { parent }
HEADER_ID, { child id }
hInstance,
nil);
if Header = 0 then
begin
MessageBox(Wnd,
'Couldn''t create a header',
'Main Window - WM_CREATE',
MB_ICONERROR or MB_OK);
WndProc := -1; { abort window creation }
exit;
end;
{ remove the annoying double click behavior of the header buttons }
Style := GetClassLongPtr(Header, GCL_STYLE);
Style := Style and (not CS_DBLCLKS);
SetClassLongPtr(Header, GCL_STYLE, Style);
{ tell the header which font to use }
SendMessage(Header, WM_SETFONT, GetStockObject(DEFAULT_GUI_FONT), 0);
{ insert the column header in the header control }
with HeaderItem do
for i := low(HeaderText) to high(HeaderText) do
begin
mask := HDI_FORMAT or HDI_TEXT or HDI_WIDTH;
pszText := HeaderText[i];
fmt := HDF_STRING;
cxy := HEADER_ITEMS_WIDTH; { width }
Header_InsertItem(Header, i, HeaderItem);
end;
exit;
end;
WM_SIZE:
begin
{ update the header size and location }
with HeaderLayout do
begin
WindowPos := #HeaderPos;
Rect := #HeaderRect;
end;
GetClientRect(Wnd, ClientRect);
CopyRect(HeaderRect, ClientRect);
ZeroMemory(#HeaderPos, sizeof(HeaderPos));
Header_Layout(Header, #HeaderLayout); { updates HeaderPos }
{ use HeaderPos to place the header where it should be in the window }
with HeaderPos do
begin
SetWindowPos(Header,
Wnd, x, y, cx, cy,
Flags);
end;
exit;
end; { WM_SIZE }
WM_NOTIFY:
begin
case HeaderNotification^.Hdr.Code of
HDN_BEGINTRACK:
begin
{ Allow dragging using the left mouse button only }
if HeaderNotification^.Button <> 0 then
begin
WndProc := ptrint(TRUE); { don't track }
exit;
end;
exit;
end;
HDN_TRACK:
begin
{ tell the header to resize itself }
Header_SetItem(Header,
HeaderNotification^.Item,
HeaderNotification^.pitem^);
exit;
end;
end;
end;
WM_DESTROY:
begin
PostQuitMessage(0);
exit;
end;
end; { case msg }
WndProc := DefWindowProc (Wnd, Msg, wParam, lParam);
end;
{-----------------------------------------------------------------------------}
function InitAppClass: WordBool;
{ registers the application's window classes }
var
cls : TWndClassEx;
begin
cls.cbSize := sizeof(TWndClassEx); { must be initialized }
if not GetClassInfoEx (hInstance, ProgramName, cls) then
begin
with cls do
begin
style := CS_BYTEALIGNCLIENT;
lpfnWndProc := #WndProc;
cbClsExtra := 0;
cbWndExtra := 0;
hInstance := system.hInstance;
hIcon := 0;
hCursor := LoadCursor(0, IDC_ARROW);
hbrBackground := COLOR_WINDOW + 1;
lpszMenuName := nil;
lpszClassName := ProgramName;
hIconSm := 0;
end;
InitAppClass := WordBool(RegisterClassEx(cls));
end
else InitAppClass := TRUE;
end;
{-----------------------------------------------------------------------------}
function WinMain : integer;
{ application entry point }
var
Wnd : HWND;
Msg : TMsg;
begin
if not InitAppClass then Halt (255); { register application's class }
{ Create the main application window }
Wnd := CreateWindowEx(WS_EX_CLIENTEDGE,
ProgramName, { class name }
ProgramName, { window caption text }
ws_OverlappedWindow or { window style }
ws_SysMenu or
ws_MinimizeBox or
ws_ClipSiblings or
ws_ClipChildren or { don't affect children }
ws_visible, { make showwindow unnecessary }
20, { x pos on screen }
20, { y pos on screen }
600, { window width }
200, { window height }
0, { parent window handle }
0, { menu handle 0 = use class }
hInstance, { instance handle }
nil); { parameter sent to WM_CREATE }
if Wnd = 0 then Halt; { could not create the window }
while GetMessage (Msg, 0, 0, 0) do { wait for message }
begin
TranslateMessage (Msg); { key conversions }
DispatchMessage (Msg); { send to window procedure }
end;
WinMain := Msg.wParam; { terminate with return code }
end;
begin
WinMain;
end.
This is an artifact caused by attempting to use the control in two different functionality modes at the same time. That, and of course fast mouse movement...
The black vertical line is actually the indicator that hints the final separator position when the mouse button will be released. Of course this indicator is only to be used when the header control does not reflect column resizing at real time.
You are, however, resizing the column at real time responding to the tracking notification. You should instead use the header control in live column drag mode and so that the indicator will not be drawn at all.
In summary, include HDS_FULLDRAG control style:
Header := CreateWindowEx(0,
WC_HEADER, { class name }
nil, { caption }
HDS_BUTTONS or
WS_CHILD or
WS_VISIBLE or
WS_CLIPCHILDREN or
WS_CLIPSIBLINGS or
HDS_FULLDRAG,
0, { at parent x = 0 }
0, { y = 0 }
0, { width }
0, { height }
Wnd, { parent }
HEADER_ID, { child id }
hInstance,
nil);
and leave out the track notification:
...
{ // don't tell the header to resize, it will do it itself
HDN_TRACK:
begin
// tell the header to resize itself
Header_SetItem(Header,
HeaderNotification^.Item,
HeaderNotification^.pitem^);
exit;
end;
}
...

Accessing properties of classes wrapped with "DelphiInterface"

I have a FMX project in C++Builder 10.2 Tokyo that is targeted for Android only. I am trying to make use of the Camera2 API. I used the Java2Pas tool to create the Delphi interfaces and classes that I need, combining them into a single Pascal file which I have added to my C++ project.
Parts of this pascal file look like this:
JTextureView_SurfaceTextureListenerClass = interface(JObjectClass)
['{106DB13E-C1B4-4898-B906-0143D97C0075}']
function onSurfaceTextureDestroyed(JSurfaceTextureparam0 : JSurfaceTexture) : boolean; cdecl;// (Landroid/graphics/SurfaceTexture;)Z A: $401
procedure onSurfaceTextureAvailable(JSurfaceTextureparam0 : JSurfaceTexture; Integerparam1 : Integer; Integerparam2 : Integer) ; cdecl;// (Landroid/graphics/SurfaceTexture;II)V A: $401
procedure onSurfaceTextureSizeChanged(JSurfaceTextureparam0 : JSurfaceTexture; Integerparam1 : Integer; Integerparam2 : Integer) ; cdecl;// (Landroid/graphics/SurfaceTexture;II)V A: $401
procedure onSurfaceTextureUpdated(JSurfaceTextureparam0 : JSurfaceTexture) ; cdecl;// (Landroid/graphics/SurfaceTexture;)V A: $401
end;
[JavaSignature('android/view/TextureView_SurfaceTextureListener')]
JTextureView_SurfaceTextureListener = interface(JObject)
['{58A7FBD1-27B9-44AC-B013-F077E1BF5975}']
function onSurfaceTextureDestroyed(JSurfaceTextureparam0 : JSurfaceTexture) : boolean; cdecl;// (Landroid/graphics/SurfaceTexture;)Z A: $401
procedure onSurfaceTextureAvailable(JSurfaceTextureparam0 : JSurfaceTexture; Integerparam1 : Integer; Integerparam2 : Integer) ; cdecl;// (Landroid/graphics/SurfaceTexture;II)V A: $401
procedure onSurfaceTextureSizeChanged(JSurfaceTextureparam0 : JSurfaceTexture; Integerparam1 : Integer; Integerparam2 : Integer) ; cdecl;// (Landroid/graphics/SurfaceTexture;II)V A: $401
procedure onSurfaceTextureUpdated(JSurfaceTextureparam0 : JSurfaceTexture) ; cdecl;// (Landroid/graphics/SurfaceTexture;)V A: $401
end;
TJTextureView_SurfaceTextureListener = class(TJavaGenericImport<JTextureView_SurfaceTextureListenerClass, JTextureView_SurfaceTextureListener>)
end;
The TJTextureView_SurfaceTextureListener interface needs to be used as a callback object, so I added some event handlers to it and changed it to look like this:
TOnSurfaceTextureDestroyed = function(aSurface: JSurfaceTexture): Boolean of object;
TOnSurfaceTextureUpdated = procedure(aSurface: JSurfaceTexture) of object;
TOnSurfaceTextureSize = procedure(aSurface: JSurfaceTexture; aWidth:Integer; aHeight: Integer) of object;
TJTextureView_SurfaceTextureListener = class(TJavaGenericImport<JTextureView_SurfaceTextureListenerClass, JTextureView_SurfaceTextureListener>)
protected
FOnTextureDestroyed: TOnSurfaceTextureDestroyed;
FOnTextureUpdated: TOnSurfaceTextureUpdated;
FOnTextureAvailable: TOnSurfaceTextureSize;
FOnTextureSizeChanged: TOnSurfaceTextureSize;
public
function onSurfaceTextureDestroyed(aSurface : JSurfaceTexture) : boolean; cdecl;
procedure onSurfaceTextureAvailable(aSurface : JSurfaceTexture; aWidth : Integer; aHeight : Integer) ; cdecl;
procedure onSurfaceTextureSizeChanged(aSurface : JSurfaceTexture; aWidth : Integer; aHeight : Integer) ; cdecl;
procedure onSurfaceTextureUpdated(aSurface : JSurfaceTexture) ; cdecl;
property OnTextureDestroyed: TOnSurfaceTextureDestroyed read FOnTextureDestroyed write FOnTextureDestroyed;
property OnTextureUpdated: TOnSurfaceTextureUpdated read FOnTextureUpdated write FOnTextureUpdated;
property OnTextureAvailable: TOnSurfaceTextureSize read FOnTextureAvailable write FOnTextureAvailable;
property OnTextureSizeChanged: TOnSurfaceTextureSize read FOnTextureSizeChanged write FOnTextureSizeChanged;
end;
implementation
{ TJTextureView_SurfaceTextureListener }
procedure TJTextureView_SurfaceTextureListener.onSurfaceTextureAvailable(aSurface: JSurfaceTexture; aWidth, aHeight: Integer);
begin
if Assigned(FOnTextureAvailable) then
FOnTextureAvailable(aSurface, aWidth, aHeight);
end;
function TJTextureView_SurfaceTextureListener.onSurfaceTextureDestroyed(aSurface: JSurfaceTexture): boolean;
begin
if Assigned(FOnTextureDestroyed) then
Result := FOnTextureDestroyed(aSurface)
else
Result := False;
end;
procedure TJTextureView_SurfaceTextureListener.onSurfaceTextureSizeChanged(aSurface: JSurfaceTexture; aWidth, aHeight: Integer);
begin
if Assigned(FOnTextureSizeChanged) then
FOnTextureSizeChanged(aSurface, aWidth, aHeight);
end;
procedure TJTextureView_SurfaceTextureListener.onSurfaceTextureUpdated(aSurface: JSurfaceTexture);
begin
if Assigned(FOnTextureUpdated) then
FOnTextureUpdated(aSurface);
end;
The IDE created the Header file that looks like this:
__interface JTextureView_SurfaceTextureListenerClass;
typedef System::DelphiInterface<JTextureView_SurfaceTextureListenerClass> _di_JTextureView_SurfaceTextureListenerClass;
__interface JTextureView_SurfaceTextureListener;
typedef System::DelphiInterface<JTextureView_SurfaceTextureListener> _di_JTextureView_SurfaceTextureListener;
class DELPHICLASS TJTextureView_SurfaceTextureListener;
__interface INTERFACE_UUID("{106DB13E-C1B4-4898-B906-0143D97C0075}") JTextureView_SurfaceTextureListenerClass : public Androidapi::Jni::Javatypes::JObjectClass
{
virtual bool __cdecl onSurfaceTextureDestroyed(Androidapi::Jni::Graphicscontentviewtext::_di_JSurfaceTexture JSurfaceTextureparam0) = 0 ;
virtual void __cdecl onSurfaceTextureAvailable(Androidapi::Jni::Graphicscontentviewtext::_di_JSurfaceTexture JSurfaceTextureparam0, int Integerparam1, int Integerparam2) = 0 ;
virtual void __cdecl onSurfaceTextureSizeChanged(Androidapi::Jni::Graphicscontentviewtext::_di_JSurfaceTexture JSurfaceTextureparam0, int Integerparam1, int Integerparam2) = 0 ;
virtual void __cdecl onSurfaceTextureUpdated(Androidapi::Jni::Graphicscontentviewtext::_di_JSurfaceTexture JSurfaceTextureparam0) = 0 ;
};
__interface INTERFACE_UUID("{58A7FBD1-27B9-44AC-B013-F077E1BF5975}") JTextureView_SurfaceTextureListener : public Androidapi::Jni::Javatypes::JObject
{
virtual bool __cdecl onSurfaceTextureDestroyed(Androidapi::Jni::Graphicscontentviewtext::_di_JSurfaceTexture JSurfaceTextureparam0) = 0 ;
virtual void __cdecl onSurfaceTextureAvailable(Androidapi::Jni::Graphicscontentviewtext::_di_JSurfaceTexture JSurfaceTextureparam0, int Integerparam1, int Integerparam2) = 0 ;
virtual void __cdecl onSurfaceTextureSizeChanged(Androidapi::Jni::Graphicscontentviewtext::_di_JSurfaceTexture JSurfaceTextureparam0, int Integerparam1, int Integerparam2) = 0 ;
virtual void __cdecl onSurfaceTextureUpdated(Androidapi::Jni::Graphicscontentviewtext::_di_JSurfaceTexture JSurfaceTextureparam0) = 0 ;
};
typedef bool __fastcall (__closure *TOnSurfaceTextureDestroyed)(Androidapi::Jni::Graphicscontentviewtext::_di_JSurfaceTexture aSurface);
typedef void __fastcall (__closure *TOnSurfaceTextureUpdated)(Androidapi::Jni::Graphicscontentviewtext::_di_JSurfaceTexture aSurface);
typedef void __fastcall (__closure *TOnSurfaceTextureSize)(Androidapi::Jni::Graphicscontentviewtext::_di_JSurfaceTexture aSurface, int aWidth, int aHeight);
class PASCALIMPLEMENTATION TJTextureView_SurfaceTextureListener : public Androidapi::Jnibridge::TJavaGenericImport__2<_di_JTextureView_SurfaceTextureListenerClass,_di_JTextureView_SurfaceTextureListener>
{
typedef Androidapi::Jnibridge::TJavaGenericImport__2<_di_JTextureView_SurfaceTextureListenerClass,_di_JTextureView_SurfaceTextureListener> inherited;
protected:
TOnSurfaceTextureDestroyed FOnTextureDestroyed;
TOnSurfaceTextureUpdated FOnTextureUpdated;
TOnSurfaceTextureSize FOnTextureAvailable;
TOnSurfaceTextureSize FOnTextureSizeChanged;
public:
bool __cdecl onSurfaceTextureDestroyed(Androidapi::Jni::Graphicscontentviewtext::_di_JSurfaceTexture aSurface);
void __cdecl onSurfaceTextureAvailable(Androidapi::Jni::Graphicscontentviewtext::_di_JSurfaceTexture aSurface, int aWidth, int aHeight);
void __cdecl onSurfaceTextureSizeChanged(Androidapi::Jni::Graphicscontentviewtext::_di_JSurfaceTexture aSurface, int aWidth, int aHeight);
void __cdecl onSurfaceTextureUpdated(Androidapi::Jni::Graphicscontentviewtext::_di_JSurfaceTexture aSurface);
__property TOnSurfaceTextureDestroyed OnTextureDestroyed = {read=FOnTextureDestroyed, write=FOnTextureDestroyed};
__property TOnSurfaceTextureUpdated OnTextureUpdated = {read=FOnTextureUpdated, write=FOnTextureUpdated};
__property TOnSurfaceTextureSize OnTextureAvailable = {read=FOnTextureAvailable, write=FOnTextureAvailable};
__property TOnSurfaceTextureSize OnTextureSizeChanged = {read=FOnTextureSizeChanged, write=FOnTextureSizeChanged};
public:
/* TObject.Create */ inline __fastcall TJTextureView_SurfaceTextureListener(void) : Androidapi::Jnibridge::TJavaGenericImport__2<_di_JTextureView_SurfaceTextureListenerClass,_di_JTextureView_SurfaceTextureListener> () { }
/* TObject.Destroy */ inline __fastcall virtual ~TJTextureView_SurfaceTextureListener(void) { }
};
Inside my C++ code, I am trying to use it like this:
_di_JTextureView_SurfaceTextureListener = TJTextureView_SurfaceTextureListener::JavaClass->init();
SurfaceTextureListener->OnTextureAvailable = SetupCamera;
But the compiler gives me an error:
no member named 'OnTextureAvailable' in 'Androidcamera2::JTextureView_SurfaceTextureListener'
Can anyone tell me what I am doing wrong here?
You're getting the error message because the JTextureView_SurfaceTextureListener interface does not have the OnTextureAvailable property.
The idea here is that the JTextureView_SurfaceTextureListener interface is the callback, and you should implement the JTextureView_SurfaceTextureListener interface in your own object. Then, in your onSurfaceTextureAvailable implementation, you call SetupCamera.
Note that you'll have to call TextureView.setSurfaceTextureListener and pass an instance of your JTextureView_SurfaceTextureListener instance in order to register your listener.

convert TDataSet results to JSON format

Need to achieve a common conversion between TDataset and JSON in C++ Builder, for the realization of data communication and conversion. However, this is difficult for an amateur developer.
I've found this already done in Delphi, but I don't know Delphi, however it seems to be good example. Maybe somebody can convert it to C++ Builder:
unit uDBJson;
interface
uses
SysUtils,Classes,Variants,DB,DBClient,SuperObject;
type
TTableJSon = class
private
const cstFieldType = 'FieldType';
const cstFieldName = 'FieldName';
const cstFieldSize = 'FieldSize';
const cstJsonType = 'JsonType';
const cstRequired = 'Required';
const cstFieldIndex = 'FieldIndex';
const cstCols= 'Cols';
const cstData= 'Data';
public
class function JSonFromDataSet(DataSet:TDataSet):string;
class function CreateFieldByJson(Fields:TFieldDefs;ColsJson:ISuperObject):Boolean;
class function ImportDataFromJSon(DataSet:TDataSet;DataJson:ISuperObject):Integer;
class function CDSFromJSon(CDS:TClientDataSet;Json:ISuperObject):Boolean;
class function GetValue(Json:ISuperObject;const Name:string):Variant;
class function CreateJsonValue(Json:ISuperObject;const Name:string;const Value:Variant):Boolean;
class function CreateJsonValueByField(Json:ISuperObject;Field:TField):Boolean;
class function GetValue2Field(Field:TField;JsonValue:ISuperObject):Variant;
end;
implementation
uses TypInfo,encddecd;
{ TTableJSon }
class function TTableJSon.CDSFromJSon(CDS: TClientDataSet;
Json: ISuperObject): Boolean;
var
ColsJson:ISuperObject;
begin
Result := False;
if Json = nil then
Exit;
CDS.Close;
CDS.Data := Null;
ColsJson := Json.O[cstCols];
CreateFieldByJson(CDS.FieldDefs,ColsJson);
if CDS.FieldDefs.Count >0 then
CDS.CreateDataSet;
ImportDataFromJSon(CDS,Json.O[cstData]);
Result := True;
end;
class function TTableJSon.CreateFieldByJson(Fields: TFieldDefs;
ColsJson: ISuperObject): Boolean;
var
SubJson:ISuperObject;
ft:TFieldType;
begin
Result := False;
Fields.DataSet.Close;
Fields.Clear;
for SubJson in ColsJson do
begin
ft := TFieldType(GetEnumValue(TypeInfo(TFieldType),'ft'+SubJson.S[cstFieldType]));
if ft= ftAutoInc then
ft := ftInteger;
Fields.Add(SubJson.S[cstFieldName],ft,SubJson.I[cstFieldSize],SubJson.B[cstRequired]);
end;
Result := True;
end;
class function TTableJSon.CreateJsonValue(Json: ISuperObject;
const Name: string; const Value: Variant): Boolean;
begin
Result := False;
Json.O[Name] := SO(Value);
Result := True;
end;
class function TTableJSon.CreateJsonValueByField(Json: ISuperObject;
Field: TField): Boolean;
begin
Result := False;
if Field Is TDateTimeField then
Json.O[Field.FieldName] := SO(Field.AsDateTime)
else if Field is TBlobField then
Json.S[Field.FieldName] := EncodeString(Field.AsString)
else
Json.O[Field.FieldName] := SO(Field.Value);
Result := True;
end;
class function TTableJSon.GetValue(
Json: ISuperObject;const Name: string): Variant;
begin
case Json.DataType of
stNull: Result := Null;
stBoolean: Result := Json.B[Name];
stDouble: Result := Json.D[Name];
stCurrency: Result := Json.C[Name];
stInt: Result := Json.I[Name];
stString: Result := Json.S[Name];
end;
end;
class function TTableJSon.GetValue2Field(Field: TField; JsonValue:ISuperObject): Variant;
begin
if JsonValue.DataType = stNull then
Result := Null
else if Field is TDateTimeField then
Result := JavaToDelphiDateTime(JsonValue.AsInteger)
else if (Field is TIntegerField) or (Field is TLargeintField) then
Result := JsonValue.AsInteger
else if Field is TNumericField then
Result := JsonValue.AsDouble
else if Field is TBooleanField then
Result := JsonValue.AsBoolean
else if Field is TStringField then
Result := JsonValue.AsString
else if Field is TBlobField then
Result := DecodeString(JsonValue.AsString)
end;
class function TTableJSon.ImportDataFromJSon(DataSet: TDataSet;
DataJson: ISuperObject): Integer;
var
SubJson:ISuperObject;
i:Integer;
iter: TSuperObjectIter;
begin
if not DataSet.Active then
DataSet.Open;
DataSet.DisableControls;
try
for SubJson in DataJson do
begin
DataSet.Append;
if ObjectFindFirst(SubJson,iter) then
begin
repeat
if DataSet.FindField(iter.Ite.Current.Name)<>nil then
DataSet.FindField(iter.Ite.Current.Name).Value :=
GetValue2Field(
DataSet.FindField(iter.Ite.Current.Name),
iter.Ite.Current.Value);
until not ObjectFindNext(iter) ;
end;
DataSet.Post;
end;
finally
DataSet.EnableControls;
end;
end;
class function TTableJSon.JSonFromDataSet(DataSet:TDataSet):string;
procedure GetFieldTypeInfo(Field:TField;var Fieldtyp,JsonTyp:string);
begin
Fieldtyp := GetEnumName(TypeInfo(tfieldtype),ord(Field.DataType));
Delete(Fieldtyp,1,2);
if Field is TStringField then
JsonTyp := 'string'
else if Field is TDateTimeField then
JsonTyp := 'integer'
else if (Field is TIntegerField) or (Field is TLargeintField) then
JsonTyp := 'integer'
else if Field is TCurrencyField then
JsonTyp := 'currency'
else if Field is TNumericField then
JsonTyp := 'double'
else if Field is TBooleanField then
JsonTyp := 'boolean'
else
JsonTyp := 'variant';
end;
var
sj,aj,sj2:ISuperObject;
i:Integer;
Fieldtyp,JsonTyp:string;
List:TStringList;
begin
sj := SO();
aj := SA([]);
List := TStringList.Create;
try
List.Sorted := True;
for i := 0 to DataSet.FieldCount - 1 do
begin
sj2 := SO();
GetFieldTypeInfo(DataSet.Fields[i],Fieldtyp,JsonTyp);
sj2.S[cstFieldName] := DataSet.Fields[i].FieldName;
sj2.S[cstFieldType] := Fieldtyp;
sj2.S[cstJsonType] := JsonTyp;
sj2.I[cstFieldSize] := DataSet.Fields[i].Size;
sj2.B[cstRequired] := DataSet.Fields[i].Required;
sj2.I[cstFieldIndex] := DataSet.Fields[i].Index;
aj.AsArray.Add(sj2);
List.Add(DataSet.Fields[i].FieldName+'='+JsonTyp);
end;
sj.O['Cols'] := aj;
DataSet.DisableControls;
DataSet.First;
aj := SA([]);
while not DataSet.Eof do
begin
sj2 := SO();
for i := 0 to DataSet.FieldCount - 1 do
begin
//sj2.S[IntToStr(DataSet.Fields[i].Index)] := VarToStrDef(DataSet.Fields[i].Value,'');
if VarIsNull(DataSet.Fields[i].Value) then
sj2.O[DataSet.Fields[i].FieldName] := SO(Null)
else
begin
CreateJsonValueByField(sj2,DataSet.Fields[i]);
end;
end;
aj.AsArray.Add(sj2);
DataSet.Next;
end;
sj.O['Data'] := aj;
Result := sj.AsString;
finally
List.Free;
DataSet.EnableControls;
end;
end;
end.
var
json:TTableJSon;
s:string;
begin
S := json.JSonFromDataSet(ADODataSet1);
end;
var
json:ISuperObject;
begin
json := TSuperObject.ParseFile('json.txt',False);
TTableJSon.CDSFromJSon(cdsJSON,json);
end;
Here is what I did/got using C++ Builder compiler which translated from pascal to c++, this code:
// CodeGear C++Builder
// Copyright (c) 1995, 2016 by Embarcadero Technologies, Inc.
// All rights reserved
// (DO NOT EDIT: machine generated header) 'uDBJson.pas' rev: 31.00 (Windows)
#ifndef UdbjsonHPP
#define UdbjsonHPP
#pragma delphiheader begin
#pragma option push
#pragma option -w- // All warnings off
#pragma option -Vx // Zero-length empty class member
#pragma pack(push,8)
#include <System.hpp>
#include <SysInit.hpp>
#include <System.SysUtils.hpp>
#include <System.Classes.hpp>
#include <System.Variants.hpp>
#include <Data.DB.hpp>
#include <Datasnap.DBClient.hpp>
#include "superdate.hpp"
#include "superobject.hpp"
//-- user supplied -----------------------------------------------------------
namespace Udbjson
{
//-- forward type declarations -----------------------------------------------
class DELPHICLASS TTableJSon;
//-- type declarations -------------------------------------------------------
#pragma pack(push,4)
class PASCALIMPLEMENTATION TTableJSon : public System::TObject
{
typedef System::TObject inherited;
private:
#define cstFieldType L"FieldType"
#define cstFieldName L"FieldName"
#define cstFieldSize L"FieldSize"
#define cstJsonType L"JsonType"
#define cstRequired L"Required"
#define cstFieldIndex L"FieldIndex"
#define cstCols L"Cols"
#define cstData L"Data"
public:
__classmethod System::UnicodeString __fastcall JSonFromDataSet(Data::Db::TDataSet* DataSet);
__classmethod bool __fastcall CreateFieldByJson(Data::Db::TFieldDefs* Fields, Superobject::_di_ISuperObject ColsJson);
__classmethod int __fastcall ImportDataFromJSon(Data::Db::TDataSet* DataSet, Superobject::_di_ISuperObject DataJson);
__classmethod bool __fastcall CDSFromJSon(Datasnap::Dbclient::TClientDataSet* CDS, Superobject::_di_ISuperObject Json);
__classmethod System::Variant __fastcall GetValue(Superobject::_di_ISuperObject Json, const System::UnicodeString Name);
__classmethod bool __fastcall CreateJsonValue(Superobject::_di_ISuperObject Json, const System::UnicodeString Name, const System::Variant &Value);
__classmethod bool __fastcall CreateJsonValueByField(Superobject::_di_ISuperObject Json, Data::Db::TField* Field);
__classmethod System::Variant __fastcall GetValue2Field(Data::Db::TField* Field, Superobject::_di_ISuperObject JsonValue);
public:
/* TObject.Create */ inline __fastcall TTableJSon(void) : System::TObject() { }
/* TObject.Destroy */ inline __fastcall virtual ~TTableJSon(void) { }
};
bool __fastcall TTableJSon::CDSFromJSon(Datasnap::Dbclient::TClientDataSet* CDS, Superobject::_di_ISuperObject Json)
{
ISuperObject *ColsJson;
bool Result = false;
if(Json == NULL)return Result;
CDS->Close();
CDS->Data = NULL;
ColsJson = Json->O[cstCols];
CreateFieldByJson(CDS->FieldDefs,ColsJson);
if(CDS->FieldDefs->Count >0)CDS->CreateDataSet();
ImportDataFromJSon(CDS,Json->O[cstData]);
return true;
}
bool __fastcall TTableJSon::CreateFieldByJson(Data::Db::TFieldDefs* Fields, Superobject::_di_ISuperObject ColsJson)
{
ISuperObject *SubJson;
TFieldType *ft;
bool Result = false;
Fields->DataSet->Close();
Fields->Clear();
// Delphi Pascal code, which I don't know how to convert
for SubJson in ColsJson do
begin
ft := TFieldType(GetEnumValue(TypeInfo(TFieldType),'ft'+SubJson.S[cstFieldType]));
if ft= ftAutoInc then
ft := ftInteger;
Fields.Add(SubJson.S[cstFieldName],ft,SubJson.I[cstFieldSize],SubJson.B[cstRequired]);
end;
return true;
}
#pragma pack(pop)
//-- var, const, procedure ---------------------------------------------------
} /* namespace Udbjson */
#if !defined(DELPHIHEADER_NO_IMPLICIT_NAMESPACE_USE) && !defined(NO_USING_NAMESPACE_UDBJSON)
using namespace Udbjson;
#endif
#pragma pack(pop)
#pragma option pop
#pragma delphiheader end.
//-- end unit ----------------------------------------------------------------
#endif // UdbjsonHPP
Please help to translate this code to C++ Builder.
right now I don't know how to translate this piece of code:
for SubJson in ColsJson do
begin
ft := TFieldType(GetEnumValue(TypeInfo(TFieldType),'ft'+SubJson.S[cstFieldType]));
if ft= ftAutoInc then
ft := ftInteger;
Fields.Add(SubJson.S[cstFieldName],ft,SubJson.I[cstFieldSize],SubJson.B[cstRequired]);
end;
All other the missing code of superobject can be found here:
https://github.com/hgourvest/superobject
UPDATE ________________________________________
Below is what I tried to translated from Delphi to C++ Builder, and the only errors I got when tried to compile I have pasted below. Please check this and help to make it correctly translated.
// CodeGear C++Builder
// Copyright (c) 1995, 2016 by Embarcadero Technologies, Inc.
// All rights reserved
// (DO NOT EDIT: machine generated header) 'uDBJson.pas' rev: 31.00 (Windows)
#ifndef UdbjsonHPP
#define UdbjsonHPP
#pragma delphiheader begin
#pragma option push
#pragma option -w- // All warnings off
#pragma option -Vx // Zero-length empty class member
#pragma pack(push,8)
#include <System.hpp>
#include <SysInit.hpp>
#include <System.SysUtils.hpp>
#include <System.Classes.hpp>
#include <System.Variants.hpp>
#include <Data.DB.hpp>
#include <Datasnap.DBClient.hpp>
#include "superdate.hpp"
#include "superobject.hpp"
//-- user supplied -----------------------------------------------------------
namespace Udbjson
{
//-- forward type declarations -----------------------------------------------
class DELPHICLASS TTableJSon;
//-- type declarations -------------------------------------------------------
#pragma pack(push,4)
class PASCALIMPLEMENTATION TTableJSon : public System::TObject
{
typedef System::TObject inherited;
private:
#define cstFieldType L"FieldType"
#define cstFieldName L"FieldName"
#define cstFieldSize L"FieldSize"
#define cstJsonType L"JsonType"
#define cstRequired L"Required"
#define cstFieldIndex L"FieldIndex"
#define cstCols L"Cols"
#define cstData L"Data"
public:
__classmethod System::UnicodeString __fastcall JSonFromDataSet(Data::Db::TDataSet* DataSet);
__classmethod bool __fastcall CreateFieldByJson(Data::Db::TFieldDefs* Fields, Superobject::_di_ISuperObject ColsJson);
__classmethod int __fastcall ImportDataFromJSon(Data::Db::TDataSet* DataSet, Superobject::_di_ISuperObject DataJson);
__classmethod bool __fastcall CDSFromJSon(Datasnap::Dbclient::TClientDataSet* CDS, Superobject::_di_ISuperObject Json);
__classmethod System::Variant __fastcall GetValue(Superobject::_di_ISuperObject Json, const System::UnicodeString Name);
__classmethod bool __fastcall CreateJsonValue(Superobject::_di_ISuperObject Json, const System::UnicodeString Name, const System::Variant &Value);
__classmethod bool __fastcall CreateJsonValueByField(Superobject::_di_ISuperObject Json, Data::Db::TField* Field);
__classmethod System::Variant __fastcall GetValue2Field(Data::Db::TField* Field, Superobject::_di_ISuperObject JsonValue);
public:
/* TObject.Create */ inline __fastcall TTableJSon(void) : System::TObject() { }
/* TObject.Destroy */ inline __fastcall virtual ~TTableJSon(void) { }
};
#pragma pack(pop)
bool __fastcall TTableJSon::CDSFromJSon(Datasnap::Dbclient::TClientDataSet* CDS, Superobject::_di_ISuperObject Json)
{
ISuperObject *ColsJson;
bool Result = false;
if(Json == NULL)return Result;
CDS->Close();
CDS->Data = NULL;
ColsJson = Json->O[cstCols];
CreateFieldByJson(CDS->FieldDefs,ColsJson);
if(CDS->FieldDefs->Count >0)CDS->CreateDataSet();
ImportDataFromJSon(CDS,Json->O[cstData]);
return true;
}
bool __fastcall TTableJSon::CreateFieldByJson(Data::Db::TFieldDefs* Fields, Superobject::_di_ISuperObject ColsJson)
{
ISuperObject *SubJson;
TFieldType ft;
bool Result = false;
Fields->DataSet->Close();
Fields->Clear();
for(int i = 0; i < ColsJson->AsArray()->Length; ++i)
{
SubJson = ColsJson->AsArray()->O[i]; //>GetO(i);
ft = TFieldType(GetEnumValue(__delphirtti(TFieldType), "ft" + SubJson->S[cstFieldType]));
if(ft == ftAutoInc)
ft = ftInteger;
Fields->Add(SubJson->S[cstFieldName], ft, SubJson->I[cstFieldSize], SubJson->B[cstRequired]);
}
return true;
}
bool __fastcall TTableJSon::CreateJsonValue(Superobject::_di_ISuperObject Json, const System::UnicodeString Name, const System::Variant &Value)
{
bool Result = false;
Json->O[Name] = SO(Value);
return true;
}
bool __fastcall TTableJSon::CreateJsonValueByField(Superobject::_di_ISuperObject Json, Data::Db::TField* Field)
{
bool Result = false;
if(dynamic_cast<TDateTimeField*>(Field) != 0)
Json->O[Field->FieldName] = SO(Field->AsDateTime);
else if(dynamic_cast<TBlobField*>(Field) != 0)
Json->S[Field->FieldName] = Field->AsString; //EncodeString(..) Field->AsVariant; TIdEncoderMIME.EncodeString(m1.Text, IndyTextEncoding_UTF8); TNetEncoding.Base64.Encode TNetEncoding.Base64.Encode(myString);
else
Json->O[Field->FieldName] = SO(Field->Value);
return true;
}
System::Variant __fastcall TTableJSon::GetValue(Superobject::_di_ISuperObject Json, const System::UnicodeString Name)
{
switch(Json->DataType)
{
case stNull: return NULL; break;
case stBoolean: return Json->B[Name]; break;
case stDouble: return Json->D[Name]; break;
case stCurrency: return Json->C[Name]; break;
case stInt: return Json->I[Name]; break;
case stString: return Json->S[Name]; break;
}
return NULL;
}
System::Variant __fastcall TTableJSon::GetValue2Field(Data::Db::TField* Field, Superobject::_di_ISuperObject JsonValue)
{
if(JsonValue->DataType == stNull)
return NULL;
else if(dynamic_cast<TDateTimeField*>(Field) != 0)
return JavaToDelphiDateTime(JsonValue->AsInteger());
else if (dynamic_cast<TIntegerField*>(Field) != 0 || dynamic_cast<TLargeintField*>(Field) != 0)
return JsonValue->AsInteger();
else if(dynamic_cast<TNumericField*>(Field) != 0)
return JsonValue->AsDouble();
else if(dynamic_cast<TBooleanField*>(Field) != 0)
return JsonValue->AsBoolean();
else if(dynamic_cast<TStringField*>(Field) != 0)
return JsonValue->AsString();
else if(dynamic_cast<TBlobField*>(Field) != 0)
return JsonValue->AsString(); //DecodeString(JsonValue.AsString) //Field->AsVariant; TIdEncoderMIME.EncodeString(m1.Text, IndyTextEncoding_UTF8); TNetEncoding.Base64.Encode TNetEncoding.Base64.Encode(myString);
}
int __fastcall TTableJSon::ImportDataFromJSon(Data::Db::TDataSet* DataSet, Superobject::_di_ISuperObject DataJson)
{
ISuperObject *SubJson;
int i;
TSuperObjectIter iter;
if(! DataSet->Active)
DataSet->Open();
DataSet->DisableControls();
try
{
for(int i = 0; i < DataJson->AsArray()->Length; ++i)
{
SubJson = DataJson->AsArray()->O[i]; //>GetO(i);
DataSet->Append();
if(ObjectFindFirst(SubJson,iter))
{
do
{ if(DataSet->FindField(iter.Ite->Current->Name) != NULL)
DataSet->FindField(iter.Ite->Current->Name)->Value =
GetValue2Field(
DataSet->FindField(iter.Ite->Current->Name),
iter.Ite->Current->Value);
}
while( ! ObjectFindNext(iter));
}
DataSet->Post();
}
}
__finally
{
DataSet->EnableControls();
}
}
void GetFieldTypeInfo(Data::Db::TField *Field, String &Fieldtyp, String &JsonTyp)
{
Fieldtyp = GetEnumName(__delphirtti(TFieldType),(int)(Field->DataType));
Fieldtyp = Fieldtyp.Delete(1,2);
if(dynamic_cast<TStringField*>(Field) != 0)
JsonTyp = "string";
else if(dynamic_cast<TDateTimeField*>(Field) != 0)
JsonTyp = "integer";
else if(dynamic_cast<TIntegerField*>(Field) != 0 || dynamic_cast<TLargeintField*>(Field) != 0)
JsonTyp = "integer";
else if(dynamic_cast<TCurrencyField*>(Field) != 0)
JsonTyp = "currency";
else if(dynamic_cast<TNumericField*>(Field) != 0)
JsonTyp = "double";
else if(dynamic_cast<TBooleanField*>(Field) != 0)
JsonTyp = "boolean";
else
JsonTyp = "variant";
}
System::UnicodeString __fastcall TTableJSon::JSonFromDataSet(Data::Db::TDataSet* DataSet)
{
ISuperObject *sj, *aj, *sj2;
int i;
String Fieldtyp,JsonTyp;
TStringList *List;
sj = SO();
aj = SA(new TVarRec(),0);
List = new TStringList;
try
{
List->Sorted = true;
for(int i = 0; i< DataSet->FieldCount - 1; i++)
{
sj2 = SO();
GetFieldTypeInfo(DataSet->Fields[i].Fields[0],Fieldtyp,JsonTyp);
sj2->S[cstFieldName] = DataSet->Fields[i].Fields[0]->FieldName;
sj2->S[cstFieldType] = Fieldtyp;
sj2->S[cstJsonType] = JsonTyp;
sj2->I[cstFieldSize] = DataSet->Fields[i].Fields[0]->Size;
sj2->B[cstRequired] = DataSet->Fields[i].Fields[0]->Required;
sj2->I[cstFieldIndex] = DataSet->Fields[i].Fields[0]->Index;
aj->AsArray()->Add(sj2);
List->Add(DataSet->Fields[i].Fields[0]->FieldName+"="+JsonTyp);
}
sj->O["Cols"] = aj;
DataSet->DisableControls();
DataSet->First();
aj = SA(new TVarRec(),0);
while(! DataSet->Eof)
{
sj2 = SO();
for(int i = 0; i< DataSet->FieldCount - 1; i++)
{
//sj2.S[IntToStr(DataSet.Fields[i].Index)] := VarToStrDef(DataSet.Fields[i].Value,'');
if(VarIsNull(DataSet->Fields[i].Fields[0]->Value))
sj2->O[DataSet->Fields[i].Fields[0]->FieldName] = SO(NULL);
else
CreateJsonValueByField(sj2,DataSet->Fields[i].Fields[0]);
}
aj->AsArray()->Add(sj2);
DataSet->Next();
}
sj->O["Data"] = aj;
return sj-> AsString();
}
__finally
{
List->Free();
DataSet->EnableControls();
}
}
//-- var, const, procedure ---------------------------------------------------
} /* namespace Udbjson */
#if !defined(DELPHIHEADER_NO_IMPLICIT_NAMESPACE_USE) && !defined(NO_USING_NAMESPACE_UDBJSON)
using namespace Udbjson;
#endif
#pragma pack(pop)
#pragma option pop
#pragma delphiheader end.
//-- end unit ----------------------------------------------------------------
#endif // UdbjsonHPP
[ilink32 Error] Error: Unresolved external 'Udbjson::TTableJSon::' referenced from C:\USERS\USER\DESKTOP\WIN32\DEBUG\UNIT1.OBJ
[ilink32 Error] Error: Unresolved external '__fastcall Superobject::SA(System::TVarRec *, const int)' referenced from C:\USERS\USER\DESKTOP\WIN32\DEBUG\UNIT1.OBJ
[ilink32 Error] Error: Unresolved external '__fastcall Superobject::SO(System::UnicodeString)' referenced from C:\USERS\USER\DESKTOP\WIN32\DEBUG\UNIT1.OBJ
[ilink32 Error] Error: Unresolved external '__fastcall Superobject::SO(System::Variant&)' referenced from C:\USERS\USER\DESKTOP\WIN32\DEBUG\UNIT1.OBJ
[ilink32 Error] Error: Unresolved external '__fastcall Superobject::TSuperArray::Add(bool)' referenced from C:\USERS\USER\DESKTOP\WIN32\DEBUG\UNIT1.OBJ
[ilink32 Error] Error: Unable to perform link
Actually you will not need to translate pascal code to C++, if you are using RAD Studio, as you can simply just #include "uDBJson.hpp" after you add the uDBJson.pas file directly to your project. Your RAD Studio will create the hpp file for you and you can call the methods in the class

How create a screenlocker similar to Windows UAC?

I'm trying to create a screen locker, similar to Windows UAC, like shown in this tutorial. I am having difficulty creating the background maximized window, with reduced light, and a screenshot of the desktop.
Here is all the code I have tried so far:
program Project1;
uses
Winapi.Windows, Winapi.Messages, Vcl.Graphics, Vcl.Forms;
function MainWndProc(hWindow: HWND; Msg: UINT; wParam: wParam;
lParam: lParam): LRESULT;
var
ps: TPaintStruct;
ScreenDC: HDC;
ScreenHandle: HWnd;
ScreenBitmap: TBitmap;
begin
Result := 0;
case Msg of
WM_PAINT:
begin
BeginPaint(hWindow, ps);
ScreenHandle := GetDeskTopWindow;
ScreenDC := GetDC(ScreenHandle);
try
ScreenBitmap := TBitMap.Create;
try
ScreenBitmap.Width := Screen.Width;
ScreenBitmap.Height := Screen.Height;
BitBlt(ScreenBitmap.Canvas.Handle, 0, 0,
Screen.Width, Screen.Height, ScreenDC, 0, 0, SRCCOPY);
finally
ScreenBitmap.Free
end
finally
ReleaseDC(ScreenHandle, ScreenDC)
end;
EndPaint(hWindow, ps);
end;
WM_DESTROY: PostQuitMessage(0);
else
begin
Result := DefWindowProc(hWindow, Msg, wParam, lParam);
Exit;
end;
end;
end;
var
wc: TWndClass;
hWindow: HWND;
Msg: TMsg;
begin
wc.lpszClassName := 'App';
wc.lpfnWndProc := #MainWndProc;
wc.Style := CS_VREDRAW or CS_HREDRAW;
wc.hInstance := hInstance;
wc.hIcon := LoadIcon(0, IDI_APPLICATION);
wc.hCursor := LoadCursor(0, IDC_ARROW);
wc.hbrBackground := (COLOR_WINDOW + 1);
wc.lpszMenuName := nil;
wc.cbClsExtra := 0;
wc.cbWndExtra := 0;
RegisterClass(wc);
hWindow := CreateWindowEx(WS_EX_CONTROLPARENT or WS_EX_WINDOWEDGE,
'AppClass',
'CREATE_WND',
WS_VISIBLE or WS_CLIPSIBLINGS or
WS_CLIPCHILDREN or WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0,
400, 300,
0,
0,
hInstance,
nil);
ShowWindow(hWindow, CmdShow);
UpDateWindow(hWindow);
while GetMessage(Msg, 0, 0, 0) do
begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
Halt(Msg.wParam);
end.
creating the background maximized window - very easy
CreateWindowExW(WS_EX_TOPMOST, L"myclassname", 0, WS_POPUP, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), HWND_DESKTOP, 0, (HINSTANCE)&__ImageBase, this);
on WM_NCCREATE we need capture screen
//HDC _hDC; - class member
//HGDIOBJ _o;
BOOL Capture()
{
BOOL fOk = FALSE;
if (HDC hdc = GetDC(HWND_DESKTOP))
{
if (_hDC = CreateCompatibleDC(hdc))
{
int cx = GetSystemMetrics(SM_CXSCREEN), cy = GetSystemMetrics(SM_CYSCREEN);
if (HBITMAP hbmp = CreateCompatibleBitmap(hdc, cx, cy))
{
_o = SelectObject(_hDC, hbmp);
static BLENDFUNCTION bf = { AC_SRC_OVER, 0, 0x80, AC_SRC_ALPHA };// 0x80 -> 50%
fOk = AlphaBlend(_hDC, 0, 0, cx, cy, hdc, 0, 0, cx, cy, bf);
}
}
ReleaseDC(HWND_DESKTOP, hdc);
}
return fOk;
}
WindowProc can be enough simply
LRESULT WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_NCDESTROY:
if (_hDC)
{
if (_o)
{
DeleteObject(SelectObject(_hDC, _o));
}
DeleteDC(_hDC);
}
//Release();
break;
case WM_NCCREATE:
//AddRef();
if (!Capture()) return FALSE;
break;
case WM_CLOSE:
return 0;// prevent from close
case WM_ERASEBKGND:
return TRUE;
case WM_PAINT:
{
PAINTSTRUCT ps;
if (BeginPaint(hwnd, &ps))
{
BitBlt(ps.hdc,
ps.rcPaint.left, ps.rcPaint.top,
ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top,
_hDC, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
EndPaint(hwnd, &ps);
}
}
break;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
static LRESULT CALLBACK _WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CScreenLocker* This;
if (uMsg == WM_NCCREATE)
{
This = reinterpret_cast<CScreenLocker*>(reinterpret_cast<LPCREATESTRUCT>(lParam)->lpCreateParams);
SetWindowLongPtrW(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(This));
}
else
{
This = reinterpret_cast<CScreenLocker*>(GetWindowLongPtrW(hwnd, GWLP_USERDATA));
}
if (This)
{
//This->AddRef();
LRESULT r = This->WindowProc(hwnd, uMsg, wParam, lParam);
//This->Release();
return r;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
then, after you create background maximized window - hwnd, need create dialog with hwnd as parent. say
ShowWindow(hwnd, SW_SHOW);
MessageBoxW(hwnd,...);
DestroyWindow(hwnd);

Resources