-
Content Count
2990 -
Joined
-
Last visited
-
Days Won
134
Everything posted by Remy Lebeau
-
Access violation errors while running without the debugger
Remy Lebeau replied to christos papapostolou's topic in Algorithms, Data Structures and Class Design
In addition to what others said - it is unusual to get an AccessViolation due to Execution of an address, usually it is due to a Read or Write instead. If you are executing code at a bad memory address, that means you tried to call a function via a corrupted function pointer, or something like that, which will be much more difficult to find. If it were just a read/write error, the error message would also give you the memory address of the code that tried to access the bad memory, so you could more easily jump right to that code. -
Then you are using an outdated version of Indy and should upgrade. The ReadUInt16() method was added almost a decade ago, in Delphi XE8. In the meantime, you can use the older ReadWord() method instead. That calculation is wrong. You need to multiple by 256 ($100), not by 16 ($10). Better to just use ReadWord()/ReadUInt16() instead. True means it will append the read bytes to the end of the TIdBytes. False means it will store the read bytes at the beginning of the TIdBytes, and will grow the TIdBytes if it is too small.
-
Not a whole lot, unfortunately. Trimming the debug info helps a lttle, but most of the size is just RTL bloat, Unicode, DFMs, RTTI, etc. In Delphi, it is possible to reduce some of the RTTI a little, but not in C++Builder, AFAIK.
-
That is to be expected with a standalone EXE. It should not need those DLLs if you have disabled all of the options I mentioned earlier. Are you sure you did it in all of your build configurations? Did you do a full rebuild? Are you sure you are simply not running an older version of the EXE? To run a single EXE on both types of PCs, you have to compile the EXE for 32bit only, not for 64bit. Make sure you have the 32bit platform active in your project's Target Platforms settings.
-
In that case, your code logic is wrong. You are throwing away one of the length bytes, so you will only be able to handle packets up to 256 bytes max. And, based on the examples provided, you should not be subtracting -1 from the length, either. You are ignoring the last byte in the payload. Try this instead: var s: string; len: UInt16; ... try if IdTCPClient1.IOHandler.InputBufferIsEmpty then begin if not IdTCPClient1.IOHandler.CheckForDataOnSource(1000) then Exit; end; len := IdTCPClient1.IOHandler.ReadUInt16; s := IdTCPClient1.IOHandler.ReadString(len); Memo1.Lines.Add(s); Timer4.Enabled := false; except end; Fair enough, though I would still not advise doing that on the main UI thread to begin with. Only for packets with payloads up to 255 bytes in size. Larger payloads will not have a zero as the 1st byte. This protocol allows for payloads up to 65535 bytes in size.
-
There is nothing built-in to FMX for retrieving the device's fonts. I've seen 3rd party solutions that provide FMX wrappers for OSX and Windows, but not for Android. Android does have some APIs you can try directly, see: https://stackoverflow.com/questions/3532397/how-to-retrieve-a-list-of-available-installed-fonts-in-android
-
FYI, there is an Indy-specific forum on this site: https://en.delphipraxis.net/forum/35-indy/ It is hard to answer that without knowing any details about the particular specification you are coding against. If you are expecting a response immediately after writing, then why are you using a Timer? Just read and let it block. If you are doing this from the main UI thread and don't want to block the UI, then use a worker thread. Why do you keep clearing the IOHandler.InputBuffer when it is already empty? Why are you discarding the 1st byte? What does it represent? FYI, you can replace your entire loop with a single call to Indy's BytesToString() function, eg: var Buffer: TIdBytes; ... IdTCPClient1.IOHandler.ReadBytes(Buffer, bajt - 1, False); s := BytesToString(Buffer); Or, you could just use IOHandler.ReadString() instead of IOHandler.ReadBytes(), eg: s := IdTCPClient1.IOHandler.ReadString(bajt - 1);
-
For both Delphi and C++: Project > Options > Packages > Runtime Packages "Link with runtime packages" = false If you are making a C++ project, you'll also need: Project > Options > Building > C++ Linker "Link with Dynamic RTL" = false "Link with the Delphi Runtime Library" = false Note that with these settings, Packages will be built into the EXE so you don't have to deploy any BPLs. But, if your code (or any of its dependencies) require external DLLs, you will still have to deploy those with your EXE. At the bare minimum, you could just zip up all of the binaries and extract them to a folder on the target machine. But why would you not want to use a setup package that handles this for you?
-
Delphi doesn't support bitfields, so you have to do the bit-twiddling manually, as Rollo62 demonstrated. https://stackoverflow.com/questions/282019/how-to-simulate-bit-fields-in-delphi-records If it wasn't for the load_weight_zone field being 2 bits, you could have just used a plain Delphi 'Set of enum' instead.
-
https://www.indyproject.org/2021/02/10/links-to-old-indy-website-pages-are-currently-broken/
-
C++ Builder 11.3 CE - Windows 10 - new installation
Remy Lebeau replied to cbPlus's topic in General Help
CE licenses are good for only 1 year. You need to re-register a new CE license every year. That said, you should be able to reinstall CE using the same license up to 3 times a year before it expires. If you need to reinstall more times than that, then you'll have to contact Embarcadero for support. You should install Windows fresh and then install the IDE and then make a backup. If you have to start over, restore the backup instead of starting fresh. -
In which case, you could have just removed it from within the IDE itself, via the "Component" menu, "Install Packages" dialog.
-
AutoNaming Events on TCollectionItem
Remy Lebeau replied to The Code Captain's topic in Delphi IDE and APIs
The only methods your TCollectionItem can override to influence the Object Inspector are GetDisplayName() and GetNamePath(). If you want to customize how your event handlers are auto-generated, you will likely need a custom property editor derived from TMethodProperty (see how TMethodProperty.Edit() is implemented in $(BDS)\source\ToolsAPI\DesignEditors.pas). -
Setting Events on TPersistent members
Remy Lebeau replied to The Code Captain's topic in Delphi IDE and APIs
The IDE simply doesn't show events for a TPersistent object that is not derived from TComponent or TCollectionItem. I found various forum posts going back over 20 years with people struggling with this exact same problem and I haven't seen anyone post a working solution in that time, not even with custom editors. -
FYI, in Delphi 12 Athens, TCustomDrawState now uses a new enum type TCustomDrawStateItem, so you can cast the values to that type, eg: for LState := LMin to LMax do begin if TCustomDrawStateItem(LState) in ACustomDrawState then Append(Result, GetEnumName(TypeInfo(TCustomDrawStateItem), LState)); end;
-
Simply tweak the code a little to keep track of the quantity used while iterating, eg: var LocNos, LotNos: string; QtyWanted, QtyUsed: Double; ... Table2.First; while not Table2.Eof do begin QtyWanted := Table2QTY.AsFloat; if QtyWanted > 0.0 then begin Query1.SQL.Text = 'SELECT * FROM Table1 WHERE ITEMCODE = :ItemCode AND LOCQTY > 0'; Query1.ParamByName('ItemCode').AsString := Table2ItemNo.AsString; Query1.Open; try Query1.First; if not Query1.Eof then begin LocNos := ''; LotNos := ''; repeat QtyUsed := Math.Min(Query1.FieldByName('LOCQTY').AsFloat, QtyWanted); LocNos := LocNos + Query1.FieldByName('LOCNO').AsString + '=' + FloatToStr(QtyUsed) + ','; LotNos := LotNos + Query1.FieldByName('LOTNO').AsString + ','; QtyWanted := QtyWanted - QtyUsed; Query1.Next; until Query1.Eof or (QtyWanted <= 0.0); SetLength(LocNos, Length(LocNos)-1); SetLength(LotNos, Length(LotNos)-1); Table2.Edit; Table2LOCNO.AsString := LocNos; Table2LOTNO.AsString := LotNos; Table2.Post; end; finally Query1.Close; end; end; Table2.Next; end;
-
Given the example you provided, try something more like this: var LocNos, LotNos: string; ... Table2.First; while not Table2.Eof do begin Query1.SQL.Text = 'SELECT * FROM Table1 WHERE ITEMCODE = :ItemCode AND LOCQTY <= :Qty'; Query1.ParamByName('ItemCode').AsString := Table2ItemNo.AsString; Query1.ParamByName('Qty').AsFloat := Table2QTY.AsFloat; Query1.Open; try Query1.First; if not Query1.Eof then begin LocNos := Query1.FieldByName('LOCNO').AsString + '=' + Query1.FieldByName('LOCQTY').AsString; LotNos := Query1.FieldByName('LOTNO').AsString; repeat Query1.Next; if Query1.Eof then Break; LocNos := LocNos + ', ' + Query1.FieldByName('LOCNO').AsString + '=' + Query1.FieldByName('LOCQTY').AsString; LotNos := LotNos + ', ' + Query1.FieldByName('LOTNO').AsString; until False; Table2.Edit; Table2LOCNO.AsString := LocNos; Table2LOTNO.AsString := LotNos; Table2.Post; end; finally Query1.Close; end; Table2.Next; end; Alternatively: var LocNos, LotNos: TStringList; ... Table2.First; while not Table2.Eof do begin Query1.SQL.Text := 'SELECT * FROM Table1 WHERE ITEMCODE = :ItemCode AND LOCQTY <= :Qty'; Query1.ParamByName('ItemCode').AsString := Table2ItemNo.AsString; Query1.ParamByName('Qty').AsFloat := Table2QTY.AsFloat; Query1.Open; try Query1.First; if not Query1.Eof then begin LocNos.Clear; LotNos.Clear; repeat LocNos.Add(Query1.FieldByName('LOCNO').AsString + '=' + Query1.FieldByName('LOCQTY').AsString); LotNos.Add(Query1.FieldByName('LOTNO').AsString); Query1.Next; until Query1.Eof; Table2.Edit; Table2LOCNO.AsString := LocNos.CommaText; Table2LOTNO.AsString := LotNos.CommaText; Table2.Post; end; finally Query1.Close; end; Table2.Next; end;
-
Those classes are both from Indy, but there is no mention of Indy in the code you have shown. And while there are some intentional leaks in Indy related to those classes, they are registered with the RTL's memory manager and FastMM should be ignoring them (also, the leak report would look different if those leaks were actually being reported). So, this implies that some other leaks exist in code that is not related to what you have shown here.
-
Indeed: CreateleOleObject -> CreateOleObject
-
It is not just a matter of IF it shows, but also WHICH VERSION it shows. Anything above 1.0.2 is not going to work with the default TIdSSLIOHandlerSocketOpenSSL at this time.
-
What do Indy's IdSSLOpenSSLHeaders.WhichFailedToLoad() and IdSSLOpenSSL.OpenSSLVersion() functions report after the load fails?
-
My example is specific to Windows, but the general approach is not. That is the point of providing your own IFMXDialogServices implementation - you can implement it for each target platform (which FMX does by default) and overwrite the default implementation as needed. TOpenDialog itself is platform-agnostic, it just delegates to IFMXDialogServices for the platform-specific stuff. You can have a different IFMXDialogServices class for each platform, or you can have 1 class with IFDEFs for each platform, etc. In any case, I just checked in Delphi 12.1 and FMX's default implementation of IFMXDialogService.DialogOpenFiles() (and a few other methods) for Android is a complete no-op (because modal dialogs are not supported on Android), which means that TOpenDialog would not do anything at all on Android. So, if you wanted to use TOpenDialog on Android then you would have to implement IFMXDialogServices yourself to display your own custom dialog.
-
Which target platform(s) are you having the trouble with? For instance, on Windows, those 3 TOpenDialog events in FMX are simply not hooked up at all (in VCL, they are). Which is funny because in later Delphi versions (not in 10.3), FMX's TOpenDialog component does actually receive those events from Vista+ (but not from earlier OS versions), but it does not pass them along to user event handlers (like VCL does). Fortunately, there is a workaround - you can write your own class that implements the IFMXDialogService interface, and then register an instance of that class with FMX via TPlatformService.AddPlatformService(). You can then implement the IFMXDialogService.DialogOpenFiles() method to do whatever you want, ie on Windows you can directly invoke the Win32 GetOpenFileName() or IFileOpenDialog API yourself and get UI events from it as needed.
-
Make a TMemo.seltext modification cancellable by the user
Remy Lebeau replied to FabDev's topic in VCL
It was added in 11.0 Alexandria. http://docwiki.embarcadero.com/RADStudio/Alexandria/en/What's_New#Smaller_Changes -
I covered that in my earlier reply. That example is performing: "SEARCH NOT BODY <body1> BODY <body2>" which AFAIK is treated as: "(NOT BODY <body1>) AND (BODY <body2>)" NOT takes only 1 condition as input. If you want multiple NOT conditions, you need multiple NOTs in the array, 1 for each condition, ie: "SEARCH NOT <criteria1> NOT <criteria2>" which is treated as: "(NOT <criteria1>) AND (NOT <criteria2>)" or: "SEARCH NOT OR <critera1> <criteria2>" which is treated as: "NOT (<criteria1> OR <criteria2>)" Only 1 criteria per NOT. Please read RFC 3501 Section 6.4.4