Getting errors creating ChromiumOSR programmatically - delphi

I'm trying to create ChromiumOSR programmatically but I keep getting an error (access violation).
Here is sample code that causes the problem:
var
pChromiumOSR: TChromiumOSR;
begin
pChromiumOSR := TChromiumOSR.Create(Self);
pChromiumOSR.OnLoadEnd := pChromiumOSRLoadEnd;
pChromiumOSR.Browser.MainFrame.LoadUrl('www.google.com');
end;
The problem is that pChromiumOSR.Browser.MainFrame is always nil. If I do
pChromiumOSR.load('www.google.com'); I don't get any errors but it doesn't fire the onLoadend.
Can anyone give me any suggestions on what I might be doing wrong?
I'm using Delphi XE2 but not sure which version of chromium (where can I find the version?)

Your attempt to use Load method for loading a page was correct. The other one was wrong and failed because the Browser instance was not created. It's because the TChromiumOSR was designed to be a design time component rather than to be created dynamically.
Now, the only place where the Browser instance is created is the Loaded method, which is called for a component after its parent form is loaded from a stream. And since you are creating it dynamically, the Browser instance is never created.
For some reason also the CreateBrowser method (which creates the Browser instance) is declared as private, which complicates its calling a bit (unless you decide to modify the source and make it public). If you don't want to change your DCEF source code, you can use a class helper to provide access to the CreateBrowser method:
uses
ceflib, cefvcl;
type
TChromiumOSRHelper = class helper for TCustomChromiumOSR
public
procedure CreateBrowserInstance;
end;
implementation
{ TChromiumOSRHelper }
procedure TChromiumOSRHelper.CreateBrowserInstance;
begin
Self.CreateBrowser;
end;
Then to create a Browser instance add the CreateBrowserInstance call before the first accessing the Browser instance (which is here the Load method):
var
pChromiumOSR: TChromiumOSR;
begin
pChromiumOSR := TChromiumOSR.Create(Self);
pChromiumOSR.OnLoadEnd := pChromiumOSRLoadEnd;
pChromiumOSR.CreateBrowserInstance;
pChromiumOSR.Load('www.google.com');
end;

Related

Function to recreate a TForm in Delphi

I need a procedure that recreates a form.
The reason being is that I have forms with many different components. These component values (edit box text, checkbox checked or not, etc) are saved inside onhide and loaded again isnide onshow. This makes sure all user settings are retained between runs of the program.
The problem comes when they make a change (intentionally or otherwise) that leads to problems. I want to be able to "reset" the form back to the default settings when the application is first installed.
I can create a reset button that runs this code
FormName.free;
DeleteFile('FormNameSettings.ini');
FormName:=TFormName.Create(Application);
FormName.show;
That does what is required. The form is closed, clears the settings file (so states are not restored when it shows again) and then recreates the form. The form now has the original default settings.
My problem is trying to get that code into a function that I can call easily from multiple forms.
procedure ResetForm(form:tform;filename:string);
begin
form.free;
if fileexists(filename)=true then deletefile(filename);
<what goes here to recretae the form by the passed tform?>
end;
Can anyone help get that ResetForm procedure working? Latest Delphi 11.
To return the newly created form we actually need a var parameter for the form, but that alone is not very elegant, because one cannot pass a derived form class to a var parameter of type TForm and has to do a hard cast to please the compiler. Even using a function that returns a TForm is not much better as the result is most likely assigned to a variable of a derived form class and that would also be rejected by the compiler.
Thanks to generics we can write some code that overcomes these restrictions. As standalone generic procedures or functions are not supported in Delphi, we wrap it inside a record declaration:
type
TFormUtils = record
public
class procedure ResetForm<T: TForm>(var form: T; const filename: string); static;
end;
We also need to save some information about the form for later use:
the owner of the form
is the form currently showing
This allows to recreate the form.
class procedure TFormUtils.ResetForm<T>(var form: T; const filename: string);
begin
var formOwner := form.Owner;
var formShowing := form.Showing;
form.free;
if fileexists(filename) then
deletefile(filename);
form := T.Create(formOwner);
if formShowing then
form.Show;
end;

