Recent

Author Topic: Installing RichMemo into Lazarus 2.0.0  (Read 3085 times)

rick2691

  • Sr. Member
  • ****
  • Posts: 444
Installing RichMemo into Lazarus 2.0.0
« on: March 03, 2022, 06:31:18 pm »
Code: Pascal  [Select][+][-]
  1. // Callback function for EM_STREAMOUT ... by the TEAM
  2. //
  3. function EditStreamOutCallback(dwCookie: Longint; pbBuff: PByte;
  4.                                cb: Longint; var pcb: Longint): DWORD; stdcall;
  5. begin                          //  DWORD was Longint
  6.   // This will write the contents of the RichEdit to a TMemoryStream field.
  7.   //
  8.   // dwCookie is Application-defined, so we're passing the blob stream.
  9.   //
  10.   pcb:= TMemoryStream(dwCookie).Write(pbBuff^, cb);
  11.   Result:= 0;
  12. end;  
  13.  

The above code was running in version 2.0.12
I just installed 2.2.0 and RichMemo will not get past debugging.

It give the following error message:
frm1.pas(1183,9) Error: Illegal type conversion: "LongInt" to "TMemoryStream"

I changed TMemoryStream to TStringStream and it give the same error again.

I tried to install RichMemo by a disk "lpk", but it can't find Graph "ppu" file. So I installed by the Online Package Manager. It appeared to install correctly. However, It paused installation to ask me something about the debugger. It offered an option 1, 2 , or both drivers. I said both because I had no idea what either of them were.

I hate ugrading to the latest and greatest of anything.

Rick
Windows 11, LAZ 2.0.10, FPC 3.2.0, SVN 63526, i386-win32-win32/win64, using windows unit

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: Installing RichMemo into Lazarus 2.0.0
« Reply #1 on: March 03, 2022, 06:51:52 pm »
What do you want to achieve with this? Save the contents of the RichMemo to a memory stream as the comment says? In this case, why don't you use the corresponding method TCustomRichMemo.SaveRichText?

Code: Pascal  [Select][+][-]
  1. function TCustomRichMemo.SaveRichText(Dest: TStream): Boolean;

rick2691

  • Sr. Member
  • ****
  • Posts: 444
Re: Installing RichMemo into Lazarus 2.0.0
« Reply #2 on: March 03, 2022, 07:41:45 pm »
wp,

The code I posted is for using a CallBack function. I am showing it so that you will know that the code is proper. It was operating only one hour ago. Then I installed the latest version of Lazarus compiler. Now the debugging in this new version is saying that valid codes are invalid, and it won't compile my program.

Your suggestion is interesting, but the issue is that the debugger is broken, and I am assuming that it is RichMemo related.

Rick
Windows 11, LAZ 2.0.10, FPC 3.2.0, SVN 63526, i386-win32-win32/win64, using windows unit

rick2691

  • Sr. Member
  • ****
  • Posts: 444
Re: Installing RichMemo into Lazarus 2.0.0
« Reply #3 on: March 04, 2022, 06:13:27 pm »
I believe that I wasn't specific enough. The debugger is halting compilation because TStream(dwCookie) and TMemoryStream(dwCookie) are invalid operations. It reports ... Error: Illegal type conversion: "LongInt" to "TMemoryStream"

I know that TStream(dwCookie) is valid because I have been using that code many years. Moreover, The first instance of this happening is by my having to use "Online Package Manager" to install Richmemo. However, Richmemo is the only component that I use streaming with. Otherwise, it would have to be the Debugger's database.

Rick
Windows 11, LAZ 2.0.10, FPC 3.2.0, SVN 63526, i386-win32-win32/win64, using windows unit

rick2691

  • Sr. Member
  • ****
  • Posts: 444
Re: Installing RichMemo into Lazarus 2.0.0
« Reply #4 on: March 04, 2022, 09:46:11 pm »
I have gone back to version 2.0.10
Everything works as coded.
Thanks for all the help.

