Jump to content

Remy Lebeau

Members
  • Content Count

    2955
  • Joined

  • Last visited

  • Days Won

    133

Everything posted by Remy Lebeau

  1. Actually, calling convention is part of the RTTI for invokable types, including class methods. But TRttiInstanceProperty.DoGetValue() (and DoSetValue()) are ignoring that fact and just assume Delphi's default Register convention when invoking the property getter/setter. If I change the invocation to specify Cdecl instead of Register, then no crash occurs. I have opened a bug ticket for this: RSS-3574: AV in TRttiProperty if getter/setter does not use Register calling convention
  2. Remy Lebeau

    access violation changing font

    Or, use TThread.ForceQueue() instead, eg: procedure TFprincipal.FontNameRClick(Sender: TObject); begin TThread.ForceQueue(nil, procedure begin ga_TipoLetra := FontNameR.Text; Font.Name := ga_TipoLetra; gn_FontSize := StrToInt(ComboSize.Text); Font.Size := gn_FontSize; Screen.MessageFont := Font; ToolBar.Font.Size := Min(gn_FontSize, 14); end); end;
  3. You are not checking if either TRttiContext.GetType() or TRttiType.GetProperty() are returning nil before accessing the objects they return. procedure TFormSimpleDraw2.Button2Click(Sender: TObject); var Value: TValue; LType: TRttiType; RttiContext: TRttiContext; CaretPositionProp: TRttiProperty; CaretPosition: TCaretPosition; begin RttiContext := TRttiContext.Create; LType := RttiContext.GetType(Memo1.ClassInfo); if LType = nil then Exit; // <-- add this CaretPosition := Memo1.CaretPosition; CaretPositionProp := LType.GetProperty('CaretPosition'); if CaretPositionProp = nil then Exit; // <-- add this Value := CaretPositionProp.GetValue(Memo1); ... end;
  4. Remy Lebeau

    access violation changing font

    Why not use Screen.Fonts instead?
  5. Remy Lebeau

    Listview data problem

    Calling Free() on a nil pointer is perfectly safe. So that means you must be calling Free() on a non-nil pointer that is NOT pointing at a valid TBitmap object. Did you make the adjustments I showed you to give each TListItemData its own TBitmap object? Also, DO NOT use both OnClose and OnDeletion events to free the same memory. Use one or the other. The OnDeletion event is the preferred place to free custom data stored in a TListView, as it is called every time a TListItem is removed from the TListView, even during shutdown. I've used this technique many times in the past, so I know it works.
  6. Remy Lebeau

    Listview data problem

    All of your list items are pointing at a single TBitmap object in memory, so all of them will show the last image that was loaded from the DB. If you want to show a separate image for each list item, they each need their own TBitmap object, eg: type PListItemData = ^TListItemData; TListItemData = record theString: string; ThePicture: TBitmap; end; ... procedure TMyForm.RunQueryAndFillListView; var ClipItem: TListItem; ListItemData: PListItemData; begin ... while not FDQuery2.Eof do begin ... ClipItem := lvClip.Items.Insert(0); New(ListItemData); try ListItemData.theString := s.Text; ListItemData.ThePicture := nil; if ContainsText(s.Text, 'Picture') then begin BlobField := FDQuery2.FieldByName('Image') as TBlobField; Stream := FDQuery2.CreateBlobStream(BlobField, bmRead); try ListItemData.ThePicture := TBitmap.Create; ListItemData.ThePicture.LoadFromStream(Stream); finally Stream.Free; end; end; ClipItem.Data := ListItemData; except ListItemData.ThePicture.Free; Dispose(ListItemData); end; FDQuery2.Next; end; ... end; ... // TListView.OnDeletion event handler procedure TMyForm.lvClipDeletion(Sender: TObject; Item: TListItem); var ListItemData: PListItemData; begin ListItemData := PListItemData(Item.Data); if ListItemData <> nill then begin ListItemData.ThePicture.Free; Dispose(ListItemData); end; end;
  7. Remy Lebeau

    “Could not load SSL library”

    First off, you posted a screenshot of code that appears to contain an actual live app password in it. I suggest you delete that screenshot, invalidate that app password, and generate a new one. Don't EVER post live credentials to an online forum! Now then... What does Indy's IdSSLOpenSSLHeaders.WhichFailedToLoad() function report after the error has occurred? All of the DLLs on the GitHub page have been tested with Indy and known to be working. There isn't a releases section. That repo is just a collection of downloadable files. From https://github.com/IndySockets/OpenSSL-Binaries No, that is the best place. However, if you wanted to put them somewhere else, you can do that, too. You would just have to call Indy's IdSSLOpenSSLHeaders.IdOpenSSLSetLibPath() function at runtime to tell Indy where the DLLs are located.
  8. Remy Lebeau

    In App Purchase (consumable and subscription)

    There is no OnPurchaseRestored event in TInAppPurchase. Did you mean OnPurchaseCompleted instead? Oh. QueryPurchases() is an internal method that is called by another internal method QueryInventory() which is called only at the end of setting up a new connection to the BillingClient.
  9. Remy Lebeau

    In App Purchase (consumable and subscription)

    That is because you are clearing the FPurchaseMap before then querying the Products instead of querying the Purchases. IsProductPurchased() looks at FPurchaseMap, but QueryProducts() populates FProductDetailsMap and not FPurchaseMap. QueryPurchases() populates FPurchaseMap. Also, there is no OnPurchasesRequestResponse event for when QueryPurchases() completes. It triggers the OnSetupComplete event instead. Which implies QueryPurchases() was not intended to be used outside of initial component setup, since TInAppPurchase tracks purchase updates in real-time.
  10. Remy Lebeau

    Copying Directory

    Have you tried calling the overloaded version of TDirectory.Copy() that takes an IgnoreErrors parameter and set it to False? The overload of TDirectory.Copy() that you are calling implicitly uses IgnoreErrors=True. When IgnoreErrors=False then a failure to copy files will raise an EInOutError exception, containing a list of all the files that failed to copy and the reason(s) why they couldn't be copied. Are you getting that exception?
  11. Remy Lebeau

    In App Purchase (consumable and subscription)

    Yes, as a result of this post on StackOverflow a few day ago: How to get updated subscription status after cancellation without restarting the app (Google Play Billing in Delphi)? Hopefully, considering they did confirm on the ticket that it is a problem. Rather than clearing the whole Inventory, I was thinking it could instead just remove individual items that are no longer in the queried purchase list. True, it won't query the whole list. But it does listen for new purchases in real-time and add them individually to the Inventory. But I don't think it listens for subscription changes, that is a whole different workflow that the component is not setup to handle.
  12. Remy Lebeau

    Class helpers catch

    Did you report the problem to Embarcadero? It is either an error in the documentation, or a bug in the compiler.
  13. Remy Lebeau

    Shadow underneath Form does not always appear (CS_DROPSHADOW)

    You should not need to resort to this. The VCL already calls UnregisterClass() and RegisterClass() after CreateParams() exits. The purpose of CreateParams() is just to report the class details that the control wants, not to manipulate the registration directly.
  14. Remy Lebeau

    Stringgrid objects problem

    That is a very dangerous approach. Don't do it that way. First, there is no guarantee that accessing the ClassName on an invalid object will raise an exception. And second, reading from invalid memory may cause other side effects (ie, page faults, etc). Since your integers are very small, then you could simply look for integers first, and treat higher values as objects since they should never reside at such low memory addresses, eg: const MaxObjIntValue = 8; ... var value := NativeInt(Objects[c,r]); if (value >= 0) and (value <= MaxObjIntValue) then begin // is an integer, use value as needed... end else begin // is an object, use TObject(value) as needed... end ... if NativeInt(Objects[c,r]) > MaxObjIntValue then Objects[c,r].Free;
  15. Remy Lebeau

    Is TImage empty

    How does that code have anything to do with the discussion at hand? Also, why would you not simply use TImage.Picture.LoadFromFile() and let it handle everything for you? procedure LoginImage(const RutaBase: string); var filename : string; begin // Intentar cargar como BMP filename := IncludeTrailingPathDelimiter(RutaBase) + 'flogin.bmp'; if FileExists(filename) then begin imgFLogin.Picture.LoadFromFile(filename); end else begin ShowMessage('File not found') end; end;
  16. Remy Lebeau

    Is TImage empty

    Yes, and this is documented behavior: https://docwiki.embarcadero.com/Libraries/en/Vcl.Graphics.TPicture.Bitmap Where it says "a Metafile or Icon graphic", it really means "any non-Bitmap graphic" instead. Use the TPicture.Graphic property when you need to access as-is whatever TGraphic descendant is currently loaded in the TPicture. Use the TPicture.Bitmap property instead when you specifically need a TBitmap.
  17. Remy Lebeau

    Is TImage empty

    Check the TImage.Picture.Graphic and TGraphic.Empty properties: if (Image1.Picture.Graphic = nil) or Image.Picture.Graphic.Empty then You can assign nil to the TImage.Picture property: Image1.Picture := nil; // same as: // Image1.Picture.Assign(nil); Or to its Graphic property: Image1.Picture.Graphic := nil;
  18. Remy Lebeau

    Stringgrid objects problem

    Another option might be to use tagged pointers. Normally, objects are aligned in memory in such a way that certain bits in object pointers are always zero, so those bits can be repurposed if you are careful. For instance, if you limit your integer values to 31 bits (x86) or 63 bits (x64), you can use an unused bit in an object pointer to flag whether the pointer holds an integer value vs an object address, and just mask off the bit when extracting the value. For example: // this assumes objects are never stored at an odd-numbered memory address.. var intValue: Integer := ...; Objects[c,r] := TObject((NativeUInt(intValue) shl 1) or $1); ... var objValue: TObject := ...; Objects[c,r] := objValue; ... if (NativeUInt(Objects[c,r]) and $1) <> 0 then begin // is an integer... var intValue := Integer(NativeUInt(Objects[c,r]) shr 1); ... end else begin // is an object... var objValue := Objects[c,r]; ... end; ... if (NativeUInt(Objects[c,r]) and $1) = 0 then Objects[c,r].Free;
  19. Remy Lebeau

    Stringgrid objects problem

    Correct. You can't. So, either store all objects only, or all integers only. Don't mix types. But, if you must, then you'll need to either wrap the integers inside of objects, or add an extra header in front of each value to identify its type, etc.
  20. Remy Lebeau

    D12, Android 14, how to locate "assets\internal" at runtime

    Standard RTL Path Functions across the Supported Target Platforms
  21. Remy Lebeau

    Winapi.Windows.PROCESS_QUERY_LIMITED_INFORMATION not found

    It will compile, but it won't behave as you are expecting. PROCESS_QUERY_LIMITED_INFORMATION is not a compiler conditional via a {$DEFINE} statement, "-D" compiler switch, or "Conditional Defines" list in the project options, thus: {$IFDEF PROCESS_QUERY_LIMITED_INFORMATION} // will always evaluate as false {$IFNDEF PROCESS_QUERY_LIMITED_INFORMATION} // will always evaluate as true Regardless of whether PROCESS_QUERY_LIMITED_INFORMATION has been declared as a constant in a unit that your code uses. That is where {$IF (NOT) DECLARED} comes into play, as it supports declarations of types, constants, variables, etc. Not to be confused with {$IF (NOT) DEFINED}, which is the {$IF} version of {$IF(N)DEF} and thus supports only compiler conditionals. const PROCESS_QUERY_LIMITED_INFORMATION = $1000; {$IF DECLARED(PROCESS_QUERY_LIMITED_INFORMATION)} // will evaluate as true {$IF NOT DECLARED(PROCESS_QUERY_LIMITED_INFORMATION)} // will evaluate as false {$IF DECLARED(PROCESS_QUERY_DOESNT_EXIST)} // will evaluate as false {$IF NOT DECLARED(PROCESS_QUERY_DOESNT_EXIST)} // will evaluate as true That is a compiler/IDE bug that would need to be reported, with example to reproduce it. I don't get that error in my tests. Sure, though you would be using your own constant declared in your own unit, and not using a constant declared in the Winapi.Windows unit if Embarcadero ever decides to add it in at a later time.
  22. Remy Lebeau

    Winapi.Windows.PROCESS_QUERY_LIMITED_INFORMATION not found

    Wow, what a coincidence, so am I And what I showed works just fine in 12.2.
  23. Remy Lebeau

    Winapi.Windows.PROCESS_QUERY_LIMITED_INFORMATION not found

    It works perfectly fine for me exactly as I have shown it. What version are you using? {$IF} has been available since Delphi 6,
  24. Remy Lebeau

    Capture as soon as file paste is selected

    What are you going on about? That has nothing to do with the subject of this discussion.
  25. Remy Lebeau

    Winapi.Windows.PROCESS_QUERY_LIMITED_INFORMATION not found

    That won't work, as PROCESS_QUERY_LIMITED_INFORMATION is not a conditional you can test with {$IFNDEF}. Use {$IF NOT DECLARED} instead: {$IF NOT DECLARED(PROCESS_QUERY_LIMITED_INFORMATION)} const PROCESS_QUERY_LIMITED_INFORMATION = $1000; {$IFEND}
×