How to set THTTPRio.Converter.Options to soLiteralParams in OnBeforeExecuteEvent

This refer to the post Delphi SOAP Envelope and WCF.
Could someone please post a sample code which can show me how to set soLiteralParams in THTTPRio.Converter.Options in Delphi 7. I have the following code currently.
I have drag-dropped a HTTPRIO component into the document which has created a line HTTPRIO1: THTTPRIO at the beginning of the code. I basically want to understand how I set soLiteralParams in the above component. Following is the code I am trying to execute which is giving me error.
procedure TForm1.CleanUpSOAP(const MethodName: String; var SOAPRequest: WideString);
var RIO: THTTPRIO;
begin
//The following line is giving error
// RIO.Converter.options := [soLiteralParams];
end;
In the above code I have declared a variable RIO of the type THTTPRIO, which I am not sure is correct.
Just guessing, as you provide very little information in your question.
Use the variable assigned to the component you dropped on your form. Don't declare a new local one (which you never created anyway). To set the Converter.Options in code, you'll need to add OPToSOAPDomConv to your uses clause.
implementation
uses
OPToSOAPDomConv;
// BTW, this name might not be a good one if it's the
// OnBeforeExecute event handler as that isn't
// clear from the name.
procedure TForm1.CleanUpSOAP(const MethodName: String; var SOAPRequest: WideString);
begin
// Note this clears any previous options!
HTTPRIO1.Converter.Options := [soLiteralParams];
// If you want to keep the previous options instead of replacing them
// HTTPRIO1.Converter1.Options := HTTPRIO1.Converter1.Options + [soLiteralParams];
end;
If you've dropped the component on the form, I'm not sure why you're not handling this in the Object Inspector instead, however.
If this doesn't solve the problem, edit your question and provide the exact error message you're receiving, including any memory addresses in the case of an exception being raised.
I have cracked this. The issue was that I didn't refer to OPconvert.pas file, which contained the TSOAPConvertOption enumeration. I don't know whether copying this file into the same folder as my project files and referring to this in the "uses" section is the right way, but it worked fine.

The control 'xxx' has no parent window

