Re: [Lazarus] Making sources compatible with Delphi (but Lazarus is priority)
On Mon, May 1, 2017 at 11:06 AM, Juha Manninen via Lazaruswrote: > On Mon, May 1, 2017 at 12:30 PM, Tony Whyman via Lazarus > ... > > No! The good idea is to use "String". I agree. >> 5. Take care when using string literals. >> I added >> {$IFDEF FPC} >> {$codepage UTF8} >> {$ENDIF} > > Yes, string literals are tricky but usually you should NOT use {$codepage > UTF8}. > It is explained in the wiki page. I will not repeat it here. So, as Mattias said, we should code using ANSI chars and everything will be Ok. >> 7. Generics > > For Delphi compatible generics you can use FPC trunk and the Generics > Collection lib made by Maciej. Is it part of FPC? If not, could you can post the official URL? >> I hope you find this a useful checklist. > > It contained so much false information that it only confuses people. :( > > I want to repeat that it is possible to write code dealing with > Unicode that is fully compatible with Delphi at source level. > It will be compatible with a future UTF-16 solution in Lazarus as well. > Encoding agnostic (UTF-8 / UTF-16) code is possible even if you must > iterate individual codepoints. See the wiki page for details. That is I wanted to read. Thanks. Some doubts: > Remember these to keep your code compatible: > 1. Normally use type "String". > 1. Assign a constant always to a type String variable. What do you mean? Instead of create a constant, is it better create a String variable and assign the string to it? > 2. Use type UnicodeString explicitly for API calls that need it. Best regards, Marcos Douglas -- ___ Lazarus mailing list Lazarus@lists.lazarus-ide.org http://lists.lazarus-ide.org/listinfo/lazarus
Re: [Lazarus] Making sources compatible with Delphi (but Lazarus is priority)
On Mon, May 1, 2017 at 8:47 AM, Mattias Gaertner via Lazaruswrote: > Option a) You can use English in sources and load all non ASCII > constants via resourcestrings or similar. Then the codepage is > irrelevant. > Option b) You can store all files as UTF-8 with BOM. Then FPC will > store all non ASCII string constants as unicodestrings. Be careful when > using PChar with them. This adds implicit conversions, so it might be > slower. > Maybe option A could be the best. I did not remember to use resourcestrings... it is a good tip, thanks. Marcos Douglas -- ___ Lazarus mailing list Lazarus@lists.lazarus-ide.org http://lists.lazarus-ide.org/listinfo/lazarus
Re: [Lazarus] Making sources compatible with Delphi (but Lazarus is priority)
On Mon, May 1, 2017 at 6:30 AM, Tony Whyman via Lazaruswrote: > Marcos, > > When I originally created the Firebird Pascal API package, I wrote it with > FPC as the only intended target. However, I then got feedback asking for > Delphi compatibility and I couldn't resist the challenge of seeing how easy > it would be to convert the source code. In the end, it was not that > difficult and the following summarises the changes needed (apart from the > minor syntax changes): > > [...snip...] > Tony, thank you for all these tips. Best regards, Marcos Douglas -- ___ Lazarus mailing list Lazarus@lists.lazarus-ide.org http://lists.lazarus-ide.org/listinfo/lazarus
Re: [Lazarus] Making sources compatible with Delphi (but Lazarus is priority)
On Mon, May 1, 2017 at 7:40 PM, Tony Whyman via Lazaruswrote: > I am not sure how much your second post rows back from this but I do think > that false is a bit harsh. Yes, sorry, it was correct when using the default types in FPC 3. However making it compatible with Delphi requires some effort, as you noticed. My experience is that the Unicode support provided by LazUtils leads to more Delphi compatible code. The Windows system codepages are a problem, yes. Then data must be converted in some I/O layer. Everybody please experiment with it. It can be used also for non-GUI code. Juha -- ___ Lazarus mailing list Lazarus@lists.lazarus-ide.org http://lists.lazarus-ide.org/listinfo/lazarus
Re: [Lazarus] Making sources compatible with Delphi (but Lazarus is priority)
Am 01.05.2017 18:50 schrieb "Tony Whyman via Lazarus" < lazarus@lists.lazarus-ide.org>: > > > > On 01/05/17 16:33, Sven Barth via Lazarus wrote: >> >> Would you please elaborate on these and which FPC version you targeted? >> >> Regards, >> Sven >> >> >> > I am working with FPC 3.0.x and an example of the solution I used follows. Note that with FPC, there is no problem calling a constructor from a placeholder, while with delphi I found it necessary to add an explicit coercion. I also wanted to return the interface provided by the object. Again with FPC, this is easy. With Delphi, I found it necessary to use QueryInterface to do the same. > > The difference between the two seems to be that FPC waits until the generic is instantiated before type checking while Delphi performs type checking when compiling the generic itself - or thereabouts. IMHO, FPC is much superior to Delphi in this area. Your assumption about the way FPC and Delphi do things is indeed correct. Comments of mine follow inside your example. > {$IFDEF FPC} > TOutputBlockItemGroup<_TItem,_IItem> = class(TOutputBlockItem) > {$ELSE} > TOutputBlockItemGroup<_TItem: TOutputBlockItem; _IItem: IUnknown> = class(TOutputBlockItem) > {$ENDIF} You should be able to use the second variant with FPC as well. It would allow the compiler to do more type checking when parsing the generic instead of when specializing it. > public > function GetItem(index: integer): _IItem; > function Find(ItemType: byte): _IItem; > property Items[index: integer]: _IItem read getItem; default; > end; > > > > {$IFDEF FPC} > { TOutputBlockItemGroup } > > function TOutputBlockItemGroup<_TItem,_IItem>.GetItem(index: integer): _IItem; > var P: POutputBlockItemData; > begin > P := inherited getItem(index); > Result := _TItem.Create(self.Owner,P); > end; > > function TOutputBlockItemGroup<_TItem,_IItem>.Find(ItemType: byte): _IItem; > var P: POutputBlockItemData; > begin > P := inherited Find(ItemType); > Result := _TItem.Create(self.Owner,P); > end; > > > {$ELSE} > > { TOutputBlockItemGroup } > > function TOutputBlockItemGroup<_TItem,_IItem>.GetItem(index: integer): _IItem; > var P: POutputBlockItemData; > Obj: TOutputBlockItem; > begin > P := inherited getItem(index); > Obj := TOutputBlockItemClass(_TItem).Create(self.Owner,P); Is this typecast really needed? > if Obj.QueryInterface(GetTypeData(TypeInfo(_IItem))^.Guid,Result) <> 0 then > IBError(ibxeInterfaceNotSupported,[GuidToString(GetTypeData(TypeInfo(_IItem))^.Guid)]); > end; "Result := Obj;" does not work? What about "Result := Obj as _IItem;"? > function TOutputBlockItemGroup<_TItem,_IItem>.Find(ItemType: byte): _IItem; > var P: POutputBlockItemData; > Obj: TOutputBlockItem; > begin > P := inherited Find(ItemType); > Obj := TOutputBlockItemClass(_TItem).Create(self.Owner,P); > if Obj.QueryInterface(GetTypeData(TypeInfo(_IItem))^.Guid,Result) <> 0 then > IBError(ibxeInterfaceNotSupported,[GuidToString(GetTypeData(TypeInfo(_IItem))^.Guid)]); > end; Regards, Sven -- ___ Lazarus mailing list Lazarus@lists.lazarus-ide.org http://lists.lazarus-ide.org/listinfo/lazarus
Re: [Lazarus] Making sources compatible with Delphi (but Lazarus is priority)
On 01/05/17 16:33, Sven Barth via Lazarus wrote: Would you please elaborate on these and which FPC version you targeted? Regards, Sven I am working with FPC 3.0.x and an example of the solution I used follows. Note that with FPC, there is no problem calling a constructor from a placeholder, while with delphi I found it necessary to add an explicit coercion. I also wanted to return the interface provided by the object. Again with FPC, this is easy. With Delphi, I found it necessary to use QueryInterface to do the same. The difference between the two seems to be that FPC waits until the generic is instantiated before type checking while Delphi performs type checking when compiling the generic itself - or thereabouts. IMHO, FPC is much superior to Delphi in this area. {$IFDEF FPC} TOutputBlockItemGroup<_TItem,_IItem> = class(TOutputBlockItem) {$ELSE} TOutputBlockItemGroup<_TItem: TOutputBlockItem; _IItem: IUnknown> = class(TOutputBlockItem) {$ENDIF} public function GetItem(index: integer): _IItem; function Find(ItemType: byte): _IItem; property Items[index: integer]: _IItem read getItem; default; end; {$IFDEF FPC} { TOutputBlockItemGroup } function TOutputBlockItemGroup<_TItem,_IItem>.GetItem(index: integer): _IItem; var P: POutputBlockItemData; begin P := inherited getItem(index); Result := _TItem.Create(self.Owner,P); end; function TOutputBlockItemGroup<_TItem,_IItem>.Find(ItemType: byte): _IItem; var P: POutputBlockItemData; begin P := inherited Find(ItemType); Result := _TItem.Create(self.Owner,P); end; {$ELSE} { TOutputBlockItemGroup } function TOutputBlockItemGroup<_TItem,_IItem>.GetItem(index: integer): _IItem; var P: POutputBlockItemData; Obj: TOutputBlockItem; begin P := inherited getItem(index); Obj := TOutputBlockItemClass(_TItem).Create(self.Owner,P); if Obj.QueryInterface(GetTypeData(TypeInfo(_IItem))^.Guid,Result) <> 0 then IBError(ibxeInterfaceNotSupported,[GuidToString(GetTypeData(TypeInfo(_IItem))^.Guid)]); end; function TOutputBlockItemGroup<_TItem,_IItem>.Find(ItemType: byte): _IItem; var P: POutputBlockItemData; Obj: TOutputBlockItem; begin P := inherited Find(ItemType); Obj := TOutputBlockItemClass(_TItem).Create(self.Owner,P); if Obj.QueryInterface(GetTypeData(TypeInfo(_IItem))^.Guid,Result) <> 0 then IBError(ibxeInterfaceNotSupported,[GuidToString(GetTypeData(TypeInfo(_IItem))^.Guid)]); end; -- ___ Lazarus mailing list Lazarus@lists.lazarus-ide.org http://lists.lazarus-ide.org/listinfo/lazarus
Re: [Lazarus] Making sources compatible with Delphi (but Lazarus is priority)
On 01/05/17 15:18, Juha Manninen via Lazarus wrote: On Mon, May 1, 2017 at 12:30 PM, Tony Whyman via Lazaruswrote: When I originally created the Firebird Pascal API package, Now I realize your code may have been for FPC but not for Lazarus. Even then the solution provided by LazUtils (2 files there) is good because it allows compatible and portable code. Later when FPC's UTF-16 support is ready, such code can be ported easily. Juha I assume that you mean that my code is non-visual which is indeed where I am coming from. If you want to write an application that is LCL/VCL compatible then that is another can of worms. Your concluding remarks in your other post were: >>I hope you find this a useful checklist. It contained so much false information that it only confuses people. I want to repeat that it is possible to write code dealing with Unicode that is fully compatible with Delphi at source level. It will be compatible with a future UTF-16 solution in Lazarus as well. Encoding agnostic (UTF-8 / UTF-16) code is possible even if you must iterate individual codepoints. See the wiki page for details. Remember these to keep your code compatible: 1. Normally use type "String". 1. Assign a constant always to a type String variable. 2. Use type UnicodeString explicitly for API calls that need it. I am not sure how much your second post rows back from this but I do think that false is a bit harsh. You seem to be coming from a view that strings are strings and the compiler should be allowed to work out what is the appropriate string encoding for the local environment. All the programmer has to do is declare the type as "string" and all will be good. I guess that is your definition of portable code: it is agnostic as regards the string encoding. I am coming from a much messier perspective that says a portable program has to deal with whatever string encoding is thrown at it. It may be valid criticism to say that I was taking a particularly messy example and deriving generic rules from it - but few programs work in a vacuum and it is worth being aware of real world problems. I my case, the real world problem is Firebird. Firebird will expect or give you a string encoded not according to the local environment but that which was specified for the database connection and it is the API user that decides this and not the API. Ideally, the user specifies UTF8, but Firebird supports many other string encodings - but not UTF16 or Unicode at present. In the original version of the library, the API was defined using the "string" type as were the internal structures. When I looked at moving to Delphi support, there was no way that this would work if "string" suddenly became "UnicodeString". All over the place I had assumed that "string" meant "AnsiString" including checking and setting the code page in order to match the connection character set with whatever code page was being used by the API user. Could I have written the API without being aware of the character encoding? I doubt it. The connection character set is not something that the compiler can be aware of. Part of the role of the API library is to manage the character encoding on behalf of the user. On the other hand, by defining the API using the explicit AnsiString type, it should mean that if the API user uses the "string" type, then the compiler can automatically transliterate from the API to the API user's string types when string means "UnicodeString". So is my messy example typical or atypical? Am I correct in offering it as a source of rules. Ideally, it is atypical. However, I would observe that few programs exist in isolation. They have to deal with external objects such as files, GUIs and TCP connections. The compiler cannot work out the character encoding for itself in these cases and either your program or some intermediate library has to be character coding aware in order to deal with these objects. The bottom line is that it would be great if we never needed to be aware of the character encoding behind the string type. However, all too often you do and, because of that, when you are writing code that is portable between platforms and compilers, you either needed to be explicit in the string type throughout your program, or at least in the modules that deal with external interfaces. Tony Whyman -- ___ Lazarus mailing list Lazarus@lists.lazarus-ide.org http://lists.lazarus-ide.org/listinfo/lazarus
Re: [Lazarus] WMPaint
On Sun, 30 Apr 2017 19:06:18 +0300 Alexey via Lazaruswrote: > procedure TCustomControl.WMPaint(var Message: TLMPaint); > begin >if (csDestroying in ComponentState) or (not HandleAllocated) then exit; >Include(FControlState, csCustomPaint); >inherited WMPaint(Message); >Exclude(FControlState, csCustomPaint); > end; > > Maybe use try-finally here for Exclude? I don't know any case where this would help. Mattias -- ___ Lazarus mailing list Lazarus@lists.lazarus-ide.org http://lists.lazarus-ide.org/listinfo/lazarus
Re: [Lazarus] Gtk2 log "Refused invalidating during paint msg": how to check
On Sun, 30 Apr 2017 18:59:17 +0300 Alexey via Lazaruswrote: > How can I check that im inside Paint code? > > Maybe come control flag, or something, exists. if csCustomPaint in ControlState then Mattias -- ___ Lazarus mailing list Lazarus@lists.lazarus-ide.org http://lists.lazarus-ide.org/listinfo/lazarus
Re: [Lazarus] Making sources compatible with Delphi (but Lazarus is priority)
On Mon, May 1, 2017 at 12:30 PM, Tony Whyman via Lazaruswrote: > When I originally created the Firebird Pascal API package, Now I realize your code may have been for FPC but not for Lazarus. Even then the solution provided by LazUtils (2 files there) is good because it allows compatible and portable code. Later when FPC's UTF-16 support is ready, such code can be ported easily. Juha -- ___ Lazarus mailing list Lazarus@lists.lazarus-ide.org http://lists.lazarus-ide.org/listinfo/lazarus
[Lazarus] Lazarus/Free Pascal wasn't even an option in this "best languages to write a desktop Linux application" list
Over on the slant website Lazarus wasn't even an option for the following question: What are the best languages to write a desktop Linux application in? Link: https://www.slant.co/topics/635/~best-languages-to-write-a-desktop-linux-application-in I added Lazarus/Free Pascal to this list just now. If you like Lazarus/Free Pascal consider adding a recommend to it as an option at the link above. -- ___ Lazarus mailing list Lazarus@lists.lazarus-ide.org http://lists.lazarus-ide.org/listinfo/lazarus
[Lazarus] Gtk2 ShowWindow(..SW_RESTORE)
Hi. Maybe someone can implement it? Gtk2 misses it- case nCmdShow of SW_SHOWNORMAL: begin if B then gtk_widget_show(PGtkWidget(GtkWindow)) else begin if not GTK_WIDGET_VISIBLE(PGtkWidget(GtkWindow)) then gtk_widget_show(PGtkWidget(GtkWindow)); gtk_window_deiconify(GtkWindow); gtk_window_unmaximize(GtkWindow); gtk_window_unfullscreen(GtkWindow); end; end; SW_HIDE: gtk_widget_hide(PGtkWidget(GtkWindow)); SW_MINIMIZE: if not B then gtk_window_iconify(GtkWindow); SW_SHOWMAXIMIZED: if B then gtk_widget_show(PGtkWidget(GtkWindow)) else begin gtk_window_deiconify(GtkWindow); gtk_window_unfullscreen(GtkWindow); gtk_window_maximize(GtkWindow); end; SW_SHOWFULLSCREEN: if B then gtk_widget_show(PGtkWidget(GtkWindow)) else gtk_window_fullscreen(GtkWindow); end; -- Regards, Alexey -- ___ Lazarus mailing list Lazarus@lists.lazarus-ide.org http://lists.lazarus-ide.org/listinfo/lazarus
Re: [Lazarus] Making sources compatible with Delphi (but Lazarus is priority)
Marcos, When I originally created the Firebird Pascal API package, I wrote it with FPC as the only intended target. However, I then got feedback asking for Delphi compatibility and I couldn't resist the challenge of seeing how easy it would be to convert the source code. In the end, it was not that difficult and the following summarises the changes needed (apart from the minor syntax changes): 1. Standard set of defines for all modules: {$IFDEF MSWINDOWS} {$DEFINE WINDOWS} {$ENDIF} {$IFDEF FPC} {$mode delphi} {$ENDIF} The first one is needed to ensure that the "WINDOWS" defined symbol works with Delphi as well as FPC, while "mode delphi" is needed for FPC. 2. All strings declared explicitly as AnsiString expect where they are used with system calls (e.g. FileNames). This rule may vary between applications. However, as FPC defaults to AnsiString and Delphi to WideString, it is usually a good idea to be explicit in your string types. In my case, most strings were the ASCII subset of UTF8 and AnsiString worked for me. Similarly AnsiChar instead of Char. 3. PByte instead of PChar. Most uses of PChar in FPC/Lazarus aren't to character strings but are instead used to point to untyped buffers. However, in Delphi, PChar now means widestring and you will be caught out if you try and use PChar for an untyped buffer. PByte has the same semantic in both FPC and Delphi and is a pointer to an unsigned byte. 4. PAnsiChar instead of PChar. When PChar is used to genuinely point to a character string then as in point 2, you should be explicit about which type of string. PWideString may also be appropriate for some cases. 5. Take care when using string literals. I added {$IFDEF FPC} {$codepage UTF8} {$ENDIF} to sources with string literals just to make sure that FPC interprets all strings as UTF8. However, you need to be careful with Delphi. In some of the test scripts I ended up with source code such as: {$IFDEF DCC} ByName('title').AsString := UTF8Encode('Blob Test ©€'); ByName('Notes').AsString := UTF8Encode('Écoute moi'); {$ELSE} ByName('title').AsString := 'Blob Test ©€'; ByName('Notes').AsString := 'Écoute moi'; {$ENDIF} The first case (DCC defined) is Delphi and as my strings were all UTF8, I added an explicit UTF8Encode to force the literal to UTF8 before assigning to the string. Note the above is a test case with literals chosen to show up differences between character sets. 6. Varargs Delphi is much fussier than FPC about varargs constructs. If you have to use them then the only way this seems to work is e.g. function blah(...): sometype; cdecl varargs; 7. Generics If you don't have to go here then don't. Unfortunately I had dug a hole for myself and made extensive use of generics. Some of the differences are minor syntax, but others... Delphi and FPC just don't work the same way. Examples of problems are: - calling a constructor from a function defined using generics. - extracting an interface from an object defined using generics. Both are possible, but with very different syntax. 8.TSystemCodePage does not exist in Delphi You may need to add {$IF not declared(TSystemCodePage)} TSystemCodePage = word; {not defined in Delphi} {$IFEND} if you are using any Ansistring code page functions. 9. $IFEND or $ENDIF As illustrated in point 8, older versions of Delphi demand $IFEND rather than $ENDIF to terminate conditional compilation. I hope you find this a useful checklist. Regards Tony Whyman MWA On 30/04/17 17:37, Marcos Douglas B. Santos via Lazarus wrote: It months ago I realized that Lazarus was saving the sources like that: 1- If there is only ANSI chars, save it as ANSI encode; 2. If there is more than ANSI chars, save it as UTF8 encode; (correct me if I'm wrong about that) I think this was changed when I updated my FPC to 3.* and Lazarus (trunk). Everything continues works. This new behavior was completly transparent to me... but I have a doubt: If Delphi sources don't use UTF8, how is the best way to mantain sources that need to work in both compilers? I mean, I would like to work with FPC and Lazarus as I am used to doing, without take concerns about "remember to change the encode of these files", "remember to not put accented chars on code", or something like that. Is there some wiki page that explains this? Are you working on projects that have these problems? Could you tell me which is the best approach to deal with it? Thank you. Best regards, Marcos Douglas -- ___ Lazarus mailing list Lazarus@lists.lazarus-ide.org http://lists.lazarus-ide.org/listinfo/lazarus
Re: [Lazarus] Lazarus Bug: No exception raised when attempting to access an array outside of range.
On Mon, 1 May 2017 11:53:55 +1200 Graham Ward via Lazaruswrote: >[...] > I recently had a software/compilation bug whereby no exception was > raised when my code was accessing an array outside of its range. Enable runtime range checks: Project / Project Options / Compiler Option / Debugging / Checks / Range Or have a "debug" and "release" mode: http://wiki.lazarus.freepascal.org/IDE_Window:_Compiler_Options#Adding_a_release_and_debug_build_modes Mattias Took > some detective work, as it was resulting in corruption at runtime with > completely unrelated code. This was caused by a bug in my own software > that tried to access index 72 for an array of range [0..71]. What was > more interesting was that if I expanded the array to 72 (or 73,74,75 for > that matter) and then tried to access range+1 (IE index 73 for the array > with an index of [0..72] this appeared to cause no ill effect to my > program once more, so I was extremely "lucky" to have such an obvious > bug appear in my code. Something more subtle would have been a lot more > difficult to locate. > > The offending code is as follows: > > setlength(isMerged, ParityCol); // fixed length for array keeping > track of merged cells. > setlength(ColIndex, ParityCol); // Define the length of the Column > Index > For J := 0 to ParityCol do > Begin > isMerged[J] := False; //This line was leading to the program > becoming unresponsive in another totally unrelated part of code > (AssignFile...) in another procedure > ColIndex[J] := 1000; // This line, although also accessing outside > of the legal range, did not appear to cause any problems!!! > end; > > Note I even tried the following line, which is obviously wrong (as the > array has a maximum index of 71) > > ColIndex[175] := 500; > > In other languages (that I am more familiar with) an exception (Error : > Array index outside of range) would have been raised. Why does the > Lazarus compiler not raise a similar error? > > I am using: > > Code Typhon Version 6.0 > FPC Version 3.1.1 > SVN Revision : 54036 > > > Assuming this is an actual bug in the compiler, then I hope this > information proves useful. If not, then please advise me accordingly, > thanks. > > Aside from this, let me say a very big thank you to you guys for all > your hard work in what is a very useful piece of software for me (FPC). > Your efforts are greatly appreciated. > > Kind Regards, > Graham > New Zealand -- ___ Lazarus mailing list Lazarus@lists.lazarus-ide.org http://lists.lazarus-ide.org/listinfo/lazarus