Eric Grange 11 Posted September 6 Hi, this is definitely on the hacky side. Is there a way to gain access to private class var of a class defined in an implementation section ? More precisely, I'm trying to gain access to TDX11Context private class vars, which is defined in the implementation section of FMX.Context.DX11, and the vertex & pixel shaders more specifically. My best attempt so far is to obtain the address of TDX11Context.DoSetShaderVariable (easy, it's virtual and just protected), and there the first line is just if (CurrentVertexShader <> nil) and (Length(FVSBuf) > 0) then begin which is simple enough to "disassemble", get the FVSBuf address, from which the other vars can be inferred. It's all quite fragile though 🙂 1 Share this post Link to post
Lajos Juhász 293 Posted September 6 I guess you already know the answer. Enter a ticket on the Quality Portal to request access to the fields you want. Give a good explanation why whould you want those fields to be public or protected in order to reach MFGA (Make Firemonkey Great Again). 1 Share this post Link to post
Uwe Raabe 2058 Posted September 6 program Project1104; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.Classes, System.Types, Winapi.D3D11, FMX.Types3D, FMX.Context.DX11; type TDX11Context = class(TCustomDX11Context) private class var FResources: IInterfaceList; FVSSlot: ID3D11Buffer; FPSSlot: ID3D11Buffer; FVSSlotModified, FPSSlotModified: Boolean; FVSBuf, FPSBuf: array of Byte; FInputLayout: ID3D11InputLayout; FResourceViews: array [0..16] of ID3D11ShaderResourceView; FSampleStates: array [0..16] of ID3D11SamplerState; FBlendDesc: TD3D11_BLEND_DESC; FBlendState: ID3D11BlendState; FBlendStateModified: Boolean; FRasterizerDesc: TD3D11_RASTERIZER_DESC; FRasterizerState: ID3D11RasterizerState; FRasterizerStateModified: Boolean; FDepthStencilDesc: TD3D11_DEPTH_STENCIL_DESC; FDepthStencilState: ID3D11DepthStencilState; FDepthStencilModified: Boolean; FStencilRef: Integer; FBufferSize: TSize; end; TDX11ContextClass = class of TDX11Context; begin try RegisterContextClasses; if TContextManager.DefaultContextClass.ClassNameIs('TDX11Context') then Writeln(Length(TDX11ContextClass(TContextManager.DefaultContextClass).FVSBuf)) else Writeln('Oops!'); except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; ReadLn; end. 1 Share this post Link to post
Eric Grange 11 Posted September 6 @Uwe Raabe this doesn't seem to work, the compiler is creating different variables, class private vars don't appear to be relative to the TClass ? @Lajos Juhász this would be a long term ticket, and given then number of private stuff one needs to crack (not just in TDX11Context, but also in TContext3D), a major undertaking for EMBT to refactor everything Share this post Link to post
Lajos Juhász 293 Posted September 6 1 minute ago, Eric Grange said: @Lajos Juhász this would be a long term ticket, and given then number of private stuff one needs to crack (not just in TDX11Context, but also in TContext3D), a major undertaking for EMBT to refactor everything I am aware. Unfortunately that is thr only right way to do it. You can try to hack the system. Unfortunately that depends heavily on the memory layout and the classes current definitions as a result most probably will break with every version of the Delphi. Share this post Link to post
Kas Ob. 121 Posted September 6 (edited) @Eric Grange How about hooking TDX11Context.DoSetShaders ? Wait a second !, TDX11Context is private and non accessible, at least on my XE8, that is bad design to hide a critical and OS dependent class, was the designer so confident it is bug free and it does include everything could be needed from DirectX11 even in the future. From the name DX11, there will be DX12 and even DX13, and they will break compatibility in huge way, so a private one is like, NO update your IDE framework and wait for our updated design... Edited September 6 by Kas Ob. 1 Share this post Link to post
Eric Grange 11 Posted September 6 @Kas Ob. yes, but the code has not changed in a long while AFAICT. On practical approach might be for EMBT to "officially" allow FMX.Context.XXX open-source forks. This would allow reimplementation projects to be kickstarted, and after a few iterations, there would probably be little left from the original EMBT source code anyway (at least from what I can see in the TDX11Context). The OpenGL context seems less "private", but it still has a lot of private vars in key areas. One of the first things forks would do would probably be to turn those private vars into fields, and support multiple contexts (and eventually multiple threads) 2 Share this post Link to post
Vincent Gsell 11 Posted September 6 4 hours ago, Lajos Juhász said: to reach MFGA (Make Firemonkey Great Again). I ignored that organization exists ! Where I sign up ? 😉 Share this post Link to post
Joseph MItzen 251 Posted September 8 The moral here is that private variables are almost as evil as threads. No one knows, forever and for all time, what anyone else might need to access in the future. 1 Share this post Link to post
Anders Melander 1794 Posted September 9 On 9/8/2024 at 10:01 AM, Joseph MItzen said: The moral here is that private variables are almost as evil as threads. That's a strange statement. Why are threads evil? Eric is trying to do something with a class that just wasn't designed for what he needs. That in itself doesn't make the design wrong or bad. On 9/8/2024 at 10:01 AM, Joseph MItzen said: No one knows, forever and for all time, what anyone else might need to access in the future. The counter-argument is that no one knows how the functionality of a class' public API will be implemented in future. Class members are private in order to not lock a public API to a specific implementation bound to those private members; They shield the API from implementation details. You are basically arguing against the use of encapsulation. Share this post Link to post
Eric Grange 11 Posted September 9 Encapsulation can be frustrating, but exposing everything means you're making promises. People's code will gain dependencies to everything that can be accessed or overridden. Which means you won't be able to change much (or fix) without breaking user code. Opening too much means code will sediment and become untouchable... In the case of the DX11 driver, it's obvious it was locked in the implementation section because whoever was working on it wasn't satisfied with it. Likely because he/she did not have time to tidy it up. It's essentially DX9 code with a light rewrite to DX11. I was able to hack it, but it was brittle. I'm now starting down the path of reimplementing it, which in the long term will open more possibilities (and hoping Delphi 12.2 doesn't wreak havoc on TContext3D, haha) 3 Share this post Link to post
Dalija Prasnikar 1398 Posted September 9 1 hour ago, Anders Melander said: The counter-argument is that no one knows how the functionality of a class' public API will be implemented in future. Class members are private in order to not lock a public API to a specific implementation bound to those private members; They shield the API from implementation details. You are basically arguing against the use of encapsulation. The problem is that Embarcadero provides base framework classes that satisfy very narrow usage and are not properly open for extension. Sometimes you need to change literally one line, to get the needed behavior, but there is no way to do that properly. So you need to resort to hacking into those classes. Protected opens up the class for needed extensions and still protects casual users from using implementation details and does not break encapsulation. Yes, if the implementation changes, you may need to update your code to match the changes, but you would need to do that regardless. Private is major PITA. 3 Share this post Link to post