I'm was trying to write a dll library in Delphi wih a function that creates an instance of a TFrame descendant and returns it. But when I imported this function in an application, every time I called it I would get an exception like "the 'xxx' control has no parent window". I'm not 100% sure, but the exception appeared in the constructor of that class when any of GUI controls was accessed.
Could you please tell me what the reason of that behaviour is? Should I just use TForm descendants instead or is there a better solution?
Thank you!
About the error
That error message is raised from the Controls.pas unit, from the TWinControl.CreateWnd method. Essentially that code is used to create the Window handle for your TWinControl descendant (TFrame, TButton, TEdit... if it can have keyboard focus it's an TWinControl descendant), and it's actually an very sensible error message: You can't have a Window without an WindowParent, and since we're talking about the VCL here, it makes a lot of sense to try and get the parent window handle from TWinControl.Parent; And that's not assigned.
That's not WHY the error message is popping up. You get to see that error message because some of the code you're using to set up the frame requires an Window handle for some operation. It could be anything, like setting the Caption of some component (that internally requires an window handle do to some calculation). I personally really hate it when that happens. When I create GUI's from code I try to delay the assignment of Parent as much as possible, in an attempt to delay the creation of the window, so I got bitten by this many times.
Specific to your DLL usage, possible fix
I'm going to put my psycho mind reader hat on. Since you need to return a FRAME from your DLL, and you can't return the actual Frame because that's an Delphi-specific object and you're not allowed to return Delphi-specific objects over DLL boundaries, my guess is you're returning an Window Handle, as all the nice API's do, using a function definition like this:
function GiveMeTheNiceFrame:HWND;
The trouble is, that routine requires the creation of the actual Window Handle, by a call to TWinControl.CreateWnd, and in turn that call requires an parent window handle to set up the call to Windows.CreateWindowEx, and the routine can't get an parent window handle, so it errors out.
Try replacing your function with something allong the lines of:
function GiveMeTheNiceFrame(OwnerWindow:HWND):HWND;
begin
Result := TMyNiceFrame.CreateParanted(OwnerWindow).Handle;
end;
... ie: use the CreateParented(AParentWindow:HWND) constructor, not the usual Create(AOwner:TComponent) and pass an owner HWND to your DLL.
There are a few important things to remember:
When using DLLs, both your DLL and your EXE each have an Application instance that are struggling for control. The Controls in your DLL will see the Application instance that belongs to the DLL; the Controls in your EXE will see the Application instance that belongs to the EXE. That struggle is not there when using packages, as then there will only be one Application instance.
Frames are Controls, but they are not Forms.
When using Controls in an application, they cannot visually exist without a parent Control (usually a Form or a container that has a parent hierarchy towards a Form).
Some Controls cannot expose their full functionality unless they exist visually and have a valid parent.
Try to reproduce your problem inside the EXE; if you cannot reproduce, it is probably the first thing in the above list.
--jeroen
Sounds like you simply need to assign the component (a form or part of a form, like a panel) that holds the frame to theframe.parent.
You cannot do GUI work before it is assigned. Frames are parts of forms for reuse, and normally need to assign some parent to them.
Move the GUI code to onshow or a procedure you call explicitely, so that the calling code can assign parent.
Or make the parent a parameter in the function.
I found this (CreateParams is called as part of CreateWnd):
procedure TCustomFrame.CreateParams(var Params: TCreateParams);
begin
inherited;
if Parent = nil then
Params.WndParent := Application.Handle;
end;
And Application.Handle = 0 so it always throws the error later in CreateWnd.
After reading this
Delphi: How to call inherited inherited ancestor on a virtual method?
I have solved it by overriding CreateParams in my frame to miss out the tCustomFrame version:
type
tCreateParamsMethod = procedure(var Params: TCreateParams) of object;
type
tMyScrollingWinControl = class(TScrollingWinControl);
procedure TDelphiFrame.CreateParams(var Params: TCreateParams);
var
Proc: tCreateParamsMethod;
begin
TMethod(Proc).Code := #TMyScrollingWinControl.CreateParams;
TMethod(Proc).Data := Self;
Proc(Params);
end;
Now it's just throwing errors when trying to set the focus on subcontrols, which I think I will fix by intercepting WM_FOCUS but we'll how it goes from here.
function CreateFrame(hwndParent: HWnd): HWnd; stdcall;
var
frame: tFrame;
begin
Result := 0;
try
frame := TDelphiFrame.CreateParented(hwndParent);
Result := frame.Handle;
except on e: Exception do
ShowMessage(e.Message);
end;
end;
You can avoid this message by assigning nil to the parent OnClose event, sometimes it works:
SomeControl.Parent := nil;//Before free your TControl
SomeControl.Free;
I think this is very cool solution. I think it is not tried before :)
I'm using a Dummy Parent (which is a Form).
function MyFrame_Create(hApplication, hwndParent:THandle; X, Y, W, H:Integer):Pointer; stdcall;
var Fr: TMyFrame;
F: TForm;
CurAppHandle: THandle;
begin
CurAppHandle:=Application.Handle;
Application.Handle:=hApplication;
//---
F:=TForm. Create(Application);//Create a dummy form
F.Position:=poDesigned;
F.Width:=0; F.Top:=0; F.Left:=-400; F.Top:=-400;//Hide Form
F.Visible:=True;
//---
Fr:=TMyFrame.Create(Application);
Fr.Parent:=F;//Set Frame's parent
//Fr.ParentWindow:=hwndParent;
Windows.SetParent(Fr.Handle, hwndParent);//Set Frame's parent window
if CurAppHandle>0 then Application.Handle:=CurAppHandle;
//---
Fr.Left:=X;
Fr.Top:=Y;
Fr.Width:=W;
Fr.Height:=H;
Result:=Fr;
end;//MyFrame_Create
procedure MyFrame_Destroy(_Fr:Pointer); stdcall;
var Fr: TMyFrame;
F: TObject;
begin
Fr:=_Fr;
F:=Fr.Parent;
Fr.Parent:=Nil;
if (F is TForm) then F.Free;
//SetParent(Fr.Handle, 0);
//Fr.ParentWindow:=0;
Fr.Free;
end;//MyFrame_Destroy

