Undeclared identifier: 'TStatusWindowHandle' when creating waiting form - delphi

i want to show wait form in my app. but when i want to run i have an error :
procedure TForm1.Button1Click(Sender: TObject);
var
status: TStatusWindowHandle;
begin
status := CreateStatusWindow('Please Wait...');
try
Sleep(2000);
finally
RemoveStatusWindow(status);
end;
end;
[Error] Unit1.pas(27): Undeclared identifier: 'TStatusWindowHandle'

The CreateStatusWindow() function is taken from the answer by #AndreasRejbrant here: What's the easiest way to write a please wait screen with Delphi?.
The TStatusWindowHandle declaration is:
TStatusWindowHandle = type HWND;
The linked answer suggests putting the CreateStatusWindow function including the type declaration into a separate unit. And then include the unit into the uses clause.
This is what should have been done here as well to avoid the compiler error.

Related

Test in DUnitx with Delphi-Mocks passing private record

I am new to DUnitx and Delphi-Mocks so please be patient. The only other post I could find on this topic was 3 years old and not answered. Returning records in Delphi-Mocks
Delphi Rio 10.3.
Windows 10
I want to test this procedure:
procedure TdmMariaDBConnection.Notify;
var
LViewModel : IPsViewModel;
begin
FMainViewModel.HandleCommands(FCommandRecord);
for LViewModel in FObservers do
LViewModel.HandleCommands(FCommandRecord);
end;
The interfaces and record type are declared as:
IPsView = interface(IInvokable)
['{F5532762-09F8-42C4-9F9F-A8F7FF7FA0C6}']
procedure HandleCommands(const Value: TPsCommandRecord);
procedure AfterCreate;
procedure BeforeDestroy;
end;
IPsViewModel = interface(IInvokable)
['{322DAB08-6A7C-4B61-B656-BC5346ACFC14}']
procedure HandleCommands(const Value: TPsCommandRecord);
end;
IPsMainViewModel = interface(IInvokable)
['{98FFB416-6C22-492F-BC85-D9A1ECA667FE}']
procedure Attach(const observer: IPsView);
procedure Notify;
procedure LoadFrame(const Value: TPanel);
procedure LoadForm(const Value: integer);
procedure LoadModalForm(const Value: integer);
procedure HandleCommands(const Value: TPsCommandRecord);
procedure SetViewFactory(Value: IPsViewFactory);
property ViewFactory: IPsViewFactory write SetViewFactory;
end;
TPsCommandRecord = record
CommandType: integer;
CommandObject: TObject;
CommandMessage: TPsTaskDialogMessageRecord;
end;
I have the Notify procedure in the protected section
type
TdmMariaDBConnection = class(TDataModule, IPsModel)
procedure DataModuleDestroy(Sender: TObject);
procedure DataModuleCreate(Sender: TObject);
private
FObservers : TList<IPsViewModel>;
FMainViewModel : IPsMainViewModel;
FCommandRecord : TPsCommandRecord;
protected
procedure Notify;
….
end;
In my test project I have a descendent class
TTestabledmMariaDBConnection = class(TdmMariaDBConnection)
end;
var
CUT : TTestabledmMariaDBConnection;
procedure TTestModel_MariaDBConnection.Setup;
begin
CUT := TTestabledmMariaDBConnection.Create(nil);
end;
so I can call protected methods. What I have so far that doesn't work because I cannot provide the private record instance from TdmMariaDBConnection, and just focusing on the MainViewModel for now.
procedure TTestModel_MariaDBConnection.NotifyCallsMainViewModelHandleCommands;
var
MVMMock : TMock<IPsMainViewModel>;
LCommandRecord : TPsCommandRecord;
begin
//Arrange
MVMMock := TMock<IPsMainViewModel>.Create;
MVMMock.Setup.Expect.Once.When.HandleCommands(LCommandRecord);
//Act
CUT.Attach(MVMMock);
CUT.Notify;
//Assert
try
MVMMock.Verify();
Assert.Pass();
except on E: EMockException do
Assert.Fail(E.Message);
end;
end;
Obviously the addition of LCommandRecord are wrong I just added them to get it to compile. I need(I think) the record instance from The test class in the setup. I tried adding a function to get that but it didn't work either.
function TdmMariaDBConnection.GetCommandRecord: TPsCommandRecord;
begin
Result := FCommandRecord;
end;
MVMMock.Setup.Expect.Once.When.HandleCommands(CUT.GetCommandRecord);
The test doesn't even complete, I get an incomplete circle in TestInsight GUI instead of the hoped for Green check.
Any help would be appreciated. Also is this the right use of Verify? I can only find the explanation that it does nothing when passing, so how to add an Assert?
Thanks in advance
Gary
The way you setup the mock it will be very strict about the parameters being passed and checks for equality to the specified setup when calling Verify.
There is also a long standing issue in Delphi Mocks that record parameters are not properly compared for equality (they only equal if the parameters where the exact same address - see SameValue in Delphi.Mocks.Helpers.pas - I know of this issue because it is my code being used with my permission - I wrote a better version some while ago being used in Spring4D which also has mocking fwiw). This is why even if it would not run in a circle with your added GetCommandRecord it might not pass.
What I usually suggest people to do (I wrote 2 mocking libraries for Delphi so far) when using mocks is to be as permissive as possible. Fortunately Delphi Mocks supports parameter matcher that let you specify that actually you don't care that much for the exact value of the parameter being passed.
That being said simply change your setup to call
MVMMock.Setup.Expect.Once.When.HandleCommands(It0.IsAny<TPsCommandRecord>);
That tells the internal matcher recording calls to the mock from the SUT that it does not matter what value comes in which satisfies the expectation.
By the way for a similar reason as with the SameValue bug it will not work using It0.IsEqualTo(LCommandRecord) because the used comparer for records internally calls System.Generics.Defaults.Equals_Binary which just does a flat memory compare of the record which possibly fails for any reference type.

