Jump to content

Anders Melander

Members
  • Content Count

    2854
  • Joined

  • Last visited

  • Days Won

    156

Posts posted by Anders Melander


  1. Yeah that's a bit unfortunate. The button is there to remind me to implement it - and it's disabled simply because I never got around to that. Same with the Import from and Save to Excel buttons.

     

    I take it your would expect to be able to import CSV in the same format as the exported CSV?

    I.e.:

    Module;Item;ItemType;Property;Source;Translation_0;...;Translation_n

     

    The original aim was to be able to map arbitrary CSV columns to the localization columns, but that's more work than I have to spare right now.


  2. 25 minutes ago, Der schöne Günther said:

    Let's see how this goes...

    Looking into my crystal ball I see that in a few years Microsoft will introduce something even better and we will be left with yet another UI layer.

    One can hope that they've learned from their mistakes but their track record isn't too great.

    • Like 1

  3. 31 minutes ago, c0d3r said:

    These 2 lines codes aren't related to kbmMW, they are delphi RTTL related codes, that you can call all the published methods in a class.

    Ah yes. Shouldn't TServerServiceMethod be declared like this then:

    type
      TServerServiceMethod = function(Sender: TObject; const ClientIdent: TkbmMWClientIdentity;  const Args:array of Variant): variant of object;

    (add "of object")

    Also I think you need to call it like this:

    var
      ServiceMethod: TMethod;
    begin
      ServiceMethod.Data := Self;
      ServiceMethod.Code := MethodAddress(Func);
    
      TServerServiceMethod(ServiceMethod)(Self, ClientIdent, Args);
    end;

     

    • Thanks 1

  4. Just now, David Heffernan said:

    Does partaking in the beta have much impact? 

    I haven't participated since Pulsar (I think that ended up as XE2) so I don't know how it's done these days. Back then pretty much everything was already written in stone at the time the field tests started so you could really only contribute with bug reports.

    In the beginning (up until around D9 (and please forget D8)) the field tests started much earlier (and ran longer) so there was a much better chance of influencing what ended up shipping.

     

    Regardless, if they're aiming for improved FP performance it would make sense to get early feedback from those to whom it actually matters.


  5. 27 minutes ago, c0d3r said:

    Odd, the initial Result.VType = 48088, variant array of unknown,  What was that?!

    Strange. Could be caused by a previous stack or heap corruption, maybe in the calling method. Or it could simply be a compiler bug. I don't think it's one that I've heard of though.

     

    If it's not evident, looking at the source, where the value comes from you can try to trace through the assembler in the CPU view to determine it.

    Also make sure to do a full build to ensure that there isn't a dcu mismatch somewhere.


  6. 31 minutes ago, Chris1701 said:

    if there's a way to create a button that scrolls the dataset or dbgrid by a page at a time up or down I haven't been able to find it.

     

    procedure TMyForm.ButtonScrollPageUp(Sender: TObject);
    begin
      PostMessage(MyGrid.Handle, WM_SCROLL, SB_PAGEUP, 0);
    end;
    
    procedure TMyForm.ButtonScrollPageDown(Sender: TObject);
    begin
      PostMessage(MyGrid.Handle, WM_SCROLL, SB_PAGEDOWN, 0);
    end;

     

    • Thanks 1

  7. There are a few issues with your code and a few things that could be improved.

     

    1) A member function has a hidden "self" parameter so in reality the signature of the MakeSine function you have declared looks like this:

    function MakeSine(const [ref] Self: TRadio; handle: HSTREAM; buffer: Pointer; Alength: DWORD; user: Pointer): DWORD; stdcall;

    If you want MakeSine declared as a member function then you need to declare it as a static class method:

    type
      TRadio = record
        ...
        class function MakeSine(handle: HSTREAM; buffer: Pointer; Alength: DWORD; user: Pointer): DWORD; stdcall; static;
      end;

    but then you lose the reference to self and can't access the member variables inside the method.
    I'm guessing that the user parameter is for passing context to the callback and if so you can achieve the same with an extra function:

    type
      TRadio = record
        ...
      private
        function DoMakeSine(handle: HSTREAM; buffer: Pointer; Alength: DWORD): DWORD;
      public
        class function MakeSine(handle: HSTREAM; buffer: Pointer; Alength: DWORD; user: Pointer): DWORD; stdcall; static;
      end;
      
    class function TRadio.MakeSine(handle: HSTREAM; buffer: Pointer; Alength: DWORD; user: Pointer): DWORD;
    begin
      Result := TRadioPointer(user).DoMakeSine(handle, buffer, Alength);
    end;
    
    function TRadio.DoMakeSine(handle: HSTREAM; buffer: Pointer; Alength: DWORD): DWORD;
    begin
      ...
    end;
    
    begin
      // Pass TRadio pointer as the "user" parameter
      resultValue := BASS_StreamCreate(cSAMPLE_RATE, 2, 0, @TRadio.MakeSine, PRadio);
    end

     

    2) The convention would be to name your TRadio pointer type "PRadio"

    type
      TRadio = record
        ...
      end;
    
      PRadio = ^TRadio;

    3) You don't need to deference typed complex pointer types with ^

    PRadio^.MakeSine // standard Pascal
    PRadio.MakeSine // allowed in Delphi

     


     

     

    • Like 1

  8. 6 minutes ago, Mark Williams said:

    I have worked through the code.

    Then you are already able to answer your own question.

     

    8 minutes ago, Mark Williams said:

    I thought that might be the safest thing to use working on the assumption that ALL emails will have a Date header formatted in compliance with the standards [...] However, I am also aware that the standards are not strictly adhered to in all case and so my assumption is possibly unsafe. 

    If your assumption is "possibly unsafe" then working on that assumption is not "the safest thing". You're contradicting yourself.

     

    You are never going to be able to handle every possible scenario. I suggest you create a set of test files, both valid and invalid. Make sure you can handle those but code defensively under the assumption that there are cases you don't know of yet.


  9. 7 hours ago, A.M. Hoornweg said:

    How do you detect if the printer is in use or not? You're accessing one stateful device that's effectively a singleton so the access has to be serialized. If you insist on using threads, you could write a dedicated printer thread. 

    Yes, the Printer global TPrinter instance is a singleton and AFAIK it is not thread safe. However I can't see why it should be a problem for each thread to create their own TPrinter instance and use that to print. The print job context wrapped by TPrinter is not a singleton and the target print device does not necessarily represent a single physical device.

     

    procedure TMyThread.Execute;
    var
      Printer: TPrinter;
    begin
      ...
      Printer := TPrinter.Create;
      try
        ...
        while (not Terminated) do
        begin
          ...
          Printer.BeginDoc;
          try
            ...
          finally
            Printer.EndDoc;
          end;
          ...
        end;
    
      finally
        Printer.Free;
      end;
    end;

     


  10. 2 hours ago, Mark Williams said:

    Is it therefore safe to assume that an email is in a format TIDMessage cannot read if it returns a 0 value for Date or is there a more reliable way of ascertaining if TIDMessage can read the particular email format?

    I don't know but don't you have the source code?

    It should be fairly easy to find out exactly what TIDMessage does if you just trace into LoadFromFile in the debugger.


  11. 21 minutes ago, Ian Branch said:

    Is there anything actually wrong with creating an object in a TRY block or is it just not good practice?

    It depends. Do either this:

    Foo := TFooBar.Create;
    try
      ...
    finally
      Foo.Free;
    end;

    or this:

    Foo := nil;
    try
      Foo := TFooBar.Create;
      ...
    finally
      Foo.Free;
    end;

     

    • Like 1

  12. 7 minutes ago, David Schwartz said:

    They can't wrap their heads around having a dozen or more files in our source tree that are just "compiler artifacts" (eg., dcu and other similar files) that don't need to be maanged by git.

    Apparently they haven't discovered that you can .gitignore files?

     

    10 minutes ago, David Schwartz said:

    we [...] follow the path of least resistance.

    I think we must have different definitions of "least resistance" :classic_smile:


  13. 5 hours ago, Gregory Koehn said:

    I would like to learn how to create a com object method that returns another com object.

    Here you go:

    type
      // The interfaces are probably defined in your type library unless they are purely
      // for internal use within the application.
      IFoo = interface
        ['{922E28A3-0127-42DB-A394-2CFED29A5575}']
        procedure DoFoo; safecall;
      end;
    
      IBar = interface
        ['{BECBDCE4-192C-48DC-9DC4-85DB92E01E9F}']
        function GetFoo: IFoo; safecall;
      end;
    
    type
      // If you're using dual/dispatch/late bound/automation interfaces then use TAutoObject or 
      // TAutoIntfObject as a base class instead. See the help.
      TFoo = class(TInterfacedObject, IFoo)
      private
        // IFoo
        procedure DoFoo; safecall;
      end;
    
    procedure TFoo.DoFoo;
    begin
      ShowMessage('Hello world');
    end;
    
    type
      TBar = class(TInterfacedObject, IBar)
      private
        // IBar
        function GetFoo: IFoo; safecall;
      end;
    
    function TBar.GetFoo: IFoo;
    begin
      Result := TFoo.Create;
    end;
    
    ...
    
    procedure Test;
    var
      Bar: IBar;
      Foo: IFoo;
    begin
      Bar := TBar.Create;
      Foo := Bar.GetFoo;
      Foo.DoFoo;
    end;

     

    5 hours ago, Gregory Koehn said:

    I can't take the time right now to learn all this by going through pages and pages of internet sites that were written for Delphi 5.

    The principles hasn't changed since Delphi 5 and you're not going to save any time by not learning this stuff. I recommend you read this (old) one: http://www.techvanguards.com/stepbystep/comdelphi/


  14. Once again: As far as I can tell there's nothing special in the work flow your describe. It's perfectly normal to have a branch per ticket, to change branch several times a day, to get interrupted while you're working on something that hasn't yet been committed, etc. The problems with Git you describe (changes disappearing, etc) are not problems with Git but with the way you use it; It will not overwrite your uncommitted changes unless you force it to.

     

    It is unclear to me what benefits your tool provides. It sounds like the problems it solves are already handled by the existing GUI Git clients.

    • Like 2
    • Thanks 1
×