I'm rewriting an app for OS X (which is running in a VirtualBox). When I compile all my objects are released. I'm a novice programmer and this is my first mac app, so I'm not even completely sure this is the problem.
I have installed RAD PAServer to OS X. In this terminal I get the following error messages:
__NSAutoreleaseNoPool(): Object 0x4237a10 of class NSPathStore2 autoreleased with no pool in place - just leaking
__NSAutoreleaseNoPool(): Object 0x664dc3c of class NSCFString autoreleased with no pool in place - just leaking
These are just 2 examples of a large variety or error messages, which all start with __NSAutoreleaseNoPool().
RAD Studio XE-5 doesn't give any error messages when compiling to OS X or a Win32 target platform.
I hope to have informed you sufficiently.
Update:
I have added a TCalendarEdit to my form. When I click on it in OS X, the program crashes and I get the following runtime error message in the PAServer terminal:
malloc: *** error for object 0x127e99d4: incorrect checksum for freed object - object was probably modified after being freed.
Update 2:
It seems not every object is released. This code works:
procedure TForm4.Button1Click(Sender: TObject);
begin
label1.Text := 'bladibla';
end;
And when I recreate TCalendarEdit functionality this way, all is fine:
var
CalendarButton: TButton;
procedure TForm4.Button7Click(Sender: TObject);
begin
Calendar1.Visible := true;
Calendar1.Position.X := Button7.Position.X;
CalendarButton := Button7;
end;
procedure TForm4.Calendar1DateSelected(Sender: TObject);
begin
if CalendarButton = Button6 then
Button6.Text := DateToStr(Calendar1.Date);
if CalendarButton = Button7 then
Button7.Text := DateToStr(Calendar1.Date);
Calendar1.Visible := false;
end;
Related
I have one problem, and I tried to search a solution but can't achieve what I want. Sorry if that is actually simple, please just point me to correct way of how to do it.
So! I have a C program that is a loader. It must call my DLL written in Delphi or Lazarus (Free Pascal). The DLL is actually a standalone GUI application: during debugging I conditionally compile it as EXE and it working.
My build script compiles it as DLL with one entry point that must execute it just as it works standalone. I expect exactly the same behavior, but I can do some things different (especially setting the Application icon) if needed.
Loader is a console-style program but compiled without a console – no windows, no anything. It just loads DLL and calls a function.
Problem is that when I build even empty default project with one form as an EXE – it will actually have "master" Application (.Handle <> 0) window in taskbar. So I can set its title independently from main form caption.
But when the same thing is inside a DLL – there is no Application window (.Handle = 0), the title will be the form caption, but the most important bug: a form cannot be minimized!
In Delphi 7 it goes background under other windows (but taskbar thing stays!); in Lazarus it just minimizes to nowhere (hided, no way to restore anymore); both without any minimizing animation.
Other than that, my application seems to behave normally. This is only issue I have.
OK, I know that forms in libraries is a bad thing to do, but:
I’m fine to instantiate "another" VCL completely independent from host’s instance, maybe even in different thread.
There is no VCL in my particular host application! For me, it must work exactly as it will in EXE alone…
I searched something about Application.Handle in DLL, and now understand than I need to pass a handle to host’s Application object, so DLL will be joined with others host forms, but I have none! It’s even not Delphi… (and Application:=TApplication.Create(nil); didn’t help either)
Anything of following will probably help me:
A) How to instruct VCL to create a normal Application object for me? How it does it when in EXE, maybe I can copy that code?
B) How to create a suitable master window from C (proper styles, etc.) to pass it’s handle to DLL? Also, I believe, in Free Pascal there is no direct access to TApplication handle value, so I couldn’t probably assign it.
C) How to live without a taskbar window, but have my form (good news: my program has only one form!) to minimize correctly (or just somehow…)?
I now you all love to see some code, so here it is:
// default empty project code, produces valid working EXE:
program Project1;
uses Forms, Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
+
// that's how I tried to put it in a DLL:
library Project1;
uses Forms, Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
function entry(a, b, c, d: Integer): Integer; stdcall;
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
Result := 0;
end;
exports
entry;
begin
end.
I specially crafted entry() function to be callable with rundll32, just for testing.
Also, I tried to put the body directly to "begin end." initialization section – same wrong behavior.
// To call a DLL, this can be used:
program Project1;
function entry(a, b, c, d: Integer): Integer; stdcall; external 'Project1.dll';
begin
entry(0, 0, 0, 0);
end.
Also, CMD-command "rundll32 project1.dll entry" will run it instantly. (Yeah, that way I might get a handle that Rundll gives me, but it isn’t what I want anyway.)
Last notes: (a) the DLL must be compiled in Lazarus; actually first thing I thought that it is a bug in LCL, but now when tested in Delphi7 I see the same; and since Delphi case is more simpler and robust, I decided to put here that; (b) my C loader doesn’t call LoadLibrary, it uses TFakeDLL hack (that OBJ file was tweaked to work without Delphi wrapper) and loads my DLL from memory (so I don’t have a handle to DLL itself), but otherwise their behavior is the same.
Okay, thanks to #Sertac Akyuz, I tried with .ShowModal:
// working Delphi solution:
library Project1;
uses Forms, Dialogs, SysUtils, Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
function entry(a, b, c, d: Integer): Integer; stdcall;
begin
Result := 0;
Application.Initialize;
Form1 := TForm1.Create(nil);
try
Form1.ShowModal;
except
on e: Exception do
ShowMessage(e.message);
end;
Form1.Free;
end;
exports
entry;
begin
end.
There is still no Application window (taskbar title equal to form caption), but now my form can be successfully minimized (with system animation). Note that for EXE compilation I have to go default way with Application, because when I tried to create the form like this – it started to minimize to desktop (iconify) instead of the taskbar.
It works perfect in empty default Lazarus project too. But when I tried to implement it to my production program, it gave me "Disk Full" exception at .ShowModal!
That thing was frustrating me little earlier (and that’s why I got rid of modality altogether, tried it no more), but now I was determined enough to get the bottom of this.
And I found the problem! My build script doesn’t pass "-WG" ("Specify graphic type application") compiler option. Looks like something in LCL was using console-alike mode, and modality loop failed for some reason.
Then, I had another very confusing issue that I want to share. My form’s OnCreate was rather big and complex (even starting other threads), and some internal function give me access violation when tried to do some stuff with one of controls on the form. It looked like the control is not constructed yet, or the form itself…
Turns out that the actual call Form1:=TForm1.Create(nil); obviously will leave the global variable "Form1" unassigned during FormCreate event. The fix was simple: to add Form1:=Self; in the beginning of TForm1.FormCreate(Sender: TObject);
Now everything is working without any problems. I can even use other forms with a normal Form2.Show(); if I firstly add them to my entry() function, like Form2:=TForm2.Create(Form1);
(edit: minor note, if you would use Lazarus and try to run entry() function from any different thread than one that loaded DLL library itself – then you should put MainThreadID:=GetCurrentThreadId(); just above Application.Initialize;)
Yay, this question is solved!
I need to detect Idle Time, Time Since the user has input anything into their machine, I've made this application before for windows only and this function worked brilliantly :-
function IdleTime: DWord;
var
LastInput: TLastInputInfo;
begin
LastInput.cbSize := SizeOf(TLastInputInfo);
GetLastInputInfo(LastInput);
Result := (GetTickCount - LastInput.dwTime) DIV 1000;
end;
However, this function doesn't work on Multi-Device Application(as far as I can tell). I've messed around with this for a while now and done some severe googling to no avail.
The target OS is OS X and Windows.
The equivalent of GetLastInputInfo on OSX is CGEventSourceCounterForEventType.
See: https://developer.apple.com/library/mac/documentation/Carbon/Reference/QuartzEventServicesRef/index.html#//apple_ref/c/func/CGEventSourceCounterForEventType
See here: Detecting user-activity on mac os x
The API interface for this call is in: Macapi.CoreGraphics
So you'll need to add that unit to your uses clause.
If you're not familair with OSX programming under Delphi, have a look at:https://delphihaven.wordpress.com
I'm developing an OS X Firemonkey application that needs to launch "openvpn", but OpenVPN needs administrator permissions to create the tunnel interface.
I am trying to convert the first sample from this blog post to Delphi:
http://www.michaelvobrien.com/blog/2009/07/authorizationexecutewithprivileges-a-simple-example/
Attempting to run this code, sometimes results in the authorisation prompt as expected, but clicking OK completely freezes the debugger and whole system needs to be powered off. It works better running without the debugger, but still sometimes will freeze...
I've caught the return code before it crashes a couple of times, and it was errAuthorizationToolExecuteFailure
I'm not very familiar with how OSX does things, is there a better method? Apple doesn't recommend using AuthorizationExecuteWithPrivileges for this. I don't know of any other way to run openvpn with the permissions it needs.
uses
Macapi.CoreFoundation, Macapi.Foundation, Macapi.Security;
const
kAuthorizationEmptyEnvironment = nil;
procedure TForm1.Button1Click(Sender: TObject);
var
AuthRef: AuthorizationRef;
Status: OSStatus;
begin
Status := AuthorizationCreate(nil,kAuthorizationEmptyEnvironment,kAuthorizationFlagDefaults,#AuthRef);
Status := AuthorizationExecuteWithPrivileges(AuthRef,'/sbin/dmesg',0,'',nil)
end;
The arguments parameter of AuthorizationExecuteWithPrivileges expects a pointer to an array of PAnsiChars that is terminated with a nil pointer as the last array item. You are simply passing a pointer to an empty string. That is going to give you random crashes depending on what happens to be in memory after the pointer to the empty string.
Try this:
procedure TForm1.Button1Click(Sender: TObject);
var
AuthRef: AuthorizationRef;
Status: OSStatus;
argv: array[0..0] of PAnsiChar;
begin
ArgV[0] := nil;
AuthRef := nil;
Status := AuthorizationCreate(nil,kAuthorizationEmptyEnvironment,kAuthorizationFlagDefaults,#AuthRef);
Status := AuthorizationExecuteWithPrivileges(AuthRef, '/sbin/dmesg', 0, #argv[0], nil);
AuthorizationFree(AuthRef, kAuthorizationFlagDefaults);
end;
Sorry about kind of vague information about the background of this question, first the actual type library I am working with is subject to a non disclosure agreement, second I do not have direct access to the system where the problem is happening.
I have something like the following TLB for the COM interface of a device I am talking to in Free Pascal:
Device = interface(IDispatch)
// ...
function GetSubsystem: Subsystem; safecall;
property Subsystem: Subsystem read GetSubsystem;
// ...
end;
Subsystem = interface(IDispatch)
// ...
function GetSensors: Sensors; safecall;
property Sensors: Sensors read GetSensors;
// ...
end;
Sensors = interface(IDispatch)
// ...
function GetListItem(index: OleVariant): Sensor; safecall;
property ListItem[index: OleVariant]: Sensor read GetListItem; default;
// ...
end;
Sensor = interface(IDispatch)
// ...
function GetValue: Double; safecall;
property Value: Double read GetValue;
// ...
end;
If I read (according to the manufacturer's manual) a value from one of the sensors on Windows XP 32bit as follows
d := MyDevice.Subsystem.Sensors['ID23'].Value;
this works fine.
On Windows 7 64 bit, the manufacturer still has a 32bit COM interface, and all other calls from my 32bit exectuable work fine - just the one above makes my executable crash. It does not even raise an exception, it simply crashes. The same happens with
var o: oleVariant;
// ...
o = 'ID23';
d := MyDevice.Subsystem.Sensors[o].Value;
As I do not have access to said system directly, debugging is quite tedious and it took me a while to isolate the problem to exactly this call.
The interesting thing is that other programming languages using this same COM interface on Win7 64bit do not show this problem.
Does anyone have advice on how to approach this issue under the given circumstances?
I can only give you some pointers to try/be wary of:
FPC 3.0 supports SEH exceptions for 64-bit, but not for 32-bit
FPC seems to have some problem with default properties of dispatch interfaces. Try to use getlistitem() directly.
I'm trying to use SetWindowsHookEx to set up a WH_SHELL hook to get notified of system-wide HSHELL_WINDOWCREATED and HSHELL_WINDOWDESTROYED events. I pass 0 for the final dwThreadId argument which, according to the docs, should "associate the hook procedure with all existing threads running in the same desktop as the calling thread". I also pass in the handle to my DLL (HInstance in Delphi) for the hMod parameter as did all the examples I looked at.
Yet, I only ever get notified of windows created by my own app and - more often than not - my tests result in the desktop process going down in flames once I close down my app. Before you ask, I do call UnhookWindowsHookEx. I also always call CallNextHookEx from within my handler.
I am running my test app from a limited user account but so far I haven't found any hints indicating that this would play a role... (though that actually surprises me)
AFAICT, I did everything by the book (obviously I didn't but so far I fail to see where).
I'm using Delphi (2007) but that shouldn't really matter I think.
EDIT: Maybe I should have mentioned this before: I did download and try a couple of examples (though there are unfortunately not that many available for Delphi - especially none for WH_SHELL or WH_CBT). While they do not crash the system like my test app does, they still do not capture events from other processes (even though I can verify with ProcessExplorer that they get loaded into them alright). So it seems there is either something wrong with my system configuration or the examples are wrong or it is simply not possible to capture events from other processes. Can anyone enlighten me?
EDIT2: OK, here's the source of my test project.
The DLL containing the hook procedure:
library HookHelper;
uses
Windows;
{$R *.res}
type
THookCallback = procedure(ACode, AWParam, ALParam: Integer); stdcall;
var
WndHookCallback: THookCallback;
Hook: HHook;
function HookProc(ACode, AWParam, ALParam: Integer): Integer; stdcall;
begin
Result := CallNextHookEx(Hook, ACode, AWParam, ALParam);
if ACode < 0 then Exit;
try
if Assigned(WndHookCallback)
// and (ACode in [HSHELL_WINDOWCREATED, HSHELL_WINDOWDESTROYED]) then
and (ACode in [HCBT_CREATEWND, HCBT_DESTROYWND]) then
WndHookCallback(ACode, AWParam, ALParam);
except
// plop!
end;
end;
procedure InitHook(ACallback: THookCallback); register;
begin
// Hook := SetWindowsHookEx(WH_SHELL, #HookProc, HInstance, 0);
Hook := SetWindowsHookEx(WH_CBT, #HookProc, HInstance, 0);
if Hook = 0 then
begin
// ShowMessage(SysErrorMessage(GetLastError));
end
else
begin
WndHookCallback := ACallback;
end;
end;
procedure UninitHook; register;
begin
if Hook <> 0 then
UnhookWindowsHookEx(Hook);
WndHookCallback := nil;
end;
exports
InitHook,
UninitHook;
begin
end.
And the main form of the app using the hook:
unit MainFo;
interface
uses
Windows, SysUtils, Forms, Dialogs, Classes, Controls, Buttons, StdCtrls;
type
THookTest_Fo = class(TForm)
Hook_Btn: TSpeedButton;
Output_Lbx: TListBox;
Test_Btn: TButton;
procedure Hook_BtnClick(Sender: TObject);
procedure Test_BtnClick(Sender: TObject);
public
destructor Destroy; override;
end;
var
HookTest_Fo: THookTest_Fo;
implementation
{$R *.dfm}
type
THookCallback = procedure(ACode, AWParam, ALParam: Integer); stdcall;
procedure InitHook(const ACallback: THookCallback); register; external 'HookHelper.dll';
procedure UninitHook; register; external 'HookHelper.dll';
procedure HookCallback(ACode, AWParam, ALParam: Integer); stdcall;
begin
if Assigned(HookTest_Fo) then
case ACode of
// HSHELL_WINDOWCREATED:
HCBT_CREATEWND:
HookTest_Fo.Output_Lbx.Items.Add('created handle #' + IntToStr(AWParam));
// HSHELL_WINDOWDESTROYED:
HCBT_DESTROYWND:
HookTest_Fo.Output_Lbx.Items.Add('destroyed handle #' + IntToStr(AWParam));
else
HookTest_Fo.Output_Lbx.Items.Add(Format('code: %d, WParam: $%x, LParam: $%x', [ACode, AWParam, ALParam]));
end;
end;
procedure THookTest_Fo.Test_BtnClick(Sender: TObject);
begin
ShowMessage('Boo!');
end;
destructor THookTest_Fo.Destroy;
begin
UninitHook; // just to make sure
inherited;
end;
procedure THookTest_Fo.Hook_BtnClick(Sender: TObject);
begin
if Hook_Btn.Down then
InitHook(HookCallback)
else
UninitHook;
end;
end.
The problem is that your hook DLL is actually being loaded into several different address spaces. Any time Windows detects an event in some foreign process that must be processed by your hook, it loads the hook DLL into that process (if it's not already loaded, of course).
However, each process has its own address space. This means that the callback function pointer that you passed in InitHook() only makes sense in the context of your EXE (that's why it works for events in your app). In any other process that pointer is garbage; it may point to an invalid memory location or (worse) into some random code section. The result can either be an access violation or silent memory corruption.
Generally, the solution is to use some sort of interprocess communication (IPC) to properly notify your EXE. The most painless way for your case would be to post a message and cram the needed info (event and HWND) into its WPARAM/LPARAM. You could either use a WM_APP+n or create one with RegisterWindowMessage(). Make sure the message is posted and not sent, to avoid any deadlocks.
This might be tertiary to your question, but as you're seeing, hooks are very hard to get right - if you can avoid using this by any means, do it. You're going to run into all sorts of problems with them, especially on Vista where you'll have to deal with UIPI.
Just to clarify something that "efotinis" mentioned about posting messages back to your process - the wParam and lParam that you post to your main process can't be pointers, they can just be "numbers".
For example, lets say you hook the WM_WINDOWPOSCHANGING message, windows passes you a pointer to a WINDOWPOS in the lparam. You can't just post that lparam back to your main process because the memory the lparam is pointing to is only valid in the process that recieves the message.
This is what "efotinis" meant when he said " cram the needed info (event and HWND) into its WPARAM/LPARAM". If you want to pass more complex messages back your going to need to use some other IPC (like named pipes, TCP or memory mapped files).
Lol, it looks like the error is in the test code.
If you create two separate buttons, one for Init and one for UnInit (I prefer Exit).
procedure THooktest_FO.UnInitClick(Sender: TObject);
begin
UninitHook;
end;
procedure THooktest_FO.InitClick(Sender: TObject);
begin
InitHook(HookCallback)
end;
Start the app. Click Init and then The test button, the following output is shown:
created handle #1902442
destroyed handle #1902442
created handle #1967978
created handle #7276488
Then the messagebox is shown.
If you click ok you get:
destroyed handle #1967978
HTH
I found the Delphi base documentation for SetWindowsHookEx. But the text is a bit vague.
function SetWindowsHookEx(idHook: Integer; lpfn: TFNHookProc;
hmod: HInst; dwThreadId: DWORD): HHOOK;
hmod: A handle to the module (a DLL) containing the hook function pointed to by the lpfn parameter. This parameter must be set to zero if dwThreadId identifies a thread created by the current process an dlpfn points to a hook function located in the code associated with the current process.
dwThreadId: The identifier of the thread to which the installed hook function will be associated. If this parameter is set to zero, the hook will be a system-wide hook that is associated with all existing threads.
By the way, for the hmod parameter you should have used a module handle. (HINSTANCE points to the application handle).
hand := GetModuleHandle('hookhelper.dll');
Hook := SetWindowsHookEx(WH_SHELL, #HookProc, hand, 0);
But although hand differs from HINSTANCE it still shows the same result.