Jump to content

Anders Melander

Members
  • Content Count

    2297
  • Joined

  • Last visited

  • Days Won

    119

Posts posted by Anders Melander


  1. 3 hours ago, Sherlock said:

    MDI is said to be an interface type, Microsoft wants to get rid of.

    "is said to" = rumor

    The SO thread is just a lot of different opinions on MDI. Like this thread will probably become.

     

    1 hour ago, Lars Fosdal said:

    MDI has been deprecated for years

    Do you have any proof for that claim?

    I've seen it many, many times but never with any reliable sources. Also one would think that MS would document that fact, in the relevant API and concept documentation, like they usually do...

     

    I have several MDI applications that runs just fine on Windows 10. They're all based on DevExpress though and I don't know if they have done anything special to handle Win10 but I doubt it.


  2. 1 hour ago, Der schöne Günther said:

    It seems to do some magic to swap out the method for resolving resource strings from System.pas with something else.

    That's fairly easy and you don't need to hack the system unit. You just need to patch the LoadStringW import.

     

    For example the following patches FindResourceW and a few others to implement a DFM fallback mechanism that loads from the main module in case the resource module doesn't contain a given DFM resource.

    It can easily be modified to patch LoadStringW to load resourcestrings from a dictionary or whatever.

     

    unit amLocalization.FindResourceFallback;
    
    interface
    
    function EnableResourceLoadingFallback: Boolean;
    
    implementation
    
    uses
      Windows;
    
    function HookAPI(const Name, Module: string; Hook: pointer): pointer;
    var
      ImageBase, Old: Cardinal;
      PEHeader: PImageNtHeaders;
      PImport: PImageImportDescriptor;
      PRVA_Import: LPDWORD;
      ProcAddress: Pointer;
    begin
      Result := nil;
    
      ImageBase := GetModuleHandle(NIL);
      PEHeader := Pointer(Int64(ImageBase) + PImageDosHeader(ImageBase)._lfanew);
      // pointer to the imports table of the main process:
      PImport := Pointer(PEHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + ImageBase);
    
      // pointer to the WinAPI function we want to hook:
      ProcAddress := GetProcAddress(GetModuleHandle(PChar(Module)), PChar(Name));
      if ProcAddress = NIL then
        Exit;
    
      while PImport.Name <> 0 do
      begin
        PRVA_Import := LPDWORD(pImport.FirstThunk + ImageBase);
        while PRVA_Import^ <> 0 do
        begin
          if PPointer(PRVA_Import)^ = ProcAddress then
          begin
            // initially imports table is in read-only segment:
            if not VirtualProtect(PPointer(PRVA_Import), 4, PAGE_READWRITE, Old) then
              Exit;
    
            Result := PPointer(PRVA_Import)^;
    
            // replacing import address with our own:
            PPointer(PRVA_Import)^ := Hook;
    
            // restoring old memory protection mode:
            if not VirtualProtect(PPointer(PRVA_Import), 4, Old, Old) then
            begin
              Result := nil;
              Exit;
            end;
    
          end;
    
          Inc(PRVA_Import);
        end;
    
        Inc(PImport);
      end;
    end;
    
    
    type
      TFindResourceW = function(hModule: HMODULE; lpName, lpType: PWideChar): HRSRC; stdcall;
    var
      FindResourceW: TFindResourceW = nil;
    
    function HookedFindResourceW(hModule: HMODULE; lpName, lpType: PWideChar): HRSRC; stdcall;
    begin
      Result := FindResourceW(hModule, lpName, lpType);
    
      if (Result = 0) and (hModule <> hInstance) then
        Result := FindResourceW(hInstance, lpName, lpType);
    end;
    
    type
      TLoadResource = function(hModule: HINST; hResInfo: HRSRC): HGLOBAL; stdcall;
    var
      LoadResource: TLoadResource = nil;
    
    function HookedLoadResource(hModule: HINST; hResInfo: HRSRC): HGLOBAL; stdcall;
    begin
      Result := LoadResource(hModule, hResInfo);
    
      if (Result = 0) and (hModule <> hInstance) then
        Result := LoadResource(hInstance, hResInfo);
    end;
    
    
    type
      TSizeofResource = function(hModule: HINST; hResInfo: HRSRC): DWORD; stdcall;
    
    var
      SizeofResource: TSizeofResource = nil;
    
    function HookedSizeofResource(hModule: HINST; hResInfo: HRSRC): DWORD; stdcall;
    begin
      Result := SizeofResource(hModule, hResInfo);
    
      if (Result = 0) and (hModule <> hInstance) then
        Result := SizeofResource(hInstance, hResInfo);
    end;
    
    function EnableResourceLoadingFallback: Boolean;
    begin
      FindResourceW := HookAPI('FindResourceW', kernel32, @HookedFindResourceW);
      Result := Assigned(FindResourceW);
    
      if (Result) then
      begin
        LoadResource := HookAPI('LoadResource', kernel32, @HookedLoadResource);
        Result := Assigned(LoadResource);
      end;
    
      if (Result) then
      begin
        SizeofResource := HookAPI('SizeofResource', kernel32, @HookedSizeofResource);
        Result := Assigned(SizeofResource);
      end;
    end;
    
    initialization
      EnableResourceLoadingFallback;
    finalization
    end.

     


  3. Constant resourcestring references are resolved during initialization by System._InitResStrings.

    If you change the application language after that, e.g. by calling LoadResourceModule, then these references will not be updated.

     

    In the example below the first ShowMessage in unaffected by the change of language while the second one isn't.

    resourcestring
      sFoo = 'Foo';
      sBar = 'Bar';
    
    const
      sFooBar: array[boolean] of string = (sFoo, sBar);
      sBetterFooBar: array[boolean] of PResStringRec = (@sFoo, @sBar);
      
    begin
      LoadResourceModule('foofoo.bar');
      ShowMessage(sFooBar[True]);
      ShowMessage(LoadResString(sBetterFooBar[True]));
    end;

     

    Apart from that I suspect the RTL/VCL uses PResStringRec for C++ compatibility.

    • Thanks 1

  4. For inspiration DevExpress controls have the standard ParentFont and individual properties to override font color and style (among other things) for Normal, Disabled, Focused and Hot state.

    There's also a style controller component so different styles can be configured centrally instead of on the individual controls.


  5. Are you asking if there's a way to have the Getter and Setter methods declared automatically from the property declaration in the interface declaration?

     

    E.g. you have:

    type

      IMyInterface = interface

        property Foo: string read GetFoo write SetFoo;

      end;

     

    and you want to end up with:

     

    type

      IMyInterface = interface

        function GetFoo: string;
        procedure SetFoo(const Value: string);

        property Foo: string read GetFoo write SetFoo;

      end;

     

    AFAIK there's no standard way to have the getters and setter automatically declared 😞

    What I usually do, if there's a lot of them, is to just copy the property declaration to an implementing class, use class completion on that to generate the getters and setters and then copy the declaration of those back to the interface declaration.


  6. 2 minutes ago, aehimself said:

    Hard drives as you might think - not necessarily

    Okay. Now the use of W2K makes much better sense. Interesting constraints.

     

    Anyway, back to the problem. If you can observe that virtual and physical memory consumption increases during execution, but all resources are released before the process is terminated (thus no leaks detected), then you can force the allocated memory to be reported as leaks by terminating the application prematurely with a call to Halt.


  7. 8 minutes ago, aehimself said:

    Yes. Considering built-in devices (robotic arms, controllers, etc.) where you can not upgrade the hardware and/or the software, I like to experiment with the absolute minimum

    That makes good sense, but why limit virtual memory? Doesn't the devices have hard disks?


  8. 12 hours ago, TomDevOps said:

    Manual memory management is pain and only slows you down.

    You should probably rephrase that "and only slows me down".

     

    In my experience laziness always comes at a price. Not bothering to use descriptive identifiers saves a few keystrokes at the price of readability. ARC and GC relieves the developer of having to deal with some of the complexities of resource management, at the price of performance. Etc.

     

    I would honestly rather have good performance and full control of what's going on with the resources.

     

     

    12 hours ago, TomDevOps said:

    They should remove that sort of things too.

    Yes. Let's break COM support so we can save some keystrokes.

    • Like 6

  9. FWIW, Windows 2000 isn't supported by the version of Delphi you're using.

     

    Also, please read the event log message again. It has all the clues:

    • It isn't your application that is experiencing an "out of memory" error.
    • It's Windows that is experiencing an "out of virtual memory" error.
    • To fix it: Increase the size of the page file.

    My guess is that the W2K system has a fixed size page file - or no page file at all. Otherwise it would just increase the size automatically - or maybe that feature was added later. I forget. and who cares anymore.

     

    If you're really interested in why you get a windows error and not an application error, read some books on Windows internals and the virtual memory manager, or just google it.

    • Like 2

  10. 3 hours ago, dkprojektai said:

    pBuffer - Pointer to memory buffer which contain image file data

    You didn't really answer @Vandrovnik's question.

     

    For Windows bitmaps the bitmap file image (i.e. bitmap header and pixel data) isn't stored in memory.

    When TBitmap loads a bmp file it reads the header information then the pixel data. From this it stores the relevant meta data (width/height, color depth, palette, etc) and pixel data in memory.

    Of these you only have direct access to the raw pixel data.

     

    If you need the file bitmap image in memory then you will either have to save the bitmap to a memory stream or construct the image yourself in memory.

     

    btw, when I write "image" I don't mean in the picture/graphic/bitmap sense.

     

    Maybe you should try to explain what problem you are trying to solve.

    • Like 1

  11. 1 hour ago, David Heffernan said:

    That memory will be backed by the swap file.

    Technically it's the page file.

    The terms page file and swap file have their roots in VMS. Both Windows NT and VMS were designed by his holiness, Dave Cutler.

     

    The swap file doesn't exist anymore in Windows (I believe it was there in early versions) but was used when a process working set was completely removed from physical memory. E.g. in low memory situations or if the process went into extended hibernation.


  12. 1 hour ago, Lars Fosdal said:

    From my experience, the complexity of dealing with multiple generations of breaking changes has been far more expensive in man-hours than the cost of keeping current.

    What breaking changes are those?

    At one of my clients we upgraded all projects (many millions LOC) directly from Delphi XE & XE2 (for 64-bit) to Delphi 10.2 with no significant effort. The worst part was the tasks you'll have to do anyway every time you migrate a project from one version of Delphi to another.

    If they had kept up to date all the way through, they would have had to pay maintenance on 20+ licenses to get the occasional new feature they didn't really need and they would have had to fix and work around all the new bugs they got as well.

    • Like 1

  13. 2 hours ago, Uwe Raabe said:

    You might be forced to reconsider this statement when your customers are more and more using high dpi configurations and criticize the visual quality of your application.

    Windows does a better job of making old applications behave well under high DPI than the VCL has so far managed.

    I would prefer to have the UI consistently scaled than having some parts support high DPI, some parts scaled and some messed up.

×