How to get unit path in runtime with Delphi?

I assume that it is possible to get the complete path of the unit (not just the name) at runtime, since when I generate an error, Delphi already has this stored information:
try
Assert (False, '#');
except
on E: EAssertionFailed from
begin
   ShowMessage (E.Message); // this show me the path
end;
end;
Would anyone know if there is any function that returns me the path of a specific unit, or something similar?
The complete path of the unit as it was on the machine that compiled the project is only possible using Assert. However personally I don't find that information incredibly useful unless you have many units with the same name in different folders or lost control over your source repository and and library paths in effect when compiling.
To get the unit name you can turn on map file or debug information (aka TD32) and do the following:
Use the FileByLevel function from JclDebug - in your case with the default value (0).
The level parameter tells the function how many calls it look up the callstack. If you put that method into a FormCreate of a VCL form for example and pass 1 it will give you Vcl.Forms.pas as the event handler was called from there.
I hesitate to write this answer as it shows a really dirty hack to get the unit name making use of the Assert compiler magic shown above.
Use the following unit:
unit UnitNameHack;
interface
const
cUnitNameSentinel = '$$$sentinel$$$';
var
HackUnitname: string = '';
implementation
var
OrgAssertErrorProc: TAssertErrorProc = nil;
procedure MyAssertErrorProc(const Message, Filename: string; LineNumber: Integer; ErrorAddr: Pointer);
begin
if Message = cUnitNameSentinel then begin
HackUnitname:= Filename;
end
else begin
OrgAssertErrorProc(Message, Filename, LineNumber, ErrorAddr);
end;
end;
initialization
OrgAssertErrorProc := AssertErrorProc;
AssertErrorProc := MyAssertErrorProc;
finalization
AssertErrorProc := OrgAssertErrorProc;
end.
Now whenever you need the unit name call
Assert(False, cUnitNameSentinel);
and retrieve the unit name from HackUnitname.
Note that you cannot wrap the Assert call and reading HackUnitName into a function, not even if inlined.
You've said, something similar. I see that it might have been in a different context, but anyway, for objects you can inspect UnitName or UnitScope to get the name of the module where the object instance was declared, without the module path (which is not valuable information anyway).
Based on Uwe Raabe's answer:
// directly after the implementation uses:
var
ThisUnit: string = '<unknown>';
procedure MyAssertErrorProc(const Message, Filename: string; LineNumber: Integer; ErrorAddr: Pointer);
begin
ThisUnit := Filename;
end;
procedure InitThisUnit;
var
OrgAssertErrorProc: TAssertErrorProc;
begin
OrgAssertErrorProc := AssertErrorProc;
try
AssertErrorProc := MyAssertErrorProc;
Assert(False);
finally
AssertErrorProc := OrgAssertErrorProc;
end;
end;
// [...]
// call InitThisUnit in the initialization section
initialization
InitThisUnit;
end.
It's still a hack, but a bit more elegant. ;-)

Converting TStack code from Delphi to Lazarus

