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

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.

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;

Delphi Bookmark Error: E2003 Undeclared identifier 'TBookmark'

Hey I wanted to use a TBookmark as a varialbe in my Form. I got it running in another Form and it is working there.
But in the new Form I get the Error.. I guess I have to include something in the uses statement but I cant remember what it was. Here is the code TBookmark is underlined in red so thats where the error sits.
procedure TForm4.FormCreate(Sender: TObject);
var test : string;
var selectedRow, rows : TBookmark;
begin
rows := Form1.DBGrid1.DataSource.DataSet.GetBookmark;
Form1.DBGrid1.SelectedRows.CurrentRowSelected := True;
Form1.DBGrid1.DataSource.DataSet.GotoBookmark(rows);
test := Form1.DBGrid1.DataSource.DataSet.FieldByName('name').AsString;
ShowMessage(test);
end;
end.
Your Form4 needs to Use the DB unit, because that's where TBookMark is declared.
Btw, what is in Form1's unit is irrelevant to this. The only relevant thing is that Form4's unit has to Use DB. What happens is that when the compiler tries to compile your Form4 unit, it needs to be able to find the definition of TBookMark, and that is in the standard DB.Pas unit along with lots of other dataset-related stuff. The same is true of any other identifier (or its class) that the compiler encounters in your project's source code.
99% of problems like this can be solved by doing a "Search | Find in Files" through Dephi's source code folders (and your project's folder if it's one of yours) to identify where the "undeclared" or missing item is declared.
Update So, you've got this code, which I'll assume is in your uForm4.Pas unit.
procedure TForm4.FormCreate(Sender: TObject);
var
test : string;
var
selectedRow, rows : TBookmark;
begin
rows := Form1.DBGrid1.DataSource.DataSet.GetBookmark;
Form1.DBGrid1.SelectedRows.CurrentRowSelected := True;
Form1.DBGrid1.DataSource.DataSet.GotoBookmark(rows);
test := Form1.DBGrid1.DataSource.DataSet.FieldByName('name').AsString;
ShowMessage(test);
end;
You want to be able to do something with the Name value that's shown in the current row of
DBGrid1 on Form1. There's nothing particularly wrong with the way you've done it, just that
it's long-winded, error-prone and invites problems like the one you've having with
TBookMark.
The point is that somewhere in your project, maybe in your uForm1.Pas unit, you know,
I don't, there must be a TDataSet-descendant (like TFDQuery, TAdoQuery or TTable) that is
specified in the DataSet property of Form1's DataSource1. For the sake of argument, lets'
say that the dataset component is FDQuery1 on Form1 and you want to get the Name field value
from the current row in DBGrid1.
To get that Name value, you don't actually need the bookmarks your code is using. The way
a TDBGrid works, the currently-selected row in the grid is always the current row in the
dataset component. So you could simply write
procedure TForm4.FormCreate(Sender: TObject);
var
test : string;
begin
test := Form1.FDQuery1.FieldByName('name').AsString;
ShowMessage(test);
end;
because you don't need to go through the rigmarole of Form1.DBGrid1.DataSource.DataSet to get to it.
Now, to explain another little mystery, how come your code would work fine if it was in uForm1.Pas
but you get the Undeclared Identifier: TBookMark error why you try the same code in uForm4.Pas
unit? Well, if you've ever watched the top of a source code file as it's being saved, you'll notice that
Delphi automatically adds, to the Uses list at the top, the units which contain any of the
components you've added to the form since its last save. So adding a TDataSource to the form would add
the DB unit to the Uses list, because that's where TDataSource is declared and so is TBookMark. Which
is why Delphi could compile Form1's code without the error, whereas when you try to mention a TBookMark
to uForm4, you need to add it to the unit's Uses list unless you add a component (like TDataSource)
to Form4 which will cause it to automatically add DB to the Uses list if it isn't already there. Mystery
solved.

