Readkey in Pascal (Unknown Identifier) - pascal

I am learning how to use the graphic mode from Pascal (Using Turbo Pascal 5.5). This is a simple code, which shows me the graphic mode with some messages:
program GraficoPri
uses Graph;
var Driver, Modo : Integer;
begin
Driver := VGA;
Modo := VGAHi;
InitGraph(Driver,Modo,'P:BGI');
{Using DOSBox, P: is a mounted drive I created where all TP files are stored}
SetTextStyle(SansSerifFont,0,2);
SetColor(Red);
OutTextXY(120,60,'Welcome to graphic mode');
Writeln('Push any button to continue'};
Readkey;
CloseGraph;
End.
Well, the problem I'm having is that "Readkey;" is giving me a 'Unknown Identifier' error. I tried changing the line with "Readln;" and it worked fine. What is the problem here?
Thank you!

Readkey is from the crt library, so you need to change
uses graph
to
uses wincrt, graph
Also, readkey is always used as a variable declaration. For example,
ch := readkey;
If you just want to push a button to continue, you should use a repeat-until keypressed loop.
repeat
until keypressed;
This will wait and do nothing until the user presses a key.

Related

VCL/LCL – a form in DLL – no Application taskbar window, cannot minimize the main form

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!

Firemonkey OS X - Request elevated permissions

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;

Delphi XE8 Printe VCL and DocumentProperties strange issue

