What does a EClassNotFound raised at runtime really mean when the class in question is there at compile and link time, and there explicitly in code? - delphi

I have a runtime error happening in the rtl Streaming in of a form, causing an exception EClassNotFound to be raised, while doing TReader.ReadRootComponent. The particular error message is "Class not found TActionList".
What is odd is:
My main form uses Action list.
For fun, I added ActnList.pas (from the VCL source folder) to my project, to try to fix it.
This happens to me when instantiating a form that I had working until a few minutes ago. The change that I made was in some sub-frame code: I removed all its implementation section code with an ifdef marker, because I am mocking up some frames, for unit testing and prototypes.
I tried adding the action list class to the project, and I tried with and without various compiler and link options, and yet, I still get this exception. Obviously something weird is up. There must be another weird way to get this problem.
In fact, it seems there is something really weird going on. When this error is raised, I get the following call stack:
rtl.Classes.ClassNotFound('TActionList')
rtl.Classes.TReader.FindComponentClass(???)
rtl.Classes.FindExistingComponent
rtl.Classes.TReader.ReadComponent(nil) /// NIL!? WHAT!!!!!
rtl.Classes.TReader.ReadDataInner(???)
rtl.Classes.TReader.ReadData(???)
rtl.Classes.TComponent.ReadState(???)
vcl.Controls.TControl.ReadState(???)
vcl.Controls.TWinControl.ReadState($60B9CF0)
vcl.Forms.TCustomForm.ReadState(???)
rtl.Classes.TReader.ReadRootComponent($606EB90)
rtl.Classes.TStream.ReadComponent($606EB90)
rtl.Classes.InternalReadComponentRes(???,???,$606EB90)
rtl.Classes.InitComponent(TComplexFormContainingFrames)
It seems the nil is intentional, in TReader.ReadDataInner(Instance:TComponent):
while not EndOfList do ReadComponent(nil);
Update: I believe the answer to this question is to understand "serialization contexts" as Mason has mentioned. And, it's time to admit my own Stupidity: I removed the parent of the frame from the project, not realizing it was the parent of the frame. I worked around it being missing by stubbing the type declaration for TMyFrameParent as TMyFrameParent = class(TFrame), and this in turn lead to the condition in question. I am leaving the question here because I think it might be really handy in future to note when this exception occurs in arcane cases, and how to fix it. In particular, Mason has a really interesting bit of information about "serialization contexts" and how they apply to class-name-finding.

It means that the class wasn't found in the current deserialization context. Not all existing classes are registered for all loading. Each form class has RTTI containing references to the components it uses. To get this to work, make sure that your form (or frame, if this is a frame) declares at least one TActionList before the private tag:
TMyForm = class(TForm)
ActionList: TActionList;
OtherComponent: TSomeComponent;
private
//whatever
public
//whatever
end;

Use Classes.RegisterClass to register classes you want to use with the streaming system. Quote from the doc
Form classes and component classes that are referenced in a form declaration (instance variables) are automatically registered. Any other classes used by an application must be explicitly registered by calling RegisterClass if instances are to be saved. Once classes are registered, they can be loaded or saved by the component streaming system.

It seems that this happens when you copy a frame from one project to another project, and that frame inherits from something, and you fake the inheritance, but leave the "inherited" item descriptions in the frame dfm, items like this:
inherited ActionList: TActionList
Left = 520
Top = 576
end
This in turn results in the "current deserialization context" that Mason talked about, not containing the class. One fix is to change Inherited to object in all the above cases.

There is another way to get this error: put 'public' at the top of a form definition class. By default class members are 'published'. I accidentally added 'public' to the top of a form declaration and it produces multiple 'Class not found' exceptions at run-time.

I got a "EClassNotFound" error when I had a TLabel declaration present in my DFM file but there was no declaration for it in the corresponding PAS file. Somehow the form editor screwed up.
The error was not visible until I deleted all labels from my form except that particular "corrupted" one. It was difficult to hunt it down because that label was hidden under a panel.
One easy fix is to cut (ctrl+x) that label (once you find it) from the form and paste it back. This time the form editor will correctly insert a declaration for it in the PAS file.

There is yet another way to get this error: I have put 'private' at the top of a form definition class (because none of the elements were used outside the form).
So same like in previous answer (by Server Overflow): by default class members are 'published' and if you change visibility of a form declaration it produces multiple 'Class not found' exceptions at run-time.

Related

Control '' has no parent window : Why is control not named?

I've been tasked with supporting an application that is written in Delphi, which is occasionally crashing with the error message "Control '' has no parent window".
My question is not to understand WHY the error is happening, but to understand why the control has no name assigned.
Is the seeming lack of a name for the control a function of the way the control was coded (i.e., controls can have names but they are optional), or is this because the name of the control is inherited from the (non-existent) parent?
My question is not to understand WHY the error is happening, but to understand why the control has no name assigned.
Controls that are created at runtime, as opposed to design time, need not have names. So, this control has no name because the programmer created it without naming it, or it is a control created internally by another control, without being named.
It is perfectly normal for controls not to be named. It is perfectly reasonable for complex applications never to refer to control names.
There are multiple reasons, including but not necessarily limited to:
1) It wasn't given a name in the code.
2) It doesn't inherit a name for whatever function called it