Create a TDataModule only once

I'm trying to build a procedure that creates a TDataModule in Application as its parent.
The problem is, the second time I call the procedure, the dm parameter still nil. I expect something diferent of nil considering that it was created before.
Here is the code I'm trying:
procedure UseDataModule(dm : TDataModule; cClass:TcomponentClass);
begin
if dm = nil then
cClass.Create(Application);
end;
There are some requirements I want for this procedure:
The given TDataModule should be created once
It must to be created by procedure because I want to use It sometimes, that's why I don't put it in auto-create forms
Its parent will be always Application
Try changing your code to this:
procedure UseDataModule(var dm : TDataModule; cClass:TcomponentClass);
// the `var` qualifier is to allow the value of `dm` to be retained
// after `UseDataModule` exits, otherwise the Created instance will be discarded
// and you will have a memory leak
begin
if dm = nil then
dm := cClass.Create(Application);
end;
Imo, it would be better to code UseDataModule as a function, but that is largely a matter of taste. Note also that you could write if notAssigned(dm) instead of if dm = Nil.
I gather from your comment that you have decided to use the following code instead of my initial suggestion:
procedure UseDataModule(var dm : TDataModule; cClass:TcomponentClass);
begin
if dm = nil then begin
dm := cClass.Create(Application) as TDataModule;
end;
end;
which seems fine to me.
Another option is to use the same code used to autocreate forms with a check to see if it is already created.
// Create data module if it doesn't already exist
if DM = nil then Application.CreateForm(TDM, DM);

CHM file not displaying correctly when Delphi VCL style active

My Delphi application includes a help file that the user can call from anywhere in the application (well... that is, for all the parts I've written so far...)
It also includes the ability for the user to switch from the regular style to another VCL style from a list.
When no style is applied, the help file displays normally like this :
But as soon as a VCL style is active, the Help file does not display correctly anymore, like this :
Is this due to the way I declare the HelpFile on main Form creation like this (path being a global variable pointing to the main exe folder):
Application.HelpFile := path+'Help\D.R.A.M.A. 2.0 Help.chm';
or is this a known problem that can not be solved ?
SIDE NOTE : the help is called on helpContext should that be important to mention and the HtmlHelpViewer is added to the uses clause.
This answer was taken from https://forums.embarcadero.com/thread.jspa?threadID=227785 and I've confirmed works very well.
Drop a TApplicationEvents component onto the applications main form.
Implement the OnHelp event of that component as this:
function TfmMain.ApplicationEvents1Help(Command: Word; Data: NativeInt; var CallHelp: Boolean): Boolean;
begin
CloseHelpWnd;
Result := ShellExecute(0,'open','hh.exe',
PWideChar('-mapid '+IntToStr(Data)
+' ms-its:'+Application.HelpFile),
nil,SW_SHOW) = 32;
CallHelp := false;
end;
On the main form, implement the CloseHelpWnd method as this:
procedure TfmMain.CloseHelpWnd;
var
HlpWind: HWND;
const
HelpTitle = 'Your help file title';
begin
HlpWind := FindWindow('HH Parent',HelpTitle);
if HlpWind <> 0 then PostMessage(HlpWind,WM_Close,0,0);
end;
You would replace 'Your help file title' with the title of your help file. This is the window caption title when you open the help file directly.
In the FormDestroy event for the main form, include a call to
CloseHelpWnd;
So far we've not seen any issues with the above method, and because we are running the help file in a separate process, it is not affected by the VCL Styles problems evident in Delphi 10.2 Tokyo.
NOTE: It does not have to be the applications main form, but it must be a form that is created before the help system is needed and remains instantiated while the application is running. In our case, we did it on a common resources form and then all programs we rebuilt with the new form had the help problem resolved.
NOTE: You still need to set the Application.HelpFile property as normal, but you don't need to include the HtmlHelpViewer unit in the Uses clause.

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