I'm using the vcl.printers unit (delphi XE8) and I'm facing an error when "talking" to a printer.
I traced into the vcl.printers and found this code (written by EMB people):
if OpenPrinter(ADevice, FPrinterHandle, nil) then
begin
if DeviceMode = 0 then // alloc new device mode block if one was not passed in
begin
DeviceMode := GlobalAlloc(GHND,
DocumentProperties(0, FPrinterHandle, ADevice, nil, nil, 0));
if DeviceMode <> 0 then
begin
DevMode := GlobalLock(DeviceMode);
if DocumentProperties(0, FPrinterHandle, ADevice, DevMode^,
DevMode^, DM_OUT_BUFFER) < 0 then
begin
GlobalUnlock(DeviceMode);
GlobalFree(DeviceMode);
DeviceMode := 0;
DevMode := nil;
end
end;
end;
if DeviceMode <> 0 then
SetPrinterCapabilities(DevMode^.dmFields);
end;
The
DocumentProperties(0, FPrinterHandle, ADevice, nil, nil, 0)
return the correct buffer size the first time (I haven't written it somewhere), then going thru the second execution time it returns 4294967295 bytes, indeed a -1 because declaration is wrong, but meanning an error.
As you can see the VCL code handle the errors very poorly since there is no error check !
But what error I have here and why ?
DocumentProperties lies in winspool.dll
To recover from it, I need to reboot the PC, but I cannot use this more than one time pass that is vey annoying for debug.
The printer is simply the "PDFcreator"
I tried with other PC and seems OK even if I run it many times.
I have also two laser network printers.
Thanks
In the past I did have the same problem with two customers. I did track it down to printers unit (printers.pas) Kind of hard to track it down without debugger on a distant computer in other part of my country.
Ok.. but I did track it all the way down to this line:
DeviceMode := GlobalAlloc(GHND, DocumentProperties (0, FPrinterHandle, ADevice, StubDevMode, StubDevMode, 0)); in the function SetPrinter in the unit PRINTERS.PAS
When I did broke it up into two lines, i.e. call to DocumentProperties first and store the value in integer variable and then check the value and only then call Globalalloc if the value is greater than 0 and kind of debugged it with stored values in debug file the error was truly in the DocumentProperties function from SPOOL.DLL if I remember correctly. This function returned -1 as size for the device, but only with this customer on one computer (he is using 4 or 5 with my program)
Of all my customers (close to 200 clients) I have had this issue on two computers. The other one fixed it kind of itself.. I didn't know how it did get fixed. The later one I was trying to fix just a couple of minutes ago. In the end I found a solution. I did fix this customer with simple change of shortcut. I began to use the automatic fix for compatibility in Windows 10 and then ran the button "test program" and it worked.. No error choosing printers or using it's propertis. Ok.. Then I tried again with the shortcut alone.. aarrgg.. error returned.. but then, aha.. I thought to myself "this has to connects to how Windows is running this program" and changed how Windows 10 ran the program as check "run as administrator" to uncheck.
And no problem.
On almost every compture with Windows 10 I do check "Run as Administrator" with no problems. I think there was a update or some issues with spool.dll that connects these dots.
ps. If you google this behavior with Delphi DocumentProperties problems, then you will find out this is known problem.. some say connected to x86 and x64 mode, but I found this out.

Communication with two application on Windows with DELPHI

I have two applications and would like the two to communicate texting when a release exception.
The problem is as follows:
in an application I use the function
Application.Handle
to grab the handle of the application.
And in my client I use:
ServerApplicationHandle: = FindWindow ('TForm1', 'Form1');
To know which application should I send the message, but both return different numbers, they would know tell me why?
As already explained (Main)Form and Application are two different things.
Since Delphi 2007 there is another behavior to note.
In dependency of Application.MainformOnTaskbar you are able (or not) to get the handle via Findwindow.
A little snipplet to show the different behavior
var
FW_ah, FW_mfh, ah, mfh: THandle;
Procedure Display(OnTask: Boolean);
begin
Application.MainFormOnTaskbar := OnTask;
ah := Application.Handle;
mfh := MainForm.Handle;
FW_ah := FindWindow(PChar(Application.ClassName), PChar(Application.Title));
FW_mfh := FindWindow(PChar(ClassName), PChar(Caption));
Showmessage(Format('ah: %d FW_ah: %d - mfh: %d FW_mfh: %d', [ah, FW_ah, mfh, FW_mfh]));
end;
begin
Display(true);
Display(false);
end;
Application.Handle is the window handle for the hidden window associated with the global Application object.
FindWindow('TForm1', 'Form1') will return the window handle of a top-level form in your application.
These are indeed not the same thing. You could, I suppose, use Form1.Handle instead of Application.Handle. However, you would need to be wary of window re-creation.
Frankly this doesn't sound like the best way to do inter-process communication. Perhaps you might consider sockets or named pipes.

SCardEstablishContext hangs as a service

Why might SCardEstablishContext hang, never to return, when called from a service?
I have code that works fine on lots of Windows installations. It accesses a Cherry keyboard's Smart Card reader (6x44) to read data on a smart card. It works fine on most PCs it has been tried on. However, on some PCs, running in Spain with Spanish Windows, the SCardEstablishContext function never returns. I cannot work out why this might be. I have logging either side of it, but the log entry after it does not appear. I cannot then shut it down (the worker thread is getting stuck), and have to kill it.
Exactly the same thread code works fine if run from an application, and not a service. Giving the service login settings of a user instead of system makes no difference.
I've installed Spanish XP on a machine here, but it works just fine. The far end has the same Winscard.dll version as I have here (both at XP SP3 status). No errors are shown in the event log.
How might I work out what is going wrong, and what might be fixing it? (Delphi code below)
// based on code by Norbert Huettisch
function TPCSCConnector.Init: boolean;
var
RetVar: LongInt;
ReaderList: string;
ReaderListSize: integer;
v: array[0..MAXIMUM_SMARTCARD_READERS] of string;
i: integer;
begin
Result := false;
FNumReaders := 0;
{$IFDEF MJ_ONLY}
LogReport(leInformation, 'About to call SCardEstablishContext');
{$ENDIF}
RetVar := SCardEstablishContext(SCARD_SCOPE_USER, nil, nil, #FContext);
{$IFDEF MJ_ONLY}
// never gets to report this (and logging known good etc)
LogReport(leInformation, 'SCardEstablishContext result = ' + IntToStr(RetVar));
{$ENDIF}
if RetVar = SCARD_S_SUCCESS then
begin
There may be different reasons why the API function appears to hang, like a deadlock, or an invisible message box or dialog waiting for user input. You should try to get a stacktrace using WinDbg.
You should also make sure that you are trying to reproduce the bug in the same environment. Important points might be whether Fast User Switching is active and whether other users are logged on, also that there are the same device drivers and services running.

Resources