Rick
Windows 11, LAZ 2.0.10, FPC 3.2.0, SVN 63526, i386-win32-win32/win64, using windows unit

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: Installing RichMemo into Lazarus 2.0.0
« Reply #5 on: March 04, 2022, 11:19:39 pm »
This is the declaration of the EDITSTREAMCALLBACK function, taken from the FPC richedit.pp unit:

Code: Pascal  [Select][+][-]
  1. type
  2.      EDITSTREAMCALLBACK = function (dwCookie:DWORD_PTR; pbBuff:LPBYTE; cb:LONG; var pcb:LONG):DWORD;

Here you see that the RichMemo declares dwCookie as a DWORD_PTR which is the Windows type for our PUInt - the unsigned integer which has the same size as a pointer. The sizes of pointers and longints are not equal in general depending on the bitness of the application: while longint always has 32 bit, the size of a pointer corresponds to the bitness: 32 bit in 32bit applications, 64bit in 64bit applications.

The solution of this compilation issue, therefore, is to declare dwCookie in your callback function as PtrUInt rather than LongInt, and your program should work also with FPC 3.2.2.

rick2691

  • Sr. Member
  • ****
  • Posts: 444
Re: Installing RichMemo into Lazarus 2.0.0
« Reply #6 on: March 07, 2022, 05:44:16 pm »
WP,

Thanks for giving this some thought.

Is the DWORD_PTR in the FPC richedit.pp unit a PtrUInt?

and if so, then ...

function EditStreamOutCallback(dwCookie:Longint; pbBuff:PByte;
                               cb:Longint; var pcb:Longint):Longint; stdcall; 

needs to be ...

function EditStreamOutCallback(dwCookie:PtrUInt; pbBuff:PByte;
                               cb:Longint; var pcb:Longint):PtrUInt; stdcall; 

per the dwCookie and Result parameters. Is that what you are saying?

If that is true, then the Delphi code that I took this from is for pre-64bit applications?
Moreover, it works for me because I am doing 32bit application?
Likewise, the debugger is choking on it because it wants 64bit compatibility?

If all of that is correct, then I think the debugger needs to be a little more verbose than it is.

Rick
Windows 11, LAZ 2.0.10, FPC 3.2.0, SVN 63526, i386-win32-win32/win64, using windows unit

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: Installing RichMemo into Lazarus 2.0.0
« Reply #7 on: March 07, 2022, 06:31:44 pm »
Is the DWORD_PTR in the FPC richedit.pp unit a PtrUInt?
Yes.

and if so, then ...

function EditStreamOutCallback(dwCookie:Longint; pbBuff:PByte;
                               cb:Longint; var pcb:Longint):Longint; stdcall; 

needs to be ...

function EditStreamOutCallback(dwCookie:PtrUInt; pbBuff:PByte;
                               cb:Longint; var pcb:Longint):PtrUInt; stdcall; 

per the dwCookie and Result parameters. Is that what you are saying?

Almost. Only for dwCookie, not for the result. Or you can stick with the original declaration with DWORD_PTR - the important thing is that dwCookie must be declared as an integer which has the same size as a pointer because you type-cast the cookie to a Memorystream which is a pointer.

Either do this
Code: Pascal  [Select][+][-]
  1. function EditStreamOutCallback(dwCookie: DWORD_PTR; pbBuff: PByte;
  2.                                cb: Longint; var pcb: Longint): DWORD; stdcall;
or this
Code: Pascal  [Select][+][-]
  1. function EditStreamOutCallback(dwCookie: PtrUInt; pbBuff: PByte;
  2.                                cb: Longint; var pcb: Longint): DWORD; stdcall;

The declaration of the function must follow the prototype of EDITSTREAMCALLBACK defined in unit richedit.pp (which is in the fpc folder packages\winunits-base\src) (cited in my post above).

If that is true, then the Delphi code that I took this from is for pre-64bit applications?
Yes.

Moreover, it works for me because I am doing 32bit application?
Likewise, the debugger is choking on it because it wants 64bit compatibility?
I don't know what you are doing. And I cannot test anything because you don't post a small sample project. So, I am just guessing (and may be wrong), but my arguments look very conclusive (to me).

