-
Content Count
2684 -
Joined
-
Last visited
-
Days Won
113
Everything posted by Remy Lebeau
-
Does the main form's OnShow event only ever fire once?
Remy Lebeau replied to Gord P's topic in General Help
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). -
Service monitoring other services activities
Remy Lebeau replied to Clément's topic in Algorithms, Data Structures and Class Design
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). -
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."
-
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.
-
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
-
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;
-
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.
-
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.
-
inline var and type deduction with Currency type
Remy Lebeau replied to Rustam Novikov's topic in RTL and Delphi Object Pascal
Sounds like a bug to me. Report it to Embarcadero: https://qp.embarcadero.com -
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 replies
-
- rad studio c++ builder
- custom components
-
(and 1 more)
Tagged with:
-
DataSnap Could not convert variant of type (Array Byte) into type (Integer)
Remy Lebeau replied to dlucic's topic in Network, Cloud and Web
You are not resetting ms.Position=0 before calling Param.LoadFromStream(). You are also leaking the TMemoryStream. -
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?
- 11 replies
-
- rad studio c++ builder
- custom components
-
(and 1 more)
Tagged with:
-
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.
-
https://docwiki.embarcadero.com/RADStudio/Athens/en/What's_New#Disabling_Floating-Point_Exceptions_on_All_Platforms
-
Reconnect TSQLConnection after lost wifi signal
Remy Lebeau replied to dlucic's topic in Network, Cloud and Web
I see only a single retry in that code. Have you tried reconnecting multiple times, perhaps with a small delay in between each attempt? -
Reconnect TSQLConnection after lost wifi signal
Remy Lebeau replied to dlucic's topic in Network, Cloud and Web
Why not simply catch the socket error and retry the failed operation? -
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:
-
Old Window border style on Delphi MDI child form
Remy Lebeau replied to Clayton A. Alves's topic in VCL
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. -
TShellExecuteInfoA/W incorrectly translated?
Remy Lebeau replied to Nigel Thomas's topic in Windows API
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. -
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.
-
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;
-
Can a windows service terminate/stop itself? If so, how?
Remy Lebeau replied to alank2's topic in General Help
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. -
Your project was likely missing the relevant package references. Recreating the components updated the project.
-
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.
-
Can a windows service terminate/stop itself? If so, how?
Remy Lebeau replied to alank2's topic in General Help
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.