How to debug or fix "Module has open descendants or linked modules" error?

I've had this long time problem that I can't view as text the main form for a project I inherited. Even if no other forms are open.
How can I debug the cause of this error message? What options do I have to fix it?
I found one related newsgroup post http://embarcadero.newsgroups.archived.at/public.delphi.ide/200906/0906193960.html but this only addresses the form inheritance cause, and doesn't explain anything about linked modules. I don't believe I'm using form inheritance.
I do have a DM (data module) for the project, and the form does load a couple of images from the dm through properties of a TTreeView on the form--does having a data module automatically mean I can never view as text a form in Delphi (aside from viewing the form as text in notepad)? It doesn't seem to matter whether my DM is open or closed in the IDE.
I also found one SO question with a related title (Module %s has open descendants or linked modules. can not reload) but the question itself and it's answer is not particularly relevant.
This is sometimes caused by a form that inherits from another form in your project (or the gallery) (known as Visual Form Inheritance in the documentation, IIRC). The IDE doesn't know how to find the base class for the form; it needs that opened before the descendant form. For instance, this can cause the same error if the unit containing TMyBaseForm isn't opened first in the IDE, particularly if the base (ancestor) unit is not included in the project first:
unit SpecialForm;
interface
uses
Forms, { all the other usual stuff }, BaseForm;
type
TMySpecialForm = class(TMyBaseForm)
private
public
end;
You can tell if this is the case by looking at your form's class declaration - if it descends from anything other than TForm, this is probably the cause of the error.
(Another instance of it happening is often when using a datamodule, because the base TDataModule .DFM isn't available. Attempting to view the datamodule .DFM as text will cause this error every time; the solution is to close your project and use an external editor such as Notepad or Notepad++ to edit the .dfm for your datamodule.)
I've had this issue occasionally, perhaps when I've used Frames, but my latest instance didn't involve Frames nor Data Modules nor inherited forms.
After an enormous amount of work creating a copy of the form (which copy didn't have the problem) and renaming the original unit and the form itself (which initially seemed to solve the problem), it turned out to be a live binding between forms.
Specifically, in my FMX application Form A has an options page with a TSpinBox that allows the user to set the minimum value for a TTrackBar on Form B (which was the form giving me grief). So the TSpinBox.Value was set to update the TTrackBar.Min field by means of a live binding. Closing Form A, or removing that live binding (and replacing it with an event handler to do the same thing) solved the problem.
I'd like to call upon the answer of Phillip J. Rayment and ADD that you don't have to have live binding to have this problem occur. It's sufficient to have custom control (class) of which you have an instance in another form. Then the RLink32 problem can appear and won't be solved until you close the form where you have the instance. The problem I experienced gave the following messages:
-RLink32 (during building)
-Access violation in module designide160.bpl` (if I made a modification to the problematic form)
-The module has open descendants or linked modules” error (if I tried to 'View as Form')

Accessing hidden private class in Objective-C

How can I access an attribute that's been hidden via:
__attribute__((visibility("hidden")))
I'm trying to access UINavigationItemButtonView, but it seems sometime recent (iOS 7.1?) they've added the above into the header file. Recursively printing the window no longer reveals UINavigationItemButtonView in the view stack either.
So, given a UINavigationBar, how can I access a UINavigationItemButtonView that has been hidden via the above flag?
Printing all the subviews in UINavigationBar doesn't reveal it.
The attribute keyword is simply a message to the compiler, and has nothing to do with the runtime. Using ((visibility("xxx")) only serves to tell the compiler if the given declaration should be "visible" or usable by clients in some other package. visibility("hidden") just means that, despite the public declaration, make this thing invisible to external packages, so that they will not be able to use it. Compiling will fail if you attempt to use this class or method.
If you don't see this class being used in a recursive description, it is likely that this class is no longer used; it certainly isn't because of the attribute statement.
Since it's a private class, you shouldn't. Anything you do to bypass that restriction may result in your application failing the review process. Not to mention that, in general, accessing private and/or hidden API's, classes, instance variables, properties or whatever else it is, is a really good way to make sure your application breaks in the (not too distant) future.

Delphi Win32 Programming/Access Violation problems

I wasn't entirely sure how to name this, so apologies in advance.
You see, I'm trying to teach myself Win32/DirectX programming, utilizing Delphi (my language of choice) using this site - http://rastertek.com/tutindex.html
Of course, the site being all in C++, I have to port it to Delphi. It seemed simple enough, at first. I'm on the second tutorial for DirectX 11 - setting up the framework and getting the initial window to show up.
Now for my actual problem. I was getting Access Violation errors. So I found and started to use MadExcept to try and find out what was going on. So it tells me the lines, but I'm clueless as to how to solve the issues at hand.
I have everything set up to mimic as well as I can the original source code. The only real difference being that in the instances where a pointer to a class for a variable, such as the case with m_input, m_grahics, and system, I made a type for those. So I have the TSystemClass, TInputClass, TGraphicsClass, and then I have PSystemClass, etc. that = ^TSystemClass, etc. I figured that this would make things a bit simpler and more neater. On a side note, I assume it should be said, but I for the construction of the copy constructors made the initial classes inherit from TPersistent so I could use it's Assign procedure.
So, back to the Access Violation errors. So first, the problem was in the main program with system being of type PSystemClass. So for a reason unknown to me, when I tried to use system.create, it was at that very instant, creating the access violation. I then realized however that I wasn't assigning system the system.create. So I tried this, and it said that, and rightfully so I suppose, at compile time an error that the two were incompatible since system.create is of type TSystemClass, and system is of PSystemClass. So I tried typecasting it, and that worked. but once again, still getting the dreaded access violations.
So then I had an odd idea, maybe I should call the regular constructor right from the TSystemClass itself. And I tried, needed to typecast again. So I did. And it worked! No longer an access violation error there! Now... New problem! Or rather in this case "problems". There's 3 things now listed in the call stack in MadExcept. The first one:
m_hinstance := GetModuleHandle(nil);
It's saying that this is causing an access violation error. Though why is this, exactly? From what I understand and have read, if GetModuleHandle is set to null/nil, it should retrieve the handle for the file that called it, right? And from what the documentation says, that should be executable.
However note: I'm not sure if the fact that I have the main program, the systemclass stuff, the inputclass stuff, and the graphicsclass stuff, all in different program/unit files to mimic the nature of the original source code. So is this possibly what's causing it? And if so how would I fix it? By putting all of the code from the unit files into the main program file? Though that, in my own personal opinion, would be quite messy and unintuitive.
The next one baffles me even more.
InitializeWindows(ScreenWidth, ScreenHeight);
I'm not dealing with anything other then a function to register the window class and set things up for the window and all here. So I'm not quite sure what the problem here is since it only deals with 2 parameters and they're defined and all already before it's called. So I'm not quite sure what the problem here is at all and what exactly is causing the access violation.
and then finally the final one is in the main program:
return := system.initialize;
Return is what I used in all instances of the result variable of the original source code, as result is of course a built in variable of all functions.
I suppose if system is never able to properly do what it's meant to do then something could/should happen here. Likewise, because I used TSystemClass.Create (typecasted to PSystemClass) earlier to create system would that do anything here? And is it possibly linked to the other two because they're not able to do their own thing properly?
And on a final note; there is one last thing actually on the call stack in MadExcept.
It says Kernel32.dll in the module section, but aside from the main thread, it lists nothing else. (If this information is needed I'll gladly put it up).
Thanks in advance to anyone who's read this far and I hope to find some help on this problem so I may further my studies.
You're instantiating your classes all wrong. Here's an example from TSystemClass.Initialize:
m_Input := PInputClass(m_Input.create);
That's a variable you declared as a PInputClass.
Earlier, in TSystemClass.Create, you initialized that variable:
m_Input := nil;
So, since you have a null reference, it should be clear that you can't call any methods on it. In particular, you cannot call Create on it. Instead, call Create on the class you want to instantiate: TInputClass.Create.
That constructor returns a value of the type you constructed, a TInputClass. It doesn't return a PInputClass, so your type-cast is wrong. As Cosmin's comment explains, Delphi object variables are already pointers. It's exceedingly rare to have to declare a pointer type based on Delphi classes. The correct code is this:
m_Input := TInputClass.Create;
After that line, you check whether m_Input is null. You never have to do that in Delphi; a constructor either returns a valid object, or it doesn't return at all. If there's a problem constructing an object, the constructor throws an exception and the assignment statement never executes. (The original C++ code does it wrong, too. The new operator hasn't returned a null pointer on failure for over a decade, long before anyone was in a position to start writing a DirectX 11 tutorial.)
You should first of all try to get rid of the TPersistent inheritance. If you want to pass an object to a library its interface should be exactly the same as the original that is used in C++. By inheriting from TPersistent you take a whole lot of load into your class that might be not needed or might even be the reason of your problems.
Additionally it would help if you posted the exact output of the exceptions. Or even the CallStack. That might help tracing down the error.

Receiving invalid property value

It was only recently that I started receiving this error.
I am receiving a run time error that first says 'Invalid Property Value', I click continue and then receive another one saying "Error reading Image2.OnClick : Invalid Property Value".
I use Image2 to manoeuvre between different forms. I have tried deleting all components named "Image2" along with any code under the OnClick event, but still receive the error.
Any suggestions?
Somewhere in one of your .dfm files that contain the design time properties of your forms, you have an OnClick property that refers to a method that has either been removed, or is invalid in some other way.
Open the .dfm file for the offending form in a text edit, and look for Image2. You will then find the offending OnClick property setting and should be able to work out how best to resolve the problem.
It's probably related to your method's access level.
If your OnClick method is declared as either private or public, try changing its access level to Published or move it right below the form declaration line.

Resources