If all of that is correct, then I think the debugger needs to be a little more verbose than it is.
You probably mean "compiler" rather than "debugger". Yes, sometimes the compiler messages are hard to understand. But again I cannot comment because you did not post the error message.

rick2691

  • Sr. Member
  • ****
  • Posts: 444
Re: Installing RichMemo into Lazarus 2.0.0
« Reply #8 on: March 09, 2022, 03:54:07 pm »
This is the code that I am using. I have altered by your advice, and I have tested it. It works as good as what I had already been using. So I suppose that I can use it and be more modern.

However, I have gone back to compiler 2.0.10, and operating in 32 bit format, which does not choke on my older code nor your changes to it. Curiously, even compiler 2.0.12 chokes on my older code, so it might date when things have become so complicated.

Code: Pascal  [Select][+][-]
  1. //========================= begin: stream callback for Get/PutRTFselection
  2.  
  3. // by Peter Below (TeamB)  < 100113.1...@compuserve.com >
  4.  
  5. // Stream Callback function
  6. //
  7. type
  8.   TEditStreamCallBack = function(dwCookie:PtrUInt; pbBuff:PByte;   //  PtrUInt = DWord = LongWord
  9.                                  cb:Longint; var pcb:Longint
  10.                                  ):DWORD; stdcall;
  11.                                  //  ):DWORD_Ptr or PtrUInt for ansistring *was*  ):Longint for widestring
  12.   TEditStream = record
  13.                 dwCookie:LongInt; // PtrUInt;
  14.                 dwError:Longint;
  15.                 pfnCallback:TEditStreamCallBack;
  16.                 end;
  17.  
  18. // Callback function for EM_STREAMOUT ... by the TEAM
  19. //
  20. function EditStreamOutCallback(dwCookie:PtrUInt; pbBuff:PByte;
  21.                                cb:Longint; var pcb:Longint):DWORD; stdcall;
  22.                                //  ):DWORD for ansistring *was*  ):Longint for widestring
  23.   // TMemoryStream;  // TStream;
  24. begin
  25.   // This will write the contents of the Richmemo OUT to a TMemoryStream field.
  26.   //
  27.   // dwCookie is Application-defined, so we're passing the blob stream.
  28.   //
  29.   pcb:= TMemoryStream(dwCookie).Write(pbBuff^, cb);  // TMemoryStream  // TStream
  30.   Result:= 0;
  31. end;
  32.  
  33. // Callback function for EM_STREAMIN
  34. //
  35. function EditStreamInCallback(dwCookie:PtrUInt; pbBuff:PByte;
  36.                               cb:Longint; var pcb:Longint):DWORD; stdcall;
  37. var                           //  ):DWORD for ansistring *was*  ):Longint for widestring
  38.   theStream: TMemoryStream;  // try TMemoryStream instead of TStream.
  39. begin
  40.   // This will write the contents of a TStream field IN to a Richmemo.
  41.   //
  42.   // dwCookie is Application-defined, so we're passing the stream containing
  43.   // the formatted text to be added.
  44.   //
  45.   theStream:= TMemoryStream(dwCookie);
  46.   Result:= 0;
  47.  
  48.   with theStream do
  49.        begin
  50.        if (Size - Position) <= cb then
  51.            begin
  52.            pcb:= Size;
  53.            Read(pbBuff^, Size);
  54.            end
  55.            else begin
  56.                 pcb:= cb;
  57.                 Read(pbBuff^, cb);
  58.                 end;
  59.        end;
  60. end;
  61.  
  62. // copyout Stream from RichEdit: uses stream callback above
  63. //
  64. Procedure GetRTFSelection(Amemo:TRichMemo; IntoStream:TMemoryStream);  // TStream);
  65. Var EditStream: TEditStream;
  66. Begin
  67.   with EditStream do
  68.        Begin
  69.        dwCookie:= Longint(IntoStream);
  70.        dwError:= 0;
  71.        pfnCallback:= @EditStreamOutCallBack;  // get OUT FROM stream
  72.        end;
  73.   Amemo.Perform(EM_STREAMOUT, SF_RTF or SFF_SELECTION, longint(@EditStream));
  74. End;
  75.  
  76. // Insert Stream into RichEdit: uses stream callback above
  77. //
  78. procedure PutRTFSelection(Amemo:TRichMemo; SourceStream:TMemoryStream);  // TStream);
  79. var EditStream: TEditStream;
  80. begin
  81.   with EditStream do
  82.        begin
  83.        dwCookie:= Longint(SourceStream);
  84.        dwError:= 0;
  85.        pfnCallback:= @EditStreamInCallBack;  // put IN to stream
  86.        end;
  87.   Amemo.Perform(EM_STREAMIN, SF_RTF or SFF_SELECTION, Longint(@EditStream));
  88. end;
  89.  
  90. //=================================== end: stream callback for Get/PutRTFselection
  91.  

