Jump to content

Remy Lebeau

Members
  • Content Count

    2684
  • Joined

  • Last visited

  • Days Won

    113

Everything posted by Remy Lebeau

  1. The VCL has a habit of recreating a whole window even if CreateWindow/Ex() is not actually required. Many UI attributes can actually be updated dynamically via SetWindowLong/Ptr() or control-specific APIs, but the VCL doesn't do things that way in most cases (sometimes it does).
  2. At my last company, I developed and maintained a central Windows service that all of our other products communicated with to 1) write entries in a centralized log file, 2) send out notifications, and 3) track heartbeats. I used a free-threaded ActiveX/COM object for the communication, and just about every thread of every product made use of this COM object. Each message identified which product and internal component it belonged to. Each product would register its heartbeats and then update them at regular intervals until shutdown. If a heartbeat ever timed out unexpectedly (because a thread had frozen or died, or was just running a task for too long) then the service would send out a notification containing those details to our tech support and/or server admins (usually an email, but other kinds of notifications were also supported).
  3. Remy Lebeau

    Use java code in Delphi

    This one was just brought to my attention: https://github.com/DelphiWorlds/JID "JID was created primarily as an alternative to Java2OP that ships with Delphi, in order to address some shortcomings in Java2OP."
  4. Remy Lebeau

    Use java code in Delphi

    I'll see if the problem exists in the latest Delphi. If the problem continues, please file a bug report with Embarcadero about Java2Op still being broken. You might need to just fix the generated code manually. Or look around to see if there is a 3rd party importer that works better than Java2Op.
  5. Remy Lebeau

    Use java code in Delphi

    Sorry, that was a copy/paste typo on my part. 'port' should be 'driver'. I have corrected it. Then the Java2Op translation is wrong. According to the official Android documentation, not of the UsbManager methods are static, so none of them should be declared in JUsbManagerClass, they should all be in JUsbManager instead. Which version of RADStudio/Java2Op are you using? This was a known problem in earlier Delphi versions (not sure if it's fixed in the latest version, I'll have to check), for instance: RSP-15473: Java2Op emits erroneous code RSP-24029: Regression in Java2OP so that instance methods are treated as class methods RSP-40400: Java2OP say often that method as Static (class) when they are not
  6. Remy Lebeau

    Use java code in Delphi

    That website provides examples in Java. Did you try matching them up to the classes in the Delphi unit which you generated? What exactly have you tried so far and are having trouble with? For instance, the 1st example to open a device might look something like this: uses ..., Androidapi.JNI.JavaTypes, Androidapi.JNI.GraphicsContentViewText, Androidapi.Helpers, JavaInterfaces; var manager: JUsbManager; availableDrivers: JList; driver: JUsbSerialDriver; connection: JUsbDeviceConnection; port: JUsbSerialPort; begin // Find all available drivers from attached devices. manager := TJUsbManager.Wrap(TAndroidHelper.Context.getSystemService(TJContext.JavaClass.USB_SERVICE)); availableDrivers := TJUsbSerialProber.JavaClass.getDefaultProber.findAllDrivers(manager); if availableDrivers.isEmpty then begin Exit; end; // Open a connection to the first available driver. driver := TJUsbSerialDriver.Wrap(availableDrivers.get(0)); connection := manager.openDevice(driver.getDevice); if connection = nil then begin // add UsbManager.requestPermission(driver.getDevice(), ..) handling here Exit; end; port := TJUsbSerialPort.Wrap(driver.getPorts.get(0)); // Most devices have just one port (port 0) port.open(connection); port.setParameters(115200, 8, TJUsbSerialPort.JavaClass.STOPBITS_1, TJUsbSerialPort.JavaClass.PARITY_NONE); ... end;
  7. Remy Lebeau

    Use java code in Delphi

    Can you fix the font formatting of your message? Your text is cut off. Can't read what the actual problem is that you are having with the converted code.
  8. Remy Lebeau

    problem with ComboBox

    The user did not interact with the ComboBox directly, they interacted with the Panel instead. The Panel's OnClick event invoked an API call to the ComboBox (the ItemIndex setter sends a CB_SETCURSEL message to the ComboBox), thus the text change is not a user-triggered action from the ComboBox's perspective, it is an application-triggered action. The ComboBox's OnChange event is fired in reply to a CBN_EDITCHANGE notification from the ComboBox, and CB_SETCURSEL does not trigger a CBN_EDITCHANGE notification.
  9. Sounds like a bug to me. Report it to Embarcadero: https://qp.embarcadero.com
  10. Remy Lebeau

    Packages and Package structure

    Yes, if you try to open those dialogs at design-time and the control has not been registered with the IDE yet. But if the dialogs create the control dynamically in code, then there is no problem. Probably, yes. It depends on your use case. Are you expecting other projects to use those dialogs? ICEs are compiler bugs, only Embarcadero can address those. You have to change your code to avoid them. Can't help you with runtime errors without more detail.
  11. You are not resetting ms.Position=0 before calling Param.LoadFromStream(). You are also leaking the TMemoryStream.
  12. Remy Lebeau

    Packages and Package structure

    If you can use the components on external Forms, why would you think you can't use them on internal Forms, too? Not really. Can you clarify the issue you are worried about with more detail?
  13. Remy Lebeau

    Drag Drop via Ole

    That code risks pointer truncation in a 64bit build. The integer typecast should be using NativeUInt or UIntPtr instead. Or, use pointer arithmetic via PByte instead. Also, the file list is a double-null terminated list, so make sure you account for that in case multiple files are dragged. Also, depending on the source, the file names may be using Ansi or Unicode characters, so pay attention to the DropFiles.fWide field.
  14. Remy Lebeau

    "Divided by zero" exception

    https://docwiki.embarcadero.com/RADStudio/Athens/en/What's_New#Disabling_Floating-Point_Exceptions_on_All_Platforms
  15. I see only a single retry in that code. Have you tried reconnecting multiple times, perhaps with a small delay in between each attempt?
  16. Why not simply catch the socket error and retry the failed operation?
  17. Remy Lebeau

    Drag Drop via Ole

    You don't. The drag code is running inside of the Windows Explorer process. If it is not invoking the IDropTarget object inside of your process, it means the call is being blocked outside of your process, most likely by UAC/UIPI if your app is running elevated. Per the comments on your StackOverflow question on this topic:
  18. Remy Lebeau

    Old Window border style on Delphi MDI child form

    It is a underlying Windows issue. Microsoft simply doesn't render MDI windows using modern styles or high DPI support (ie, MDI does not operate under DWM). That is why Embarcadero finally decided to revamp their MDI system in the VCL in Delphi 12: https://docwiki.embarcadero.com/RADStudio/Athens/en/What's_New#MDI_Reworked_for_HighDPI_and_Styles Not on-hand, but I've seen MS employees verify the issue. I also found this tidbit, take it with a grain of salt: https://www.akadia.com/services/dotnet_software_design.html#The MDI (Multiple Document Interface) Approach Nobody ever claimed that .NET would replace COM. GDI+ augments GDI, but does not replace GDI. It is a well-known fact that after XP, MDI has been left behind in visual handling. MS simply never bothered to update MDI for modern systems. Feels like deprecation to me.
  19. Remy Lebeau

    TShellExecuteInfoA/W incorrectly translated?

    Technically, no. The layout is fine. But, if they had done the "politically correct" thing by extracting the union into a separate type, eg: _SHELLEXECUTEINFOW_Union = record case Integer of 0: (hIcon: THandle); 1: (hMonitor: THandle); end; _SHELLEXECUTEINFOW = record cbSize: DWORD; fMask: ULONG; Wnd: HWND; lpVerb: LPCWSTR; lpFile: LPCWSTR; lpParameters: LPCWSTR; lpDirectory: LPCWSTR; nShow: Integer; hInstApp: HINST; { Optional fields } lpIDList: Pointer; lpClass: LPCWSTR; hkeyClass: HKEY; dwHotKey: DWORD; u: _SHELLEXECUTEINFOW_Union; // DUMMYUNIONNAME maps to 'u' for C/C++ hProcess: THandle; // compilers that don't support nameless unions... end; Then referencing the hIcon and hMonitor handles would have to be done as SHELLEXECUTEINFO.u.hIcon instead of as SHELLEXECUTEINFO.hIcon, etc. The variant part keeps the syntax a little cleaner.
  20. Remy Lebeau

    Drag Drop via Ole

    The Form's OnCreate event is not the best place to register the drop target. If your Form's window is ever recreated at runtime, you will lose your registration. Instead, override the Form's virtual CreateWnd() method and do the registration there instead.
  21. Remy Lebeau

    D12 TItemClickEvent undeclared identifier

    It should not be undeclared. It is a public sub-type of TCustomListBox. The following is taken from FMX.ListBox.pas: TCustomListBox = class(...) ... public type ... TItemClickEvent = procedure(const Sender: TCustomListBox; const Item: TListBoxItem) of object; ... strict private ... FOnItemClick: TItemClickEvent; ... public ... property OnItemClick: TItemClickEvent read FOnItemClick write FOnItemClick; end; The following works fine for me in D12.2: uses ..., FMX.ListBox; procedure TForm1.Button1Click(Sender: TObject); var OnClickHandler: TCustomListBox.TItemClickEvent; begin OnClickHandler := ListBox1.OnItemClick; ListBox1.OnItemClick := nil; // ... ListBox1.OnItemClick := OnClickHandler; end; You could also use an inline variable and let the compiler deduce the type: uses ..., FMX.ListBox; procedure TForm1.Button1Click(Sender: TObject); begin var OnClickHandler := ListBox1.OnItemClick; ListBox1.OnItemClick := nil; // ... ListBox1.OnItemClick := OnClickHandler; end;
  22. In order to use a loop correctly in the OnExecute event, you must call ProcessRequests() with WaitForMessage=false. Using WaitForMessage=true, ProcessRequests() will not return until the service is stopped, and the stop will set Terminated=true, thus making such a loop useless. If you want to prevent the service from being stopped at all while the TProcess is busy, then you can do one of the following: when starting the TProcess, set the service's AllowStop property to false and call the ReportStatus() to update the SCM, and then once the TProcess has finished you can set AllowStop back to true and call ReportStatus() again. leave AllowStop set to true, and have the OnStop event return Stopped=false (and set the service's Win32ErrCode or ErrCode property accordingly) if the TProcess is currently busy. On the other hand, if you want the service to stop normally but wait for the TProcess to finish, then you can handle that in the OnStop event. The service's Status is already csStopPending when the OnStop event is entered. Simply run a loop inside of the OnStop event to call ReportStatus() at regular intervals (not exceeding the WaitHint property) while the TProcess is busy so the SCM knows the service is not frozen. Once the TProcess has finished, then OnStop can return Stopped=true, which will update the SCM with a status of csStopped. As I explained earlier, the OnExecute code you have shown is basically useless and should be eliminated completely. I would not use that approach. The init code should be in the OnStart event. The termination code should be in OnStop event. The OnExecute event should be eliminated whenever possible. Yes, and yes. Yes. For example: void __fastcall TService1::ServiceStart(TObject *Sender, bool &Started) { TProcess->Enabled = true; log1.Log(L"Service started"); Started = true; } void __fastcall TService1::ServiceStop(TObject *Sender, bool &Stopped) { while (TProcess->Enabled) { Sleep(WaitHint-100); ReportStatus(); } log1.Log(L"Service STOPPED"); Stopped = true; } void __fastcall TService1::TProcessTimer(TObject *Sender) { ... if (some condition) { TProcess->Enabled = false; if (Status != csStopPending) ServiceController(SERVICE_CONTROL_STOP); } ... } One thing to keep in mind - you keep saying the TProcess is a "timer method". If you mean a TTimer, then such a loop in the OnStop event would block the timer from firing any further OnTimer events, unless you manually pump the service thread's message queue to dispatch WM_TIMER messages. You would have had to do that anyway in the OnExecute event, if you start the timer in the context of the service thread. Personally, I never do any work in the service thread directly. I always have the OnStart event create a worker thread, and then have the OnStop event terminate the worker thread and wait on it. If I need to do things at regular intervals, I have the worker thread use a Waitable Timer Object or Waitable Event Object in a loop.
  23. Remy Lebeau

    Class TSpinEdit not found

    Your project was likely missing the relevant package references. Recreating the components updated the project.
  24. Remy Lebeau

    Class TSpinEdit not found

    Is TSpinEdit present on the Component Palette? Is the "Embarcadero Sample Components" package ($(BDS)\bin\dclsmp280.bpl) installed in the IDE in the "Component | Install Packages..." dialog? That is the correct unit.
  25. That is because you are calling ProcessRequests() with the WaitForMessage parameter set to true. Not only is that blocking your while loop until a new SCM request arrives, but it also runs an internal loop that will not exit until a SERVICE_CONTROL_STOP request is received. ProcessRequests() will call Terminate() when processing a SERVICE_CONTROL_STOP request. So, your while loop will run AT MOST 1 iteration when using WaitForMessage=true. If you need to call ProcessRequests() yourself and be able to do other things in between calls (ie your Sleep(), etc) then you must call it with WaitForMessage=false instead, so it will exit immediately if there is no SCM request pending. Correct, because you are satisfying the condition that ProcessRequests() is waiting for. See above for why that approach will not work as you are expecting.
×