In Delphi I have the following code, and all works well:
var
StackOptions:TStack<String>;
s:string;
bfisio:boolean;
begin
StackOptions:=TStack<String>.Create;
//some pushs here
for s in StackOptions do begin
dosomething;
end;
end;
In Lazarus I can do this:
uses
..., gstack;
type
TStringStack = specialize TStack<String>;
var
StackOptions: TStringStack;
s:string;
begin
//But this code doesn;t compile
StackOptions := TStringStack.Create;
//some pushs here
for s in StackOptions do begin // <-- Error
dosomething;
end;
end;
I get the next error in Lazarus:
Compile Project, Target: TicketLaz.exe: Exit code 1, Errors: 1
umain.pas(263,12) Error: Cannot find an enumerator for the type "TStack$1$crcAC3AF268"
How could I loop the Stack and search for a value with Lazarus without removing items from Stack?
FPC's stack is backed by a TVector.
The TVector has an enumerator.
You can easily add a class helper like so:
Quick and dirty code.
type
TStringStack = specialize TStack<String>;
type
{ TStackHelper }
TVectorEnumerator = specialize TVector<string>.TVectorEnumerator;
TStackHelper = class helper for TStringStack
function GetEnumerator: TVectorEnumerator;
end;
{ TStackHelper }
function TStackHelper.GetEnumerator: TVectorEnumerator;
begin
Result:= FData.GetEnumerator;
end;
I really don't see why a stack is not supposed to have an iterator.
Even in assembly you can simply do mov reg,[esp-04].
This puritanical approach to data-structures helps no-one
All this is complicated by the fact that TStack is generic.
I know FPC allows generic class helpers, but I'm not sure how to make the solution work for all TStack<T>
Another approach would be to simply edit gstack.pas to expose the iterator.

Access Violation error using IInterfaceList Delphi XE3

I have encountered an access violation error [Access violation at address 5005F6E in module 'rtl170'. Read of address 0000000A] using the IInterfaceList.
My code looks something like this:
if not Assigned(FoRoutingCodes) then Exit;
for i := 0 to FoRoutingCodes.nCount - 1 do
begin
...
end;
the declaration of FoRoutingCodes is:
FoRoutingCodes : IRoutingCodeList;
and the definition of IRoutingCodeList
IRoutingCodeList = interface
function GetCount: Integer;
...
property nCount: Integer read GetCount;
end;
the implementation of nCount property is:
function TRoutingCodeList.GetCount: Integer;
begin
Result := 0;
if Assigned(FoItems) then
Result := FoItems.Count; // here i get the access violation error
end;
where TRoutingCodeList is the implementation of IRoutingCodeList and FoItems is declared as:
FoItems: IInterfaceList;
I have fixed this using
FoItems: TList<IRoutingCode>;
instead of
FoItems: IInterfaceList;
I am new to delphi, can anyone help me understand what was wrong with previous approach.
I don't know if this is relevant because there are many other changes is our product, but this issue appeared only after we moved from Delphi XE to Delphi XE3.
Thanks in advance.
Update: in response to Uwe Raabe
I have changed FoItems initialisation from
constructor TRoutingCodeList.Create;
begin
FoItems := TInterfaceList.Create;
end;
to
constructor TRoutingCodeList.Create;
begin
FoItems := TList<IRoutingCode>.Create;
end;
Considering only the code you posted so far, I can´t see the problem. However, since you know the exact location of the error, my advice is to set a breakpoint at that line in code and evaluate (CTRL+F7) the member FoItems to see what is it.
Usually, when I suspect I have a bad object reference, I evalute it´s ClassName (in your case, FoItems.ClassName). If the reference is invalid, this method usually raises an exception of returns a strange name.
Also, set a breakpoint in the constructor in order to be sure that FoItems is indeed being instantiated.
I Hope this helps!

Why does the compiler say "Too many actual parameters" when I think I've provided the correct number?

I've declared the following function:
function next(current, next: string): Integer;
begin
form1.Label1.Caption := next;
form1.Label2.Caption := current;
form1.label3.Caption := clipboard.AsText+inttostr(c);
Result:=1;
end;
I try to execute it with this code:
if label1.Caption = '' then res := next('current', 'next');
I am getting the following error:
[Error] Unit1.pas(47): E2034 Too many
actual parameters
I think all parameters are good, so why am I getting that error?
I just tried your code on both Delphi 7 and Delphi 2010. If it works on those two, it should also work on Delphi 2005.
Conclusion: Delphi wants to use a different version of the "next" routine, because of code scope/visibility. Try ctrl+click-ing on "next" in "res := next();" and see where Delphi takes you. Alternatively post more code so we can tell you why Delphi is not choosing your version of the "next" routine. Ideally you should post a whole unit, starting from "unit name" to the final "end."
As specified by Cosmin Prund, the problem is because of the visibility.
TForm has a procedure with name Next which wont accept any parameters.
Your function uses the same name and as you are calling the function in TForm1 class implementation, compiler is treating the call as TForm1.Next and hence it was giving error.
To solve the problem, precede the unit name before the function name i.e., Unit1.Next().
So this should be your code
if label1.Caption = '' then res := Unit1.next('current', 'next');

Resources