How the code works is that I select anything or everything that is in an RTF document, and then call to MnuSaveSelectionClick(Sender: TObject).

Code: Pascal  [Select][+][-]
  1. procedure TCmdForm.SaveSelection;  // PageMemo to New TabPage
  2. var MS: TMemoryStream;  // TMemoryStream;
  3. // TMemoryStream is a TStream descendant that stores its data in memory.
  4. // TMemoryStream self-handles all allocation and destroying of memory.
  5. // When the stream is freed, all allocated memory will also be freed.
  6. begin  // PageMemo range must already be selected
  7.   MS:= TMemoryStream.create;  // TMemoryStream.Create;  //MS:= TStringStream.create;
  8.   try
  9.     GetRTFSelection(PageMemo,MS); // stores selection as MS
  10.     PageMemo.SelLength:= 0;
  11.     MS.Position:= 0;
  12.     btnNewClick(Self);
  13.     PageMemo.SetFocus;
  14.     PutRTFSelection(PageMemo,MS); // copy/paste MS to Untitled
  15.     PageMemo.SelLength:= 0;    //PageMemo.SetFocus;
  16.   finally
  17.     MS.Free;
  18.   end;
  19. end;
  20.  
  21. procedure TCmdForm.MnuSaveSelectionClick(Sender: TObject);
  22. begin
  23.   if PageTabControl.PageCount>0 then
  24.      begin
  25.      if PageMemo.SelLength>0
  26.         then SaveSelection   // ReportPageTab;
  27.         else showmessage('Nothing selected.');
  28.      end else showmessage('No active document.');
  29. end;
  30.  

This opens a new TabSheet and copies the selected to it. It is just a convenience for saving (on the fly) the content in a document that I have decided to edit. ie. rewrite. So that I can restore the section if my editing doesn't get me anywhere. It's a book.

Given all the trouble that I have encountered by upgrading to the latest compiler version, I may not reinstall it. There could be other 64bit problems that I don't know about yet. Meanwhile, I only want to get my work finished.

Unfortunately, even with version 2.0.10 I now have a problem importing images into the document ... because I am forced to use Online Package Manager to install RichMemo, instead of just installing from a disk package. It seems that graphic functions have been modified, and images are currently imported at too large of a scale (about double size).

Do you know anything about that? I would really like to get that fixed.

