Jump to content

PeterBelow

Members
  • Content Count

    455
  • Joined

  • Last visited

  • Days Won

    12

Posts posted by PeterBelow


  1. 10 hours ago, JohnLM said:

    I had other questions but am pressed for time for work.   But real quick.  I see TMemoryStream has .Clear and TStream do not.  Is there a similar way to clear streams when using TStream ?

    Setting the stream.size to 0 usually is the equivalent of Clear but that depends on the implementation of the actual TStream descendent you are using.

     

    Btw.: TeamB was a group of users offering support to other users on the old Borland newsgroups. As recognition they received goodies like free product licences, a bit like the current Embarcadero MVP program, and we had dedicated support partners at Borland. All that slowly died off after Codegear took over, unfortunately.

    • Sad 1

  2. 12 hours ago, JohnLM said:

    I am a beginner just learning a few things about Stream, how to Write and Read from it. 

     

    For instance, given the code snippet below, I can write and read a text string into a TEdit. This is bare basic without Try/Finally. 

     

    * code snippet extracted from one of my projects. 

    
    var s: string;
    
    procedure TForm1.btnStrToStreamClick(Sender: TObject); // save/write to a stream
    begin
      s := 'this is a test.';
      strmSize := length(s);  // 15 chars
      strm.Write(s, strmSize);
    end;
    
    procedure TForm1.btnStrmToStringClick(Sender: TObject); // load/read into a tedit control
    begin
      strm.Read(s, strmSize); // read back the 15 chars
      eb2.Text := s;          // show in tedit control
    end;

     

    The code will not work as intended. Streams store bytes, not characters, and the size of a character is 2 bytes in Unicode-enabled Delphi versions. To calculate the number of bytes to write you have to use

      strmSize := Length(s) * Sizeof(char);

    TStream.Read and TStream.Write are also somewhat deceptive and excellent traps for beginners :classic_cool:. They use untyped parameters and those do not work as you obviously expect from your code snippets. The compiler passes the address of the variable s to the method, not its content. So your strm.Write statement writes strmsize bytes starting from the address of s, but since strings in Delphi are reference types that address only holds a pointer pointing at the actual content of the string. You have to use

      strm.Write(s[1], strmSize);

    to write the content of the string.

    Reading it back has to follow the same pattern, and you have to position the stream to the start first and make sure the string you read into has enough memory allocated. Assuming the stream contains only the one string you have written into it this would look like this. I use a local string variable here to make things clearer, globals just confuse things:

     

    procedure TForm1.btnStrmToStringClick(Sender: TObject); // load/read into a tedit control
    var
      LTarget: string;
    begin
      strm.Position := 0;
      SetLength(LTarget, strm.Size div sizeof(char))
      strm.Read(LTarget[1], Length(LTarget)* sizeof(char));
      eb2.Text := LTarget;
    end;

    Things get more complex if you want to store more than one string into the same stream. In such a case it is advisable to store the length of a string (as integer) before the string content, so you can read the length first to figure out how to size the target string and how many bytes to read into it.

     

    Delphi has useful helper classes like TStringReader and TStringWriter to make such stuff easier. And if you only have to handle text you can put it into a TStringlist and use the list's SaveToStream and LoadFromStream methods to avoid all the hassle completely.

     

    • Like 4

  3. 3 hours ago, David Heffernan said:

    Negative integer wouldn't be a problem per se. A DLL loaded between 0x80000000 and 0xffffffff would be negative when interpreted as a signed integer.

    The problem in this case was that integer is 32 bit but the load address of a 64 bit DLL is 64 bits when loaded from a 64 bit project.


  4. 10 hours ago, Robert Gilland said:

    I am using Delphi 11.3

    I type a single quote in my IDE editing a pascal unit, and the quote does not appear until I press the space character.

    What is happening?

    More than this if I press a capital C after the single quote, I get a C with a tail underneath it.

    Very strange.

    This is Windows' character composition on locales that have accented characters. You are probably not using the correct key for the single quote; on a german or french keyboard the key label looks very much like the acute accent character,  "´" instead of the apostrophe/single quote "'".  Which locale are you using, and what type of keyboard?


  5. 22 minutes ago, softtouch said:

    Oh heck, I would have to deploy a lot of bpl then. I think I will just switch to use a dll instead of a bpl. I just tried it with a dll, and no issue at all, the 3rd. party control are displayed just fine.

    Be careful here. A DLL contains a different instance of the memory manager (unless you use ShareMem) and all the RTL and VCL code than the host application. Better make sure the DLL interface for the host app is written using API or COM compatible data types in the parameters exclusively, otherwise you may run into any number of weird problems.


  6. 19 hours ago, JDRenk said:

    I have added the File Menu (from File Menu Template) to my Main Menu along with Open Dialog and Save Dialog and it is not working.  I have compared it with working code and it is the same.  The difference is under Structure, the File Icons are partially shown which seems to indicate something amiss.  

     

    Thanks,

    Jeff

    Have you added handlers for the menu items OnClick event to call the dialog's Execute method? The menu items do not do that automatically. However, if you use a TActionlist with the standard file actions (added from the context menu of the action list editor) you can tie the actions to the appropriate menu items and they come with their own integrated file dialogs; you do not need to add the dialogs to the form manually.


  7. 3 hours ago, david_navigator said:

    I have some inherited code that does some complex maths using a recursive function (i.e the function calls itself). Last night a customer had a situation where running the routine killed the app. My belief is that the app ran out of stack space due to this routine calling itself multiple times and thus died.

    Is there anyway to detect this is likely to happen so that the code can be aborted with a message instead?

     

    David 

    There is a EStackoverflow exception type defined in System.Sysutils but it has been deprecated for several Delphi versions. A stack overflow cannot be trapped reliably via try except and recovering from it is practically impossible. What you can do, however, is to increase the stack size used by the program (in the linker part of the program options). Of course that is a band aid that does not protect from future failures due to an even more pathological set of input data.

     

    You can look into rewriting the algorithm to avoid recursion. Intead of relying on local variables to hold intermediate results (i.e. store them on the stack) you store this data into a record and manage a stack of these records yourself. This gives you much more control over the memory used, as well as removing the hard limit imposed by the default stack size.

    • Thanks 1

  8. For a GUI program this code is not designed correctly. A GUI program has to have a message loop and has to do any painting of the UI when Windows tells it to paint its window, by handling the WM_PAINT message in the window proc. You cannot leave that to DefWindowProc in this case, since it knows nothing about the bitmap you want to show.

     

    Anyway, this is not the way you write GUI programs in Delphi. Just create a VCL program skeleton via the File -> New menu, drop a TImage on the form the IDE creates for you, load the bitmap into its Picture property, set the Align property of the image to alclient, save the project, build and run it. Done.

     

    The whole purpose of using an environment offering a rich GUI class library like Delphi's VCL is to shield you from all the messy details of the Windows API.


  9. 34 minutes ago, Luis SIlvino said:

    I had compatibility issues with the connection of PAServer to the virtual Mac I am using. Giving a brief context, I am using a virtual Mac through a service provided by MacInCloud (https://www.macincloud.com/), which offers an installed and updated PAServer on the machine from the following link:
    https://docwiki.embarcadero.com/RADStudio/Alexandria/en/Installing_the_Platform_Assistant_on_a_Mac

    The problem is that the version of Delphi 11.3 we are using requires compatibility with version 13.3.12.7 of PAServer, but the download from the official Embarcadero page provides PAServer version 13.3.12.6.

    As the Mac machine belongs to the personnel at MacInCloud, they do not accept the installation of a .pkg that does not come from an official Embarcadero download link. (I don't have administrator permissions, so I can't install it myself.)

    So, the main question is, how can I get in touch with someone from Embarcadero to request an update to the official Download link?

     

    Delphi.thumb.png.51357b9e78b7dad9fd03a271be124a97.png

    If you have an active ssubscription just create a support case (https://supportforms.embarcadero.com/ if memory serves).

    • Like 1

  10. 14 minutes ago, dormky said:

    I have an old 2007 project that needs to be brought up to 10.3.

    However, I cannot compile the project with 10.3 as it seems it cannot recognize any installed libraries (include VCL itself). What do I need to do to migrate the project ?

    Depending on your project this can get complex and even expensive if you used a lot of 3rd-party libraries.

    You can find a good overview here. If you google for "migrating delphi projects" the first hits (for me) list a number of youtube videos that may be useful. There is also a fairly recent book on the topic available: "Delphi Legacy Projects: Strategies and Survival Guide" from William H Meyer.

     

    Do not try to open the old project file directly, first delete all files with extensions other than dpr, pas, inc, rc, res from the project directory (after making a backup, of course) and then open the project's dpr file in the 10.3 IDE. That creates a new project (dproj) file. Open the project options dialog and adjust any pathes in the compiler page as required. Make sure to enable all hints and warnings and then try to build the project. The hints and warnings you get even if the build is successful (which is unlikely) will give you an inkling about the magnitude of the task you are facing.

    The main pain points are:

    • Ansi to Unicode conversions.
    • 3rd-party components used (i hope you have source code for all of them). Even if D 10 Versions exist for the old components (which you have to buy if commercial) there are likely to be a lot more compatibility issues with them compared to Delphi RTL or VCL code.
    • Database access if you used the BDE (which is dead, buried and cremated for good measure).
    • Assuming sizeof(pointer) = sizeof(integer) (especially if you want to go 64 bit) or sizeof(char) = sizeof(byte) when misusing strings as storage for binary data.

    Good luck :classic_cool:

    • Like 1

  11. 14 hours ago, grantful said:

    I am trying to load a image from a sqlite database field

    tfdQuery sql is 

     

    select camarapic from photos

     

    
    Procedure LoadBitmapFromBlob(Bitmap: TBitmap; Blob: TBlobField);
    var
      ms, ms2: TMemoryStream;
    begin
      ms := TMemoryStream.Create;
      try
        Blob.SaveToStream(ms);
        ms.Position := 0;
        Bitmap.LoadFromStream(ms);
      finally
        ms.Free;
      end;
    end;

    When i run the app the image2  just goes blank

     

    Are you sure the database BLOB stores the image in the format TBitmap can handle? The code would fail if it is a JPG or GIF or PNG...


  12. 5 hours ago, o815 said:

    Hi there,

     

    I've noticed some issue since we upgraded from Delphi 10.3 to 11.3.

    Currently after compiling our software as a "release", we encrypt the exe file with "WibuKey" (a USB Dongle for copy protection).

    Now (since Delphi 11.3) I have a strange issue with encrypted Delphi exe files, meaning that my GUI suddenly shows chinese / unreadable symbols f.e. on a simple TPanel.Caption.

    The thing is, TPanel.Caption isn't any resourcestring or something, also there is no localization file used.

     

    To double check it isn't an issue with the "release", we compiled it as "debug" an encrypted the exe file - same issue.

    In my understanding, there must be a difference between Delphi 10.3 - to 11.3 in the compiled exe file, especially with strings. So the encrypted exe file seems to read from the wrong "string-address" of the TPanel.Caption.

     

    Perhaps someone else has similar issues with encrypted delphi 11.3 exe files?

    D11.3 uses some additional linker option by default to enable the address space layout randomization (ASLR) feature. Try to disable that and see if it fixes the issue.

    • Like 3

  13. 1 hour ago, CoMPi74 said:

    Is there a way to create a kind of custom form (or custom form descendant) which would be completely transparent for all mouse and keyboard activities. More precisely, I need a custom form (or other control) to show a message which will disappear after a certain amount of time.

    Try the form in the attached archive. To use it add the form unit to the uses clause of your form and add a call like

     

    procedure TForm2.Button1Click(Sender: TObject);
    begin
      TTransparentMsgForm.ShowMessage(
        'This is a test message.', 30, self);
    end;

     

    Examples.zip


  14. 11 hours ago, omnibrain said:

    I want to host a console in my Delphi application. Editors/IDEs like VS Code and IntelliJ IDEA have an embedded console. I want essentially achieve the same. For the moment it doesn't matter if it is the "old" console oder the new "windows terminal". I want to have a tab or panel in my application with a console that runs cmd or powershell.

     

    Trouble is, I don't know where to start. When I search I only find how to write Delphi console applications. Or I find information on how to read the console output of other programs (like with TurboPack DOSCommand). 

     

    Start by reading the docs for the AllocConsole API function.


  15. 2 hours ago, SneakyPeaky99 said:

    Thank you for advice, i have managed to determine where was the problem with 'Extension already exists' exception. I have one more question, do you know any way to solve errors like: "Runtime error 204 at 0027BE19"? Or do you know any place i should start looking for solution? Code on the right side is an address code given in hex but it doesn't give me any clue what is going on.

    errorpng.png

    See the list of error codes here. 204 is an invalid pointer operation, which may be caused by corrupted memory (stack overwrite, writing beyond the bounds of a heap-based memory block, etc.).

    Open the project in the IDE, place a breakpoint on the first code line after the "begin" of the DPR file, run under the debugger until you hit this breakpoint. If the error pops up before you reach the breakpoint it is triggered by code executed from a unit initialization section. In this case build with debug dcus and place a breakpoint on the first line of the initialization section of system.sysutils.

    After you reach such a breakpoint you can use the "go to address" function of the debugger. This hides in the context menu of the disassembly view (View -> Debug windows -> CPU Windows). Make sure you have "debug information" selected in the active project configuration. When you type in the address do not forget to start with a "$" sign to flag the typed text as a hex value.

     


  16. 16 hours ago, alogrep said:

    However, I like to print a small logo (saved as abitmap separately) at the sart of the printing, followed by the richedit content, all on the same page.. Is that possible?

    Certainly. You can mix direct output to the printer canvas with rendering via EM_FORMATRANGE.  By the way: do you know Code News Fast? It is an excellent source for Delphi code examples and it even has all the content of the long defunct Delphi newsgroups on hand. This old post may be a good starting point.

     

    By the way: the change in behaviour of your printing code from XE to Delphi 11 may be due to the fact that D11 uses a different version of the richedit common control (4.x) than XE did (2.x). There are suptle differences between these control versions.


  17. 16 hours ago, alogrep said:

    Thanks Peter.

    I applied your suggestions (I did not have the Newpage, because this richedit text will never exceed 1 page).

    However, checking if nextchar <=fmtRange.chrg.cpMin allows me to abort printing but it does not tell me what is the error, why that happens.

    If your text fits into one page it may simply indicate that all text has been printed....

×