Access Violation when assigning component property on Data Module

I'm on Delphi 2009, and my application contains a data module, which has a custom component named 'Globals' on it.
In another form in the application, I'm trying to change a published property (a string) on the Globals component:
dm.Globals.qhProject := _ProjectName.Text; //always gives access violation
The _ProjectName control is a TLabeledEdit descendant. I always get an access violation here if there's any text in the box.
However, if I manually assing a string to the property, I don't get the AV:
dm.Globals.qhProject := 'some text'; //works
Here's the declaration of the qhProject property:
FqhProject: string;
property qhProject: string read FqhProject write FqhProject;
I can't figure out why there's an AV here at all. I've tried moving the auto create order of the forms/data module around, but I always get the AV.
What am I doing wrong here?
Update:
I'm using Billenium Effects TFormContainer to switch between different forms in the application. Both forms that are involved here are in the form container. One form, TdlgSummary, contains the following:
procedure TdlgSummary.SyncVars;
begin
dm.Globals.qhProject := _ProjectName.Text
end;
The other form, TdlgFinalize, contains the following:
dlgSummary.SyncVars;
If I run SyncVars inside of dlgSummary, it works fine. If I call it from dlgFinalize, I get the AV. This seems to be the crux of the problem, but I can't figure out what's going wrong. Even if I switch control to dlgFinalize, dlgSummary hasn't been destroyed, because I can go back to it. Any ideas?
Looks to me like _ProjectName is nil. Try putting a breakpoint at this line and examine _ProjectName, see if it gives a valid reference or not.

AV When using a Procedure from one Component called by another

Im not sure if i have explaned this the best i can but, here we go...
I have 2 Custom components on a form, Which are link together at design time through the IDE. Whenever i call a procedure from on of the Component i get the Access violation,
Access violation at address 0049A614
in module 'Project2.exe'. Read of
address 00000034.
This is a small section of my code
TMyClient = class(TClientSocket)
{...}
end;
and...
TPresence = class(TComponent)
private
ftheClient: TMyClient
public
procedure SetStatus(status: string);
published
property UserName : string read fUserName write fUserName;
property theClient: TMyClient read ftheClient write ftheClient;
end;
procedure TPresence.SetStatus(status: string);
begin
try
***** if theClient = nil then
Exception.Create('theClient is Nil');
except
on e:Exception do
MessageDlg(e.classname+', '+e.message, mtWarning, [mbOK], 0);
end;
{...}
end;
0049A614 is at the *****, and the IDE stops here.
I Have also tried to do the assign at run time with
Presence1.theClient := MyClient1;
with no luck
using procedures from Presence1 or MyClient1 that do not rely on each other work fine.
Delphi 7
Follow Up:
from mghie comments, i rethought about it.
I removed the TPresence Component from the form (which caused some strange IDE errors, that might have had something to do with it) and created it design time, assigning everything that was needed. Now it works, but putting the TPresence Component back on the from brings the error back.
Thankyou for your help guys, i should be able to work this one out now, if i can't ill reopen another question :)
You seem to be thinking that the exception is raised because the client field of Presence1 is not set - if you do however get the exception "Read of address 00000034" it means that the Self pointer in the SetStatus() call is nil. That would indicate that you call SetStatus() on an unassigned TPresence reference. It is not really possible to tell the reason for that from the snippet you posted, but it should get you started debugging.
I would still advise you to write a proper setter method for all component references in your own custom components - first because you have a better hook when debugging such problems (you can set a breakpoint there), and second because you should always call TComponent.FreeNotification() on such linked components to be able to track their destruction and set the internal reference to nil.
We probably need more of your code. It is possible you are not correctly creating an instance of TPresence which would give you the error you are experiencing. Try to give us a simple as possible code snippet that causes your error.

Resources