Rick
Windows 11, LAZ 2.0.10, FPC 3.2.0, SVN 63526, i386-win32-win32/win64, using windows unit

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: Installing RichMemo into Lazarus 2.0.0
« Reply #9 on: March 09, 2022, 04:28:11 pm »
Quickling scanning through this code I see three more issues with Pointer-to-Integer conversion. I marked the lines by a yellow background: Use a PtrUint rather than a LongInt here in order to be compatibile with 64-bit.
Code: Pascal  [Select][+][-]
  1. //========================= begin: stream callback for Get/PutRTFselection
  2.  
  3. // by Peter Below (TeamB)  < 100113.1...@compuserve.com >
  4.  
  5. // Stream Callback function
  6. //
  7. type
  8.   TEditStreamCallBack = function(dwCookie:PtrUInt; pbBuff:PByte;   //  PtrUInt = DWord = LongWord
  9.                                  cb:Longint; var pcb:Longint
  10.                                  ):DWORD; stdcall;
  11.                                  //  ):DWORD_Ptr or PtrUInt for ansistring *was*  ):Longint for widestring
  12.   TEditStream = record
  13.                 dwCookie:LongInt; // PtrUInt;
  14.                 dwError:Longint;
  15.                 pfnCallback:TEditStreamCallBack;
  16.                 end;
  17.  
  18. // Callback function for EM_STREAMOUT ... by the TEAM
  19. //
  20. function EditStreamOutCallback(dwCookie:PtrUInt; pbBuff:PByte;
  21.                                cb:Longint; var pcb:Longint):DWORD; stdcall;
  22.                                //  ):DWORD for ansistring *was*  ):Longint for widestring
  23.   // TMemoryStream;  // TStream;
  24. begin
  25.   // This will write the contents of the Richmemo OUT to a TMemoryStream field.
  26.   //
  27.   // dwCookie is Application-defined, so we're passing the blob stream.
  28.   //
  29.   pcb:= TMemoryStream(dwCookie).Write(pbBuff^, cb);  // TMemoryStream  // TStream
  30.   Result:= 0;
  31. end;
  32.  
  33. // Callback function for EM_STREAMIN
  34. //
  35. function EditStreamInCallback(dwCookie:PtrUInt; pbBuff:PByte;
  36.                               cb:Longint; var pcb:Longint):DWORD; stdcall;
  37. var                           //  ):DWORD for ansistring *was*  ):Longint for widestring
  38.   theStream: TMemoryStream;  // try TMemoryStream instead of TStream.
  39. begin
  40.   // This will write the contents of a TStream field IN to a Richmemo.
  41.   //
  42.   // dwCookie is Application-defined, so we're passing the stream containing
  43.   // the formatted text to be added.
  44.   //
  45.   theStream:= TMemoryStream(dwCookie);
  46.   Result:= 0;
  47.  
  48.   with theStream do
  49.        begin
  50.        if (Size - Position) <= cb then
  51.            begin
  52.            pcb:= Size;
  53.            Read(pbBuff^, Size);
  54.            end
  55.            else begin
  56.                 pcb:= cb;
  57.                 Read(pbBuff^, cb);
  58.                 end;
  59.        end;
  60. end;
  61.  
  62. // copyout Stream from RichEdit: uses stream callback above
  63. //
  64. Procedure GetRTFSelection(Amemo:TRichMemo; IntoStream:TMemoryStream);  // TStream);
  65. Var EditStream: TEditStream;
  66. Begin
  67.   with EditStream do
  68.        Begin
  69.        dwCookie:= Longint(IntoStream);
  70.        dwError:= 0;
  71.        pfnCallback:= @EditStreamOutCallBack;  // get OUT FROM stream
  72.        end;
  73.   Amemo.Perform(EM_STREAMOUT, SF_RTF or SFF_SELECTION, longint(@EditStream));
  74. End;
  75.  
  76. // Insert Stream into RichEdit: uses stream callback above
  77. //
  78. procedure PutRTFSelection(Amemo:TRichMemo; SourceStream:TMemoryStream);  // TStream);
  79. var EditStream: TEditStream;
  80. begin
  81.   with EditStream do
  82.        begin
  83.        dwCookie:= Longint(SourceStream);
  84.        dwError:= 0;
  85.        pfnCallback:= @EditStreamInCallBack;  // put IN to stream
  86.        end;
  87.   Amemo.Perform(EM_STREAMIN, SF_RTF or SFF_SELECTION, Longint(@EditStream));
  88. end;
  89.  
  90. //=================================== end: stream callback for Get/PutRTFselection
  91.  

because I am forced to use Online Package Manager to install RichMemo, instead of just installing from a disk package.
Nobody forces you to use Online Package Manager. It is just a convenient - a VERY convenient - tool to distribute packages. But you still can load the .lpk file of any package from any source into Lazarus and install it manually. I do this all the time.

It seems that graphic functions have been modified, and images are currently imported at too large of a scale (about double size).

Do you know anything about that? I would really like to get that fixed.
I am not a specialist with RichEdit/RichMemo. But you should search the forum for it. I remember there was a discussion about images in RichMemo not too long ago.

rick2691

  • Sr. Member
  • ****
  • Posts: 444
Re: Installing RichMemo into Lazarus 2.0.0
« Reply #10 on: March 09, 2022, 05:07:23 pm »
wp,

Thanks for your review.

Quote
dwCookie:= Longint(SourceStream);

Would it be the same method; ie. LongWord(SourceStream);

Quote
Nobody forces you to use Online Package Manager.

That hasn't been my experience. I cannot select a disk package and install it. I bring it in, and I compile it, but it doesn't install. It has been several years since I have had to install from disk, and I may have forgotten another step that I have follow.

I agree that Online Package Manager is perfect and easy to use, but I haven't where it will install an older version of RichMemo.
Windows 11, LAZ 2.0.10, FPC 3.2.0, SVN 63526, i386-win32-win32/win64, using windows unit

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: Installing RichMemo into Lazarus 2.0.0
« Reply #11 on: March 09, 2022, 05:46:54 pm »
Quote
dwCookie:= Longint(SourceStream);

Would it be the same method; ie. LongWord(SourceStream);

It would be the same issue. LongInt, LongWord, Cardinal, DWord - they always are 32-bit integers, in both 32- and 64-bit applications. But the integers that you need must change their size from 32 to 64 bit, depending on the bitness of the application. And these are the PtrInt, PtrUInt, NativeInt, NativeUInt types.

I cannot select a disk package and install it. I bring it in, and I compile it, but it doesn't install. It has been several years since I have had to install from disk, and I may have forgotten another step that I have follow.
No you can. Go to "Package" > "Open package file" > Navigate to the folder in which you unzipped the package; select the .lpk file > "Use" > "Install". This works for most packages.

BUT: you cannot "install" runtime packages (you can see this in "Option" > "IDE Integration") - you only need to open the package file so that the IDE knows where the lpk file ist.

And some packages are split into runtime and designtime packages. They usually have an appendix in their name such as "Run"/"Design" or "R"/"D" or similar. At first "open" the runtime package with "Package" > "Open package file". Then load the designtime package and "install" it as I described above.

Usually runtime and designtime packages must reside in different directories, and sometimes the designtime package is hard to find. Like with RichMemo. The package that you see first here it the runtimepackage ("richmemopackage.lpk"); the designtime package is in folder "ide" of the RichMemo installation ("richmemo_design.lpk")

If you, by all means, want an older version of RichMemo, take this one: https://sourceforge.net/p/lazarus-ccr/svn/HEAD/tree/components/richmemo/ (download the "Snapshot"), or maybe even this ancient one: https://sourceforge.net/projects/lazarus-ccr/files/RichMemo/RichMemo%201.0.0/. But don't ask for help in case of bugs - everybody will tell you to upgrad to a newer version...

rick2691

  • Sr. Member
  • ****
  • Posts: 444
Re: Installing RichMemo into Lazarus 2.0.0
« Reply #12 on: March 09, 2022, 07:25:55 pm »
wp,

Quote
LongInt, LongWord, Cardinal, DWord - they always are 32-bit integers, in both 32- and 64-bit applications. But the integers that you need must change their size from 32 to 64 bit, depending on the bitness of the application. And these are the PtrInt, PtrUInt, NativeInt, NativeUInt types.

Now I get it.

Quote
But don't ask for help in case of bugs - everybody will tell you to upgrade to a newer version.

Got it.

Rick
Windows 11, LAZ 2.0.10, FPC 3.2.0, SVN 63526, i386-win32-win32/win64, using windows unit

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: Installing RichMemo into Lazarus 2.0.0
« Reply #13 on: March 10, 2022, 06:18:50 am »
But don't ask for help in case of bugs - everybody will tell you to upgrad to a newer version...
do be honest, I won't... I'd be happy to update richmemo sources to be compatible with 2.0.0 (if a certain IFDEFs used)

But the problem is not with richmemo itself, but rather with FPC version changes and the use of WinAPI directly
« Last Edit: March 10, 2022, 06:37:10 am by skalogryz »

 

TinyPortal © 2005-2018