Apparently the Import Component and View Type Library wizards are not enabled in Turbo Delphi (Win32) by default.
A workaround has been posted on the newsgroups:
Create an empty file named:
ATLBASE.H
in this directory: $(BDS)\include\atl\
ATLBASE.H
in this directory: $(BDS)\include\atl\
[HKEY_CURRENT_USER\Software\Borland\BDS\4.0\Type Library]
"ActiveXWizard"="True"
"InteropCheck"="True"
, also mentioned here.
Ctrl+Shift+J
on a selected text in the editor. Works in Delphi 2005 and higher.)INTERNET_OPTION_SEND_TIMEOUT
INTERNET_OPTION_RECEIVE_TIMEOUT
INTERNET_OPTION_SEND_TIMEOUT
INTERNET_OPTION_RECEIVE_TIMEOUT
TDockableToolbarForm
.TOrderedListEditDlg
) to edit the list of Subversion working copy directories.ICustomEditorView
interface and register it with a RegisterEditorView
call.EditorViewSupport
unit to your uses clause. This unit is only available through designide.dcp; there is no source code. But you can use Code Insight and Help Insight to see what methods are declared in the interface:
TSvnEditorView = class(TInterfacedObject, ICustomEditorView, ICustomEditorFrameView)
private
{ ICustomEditorView }
function GetCanCloneView: Boolean;
function GetCaption: string;
function GetPriority: Integer;
function GetStyle: TEditorViewStyle;
function GetViewIdentifier: string;
procedure Display(const AContext: IInterface; AViewObject: TObject);
function EditAction(const AContext: IInterface; Action: TEditAction; AViewObject: TObject): Boolean;
function GetEditState(const AContext: IInterface; AViewObject: TObject): TEditState;
function Handles(const AContext: IInterface): Boolean;
procedure Hide(const AContext: IInterface; AViewObject: TObject);
procedure ViewClosed(const AContext: IInterface; AViewObject: TObject);
{ ICustomEditorFrameView }
function GetFrameClass: TCustomFrameClass;
end;
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:template match="/">
<html>
<script language="javascript">
function showsrc() {
window.alert(document.body.innerHTML);
}
</script>
<body>
<a href="javascript:showsrc();">source</a>
<xsl:copy-of select="."/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Then move your mouse over some identifiers in your source code to bring up the Help Insight browser window, and click on the "source" link to see the original XML produced by the compiler.<MEMBER DisplayName=|DisplayName| name=|name|>
<SOURCE declaredOn=|declaredOn|
declaredIn=|declaredIn|
declaredInShort=|declaredInShort|></SOURCE>
[|your XML comments|]
<SUMMARY><PARA>|summary|</PARA></SUMMARY>
[|params|]
</MEMBER>
I'm not going to write up a complete description of the elements, here are just a few quick examples. Given the following source code, you get the XML shown below when you invoke Help Insight for Const1, TForm1, Field, Func, Prop, Event and Form1, respectively:const
Const1 = 42; // the answer to life, the universe and everything
type
TForm1 = class(TForm)
public
Field: Integer;
FEvent: TNotifyEvent;
function Func(X, Y: Integer; const S: string): Boolean;
property Prop: Integer read Field;
property Event: TNotifyEvent read FEvent;
end;
var
Form1: TForm1;
<MEMBER DisplayName="Const1 Constant" name="C:Const1">
<SOURCE declaredOn="10,3"
declaredIn="C:\Temp\Unit1.pas"
declaredInShort="Unit1.pas"></SOURCE>
<SUMMARY><PARA>Const1 = 42 - System.Integer</PARA></SUMMARY>
<MEMBER>
<MEMBER DisplayName="TForm1 Type" name="T:Unit1.TForm1">
<SOURCE declaredOn="13,3"
declaredIn="C:\Temp\Unit1.pas"
declaredInShort="Unit1.pas"></SOURCE>
<SUMMARY><PARA>Declared in Unit1</PARA></SUMMARY>
</MEMBER>
<MEMBER DisplayName="Field Field" name="F:Unit1.TForm1.Field">
<SOURCE declaredOn="15,5"
declaredIn="C:\Temp\Unit1.pas"
declaredInShort="Unit1.pas"></SOURCE>
<SUMMARY><PARA>Field - System.Integer</PARA></SUMMARY>
</MEMBER>
<MEMBER DisplayName="TForm1.Func(Integer,Integer,string) Method"
name="M:Unit1.TForm1.Func(System.Integer,System.Integer,System.string)">
<SOURCE declaredOn="17,14"
declaredIn="C:\Temp\Unit1.pas"
declaredInShort="Unit1.pas"></SOURCE>
<SUMMARY><PARA>Declared in <SEE DisplayName="Unit1.TForm1"
cref="Unit1|Unit1.TForm1"></SEE></PARA></SUMMARY>
<PARAM name="X">System.Integer
<PARAM name="Y">System.Integer
<PARAM name="S">System.string
<RETURNS><PARA>System.Boolean</PARA></RETURNS>
</MEMBER>
<MEMBER DisplayName="Prop Property" name="P:Unit1.TForm1.Prop">
<SOURCE declaredOn="18,14"
declaredIn="C:\Temp\Unit1.pas"
declaredInShort="Unit1.pas"></SOURCE>
<SUMMARY><PARA>Prop - System.Integer</PARA></SUMMARY>
</MEMBER>
<MEMBER DisplayName="Event Event" name="E:Unit1.TForm1.Event">
<SOURCE declaredOn="19,14"
declaredIn="C:\Temp\Unit1.pas"
declaredInShort="Unit1.pas"></SOURCE>
<SUMMARY><PARA>Declared in <SEE DisplayName="Unit1.TForm1"
cref="Unit1|Unit1.TForm"></SEE></PARA></SUMMARY>
<PARAM name="Sender">System.TObject
</MEMBER>
<MEMBER DisplayName="Form1 Field" name="F:Unit1.Form1">
<SOURCE declaredOn="23,3"
declaredIn="C:\Temp\Unit1.pas"
declaredInShort="Unit1.pas"></SOURCE>
<SUMMARY><PARA>Form1 - <SEE DisplayName="Unit1.TForm1"
cref="Unit1|Unit1.TForm"></SEE></PARA></SUMMARY>
</MEMBER>
As you can see, the <SOURCE>
node contains information about the source code file name, line number and column of the declaration. Also note the unclosed <PARAM>
tags ;-)<SOURCE>
and <SUMMARY>
nodes. Whatever your comments are, they all go there. The weird part is that if your comments contain any <PARAM>
or <RETURNS>
tags, or even any tags starting with these strings, such as <PARAMDEF>
or <RETURNSDESC>
, you will suppress the Help Insight's own <PARAM>
and <RETURNS>
sections (they will not be included anymore). If you want to have, for example, a list of parameters from the compiler mixed with your own descriptions of them, you'll have to use different tag names (I use <xparam>
and <xreturns>
) and write some XSL to produce the combined output.href="helpinsight:typelink:Unit1|Unit1.TForm1"
would open Help Insight window for my TForm1 type. Another I've found is href="helpinsight:filelink:C:\Temp\Unit1.pas?10,3"
which would make your IDE editor go to Unit1.pas at line 10, character position 3.<devnotes>
node in the XML output.
type
{$region 'xmldoc'}
/// <summary>
/// This is the application's main form.
/// </summary>
{$endregion}
TForm1 = class(TForm)
procedure TXMLDocRegionKeyBinding.BindKeyboard(const BindingServices: IOTAKeyBindingServices);
begin
BindingServices.AddKeyBinding([ShortCut(Ord('D'), [ssShift, ssCtrl])], Execute, nil);
end;
procedure TXMLDocRegionKeyBinding.Execute(const Context: IOTAKeyContext; KeyCode: TShortcut;
var BindingResult: TKeyBindingResult);
var
AllElided: Boolean;
Row, Col: Integer;
Lines: TStringList;
I: Integer;
ElideActions: IOTAElideActions;
begin
BindingResult := krHandled;
if Supports(Context.EditBuffer.TopView, IOTAElideActions, ElideActions) then
begin
Row := Context.EditBuffer.EditPosition.Row;
Col := Context.EditBuffer.EditPosition.Column;
try
Lines := TStringList.Create;
try
Lines.Text := ReadEditorSource(Context.EditBuffer);
// if all 'xmldoc' regions are elided then we want to unelide all;
// otherwise we want to elide (those which are not)
AllElided := True;
for I := 0 to Lines.Count - 1 do
if AnsiSameText('{$region ''xmldoc''}', TrimLeft(Lines[I])) then
begin
Context.EditBuffer.EditPosition.Move(I + 1, 1);
if not IsRegionElided(Context.EditBuffer.EditPosition, Lines[I]) then
begin
AllElided := False;
Break;
end;
end;
for I := 0 to Lines.Count - 1 do
if AnsiSameText('{$region ''xmldoc''}', TrimLeft(Lines[I])) then
begin
Context.EditBuffer.EditPosition.Move(I + 1, 1);
if AllElided then
ElideActions.UnElideNearestBlock
else if not IsRegionElided(Context.EditBuffer.EditPosition, Lines[I]) then
begin
Context.EditBuffer.EditPosition.Move(I + 1, 1);
ElideActions.ElideNearestBlock;
end;
end;
Context.EditBuffer.TopView.Paint;
finally
Lines.Free;
end;
finally
Context.EditBuffer.EditPosition.Move(Row, Col);
end;
end;
end;
function TXMLDocRegionKeyBinding.IsRegionElided(const EditPosition: IOTAEditPosition; const Line: string): Boolean;
begin
EditPosition.MoveEOL;
Result := EditPosition.Column < Length(Line);
end;
DSnapCom
unit. The client's IP address (passed in by httpsrvr.dll or scktsrvr.exe as an additional BSTR parameter) was not released properly, which caused a few bytes of memory leak for each method call.ThreadingModel = tmFree
) because it gives you total control over synchronization and optimization of your code. But writing thread-safe code also requires more work. In some cases, it may be useful to register your appserver to use the single-threaded apartment (STA) model (ThreadingModel = tmApartment
) and rely on COM to serialize calls from different threads into one thread "apartment" - the same thread which was used to create the instance.TRemoteDataModule
directly):
unit DataBkrEx;
interface
uses
Classes, ActiveX,
DataBkr;
type
TRemoteDataModuleEx = class(TRemoteDataModule, IMarshal)
private
FMarshal: IUnknown;
function GetMarshal: IMarshal;
property Marshal: IMarshal read GetMarshal implements IMarshal;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
end;
implementation
uses ComObj;
{ TRemoteDataModuleEx private }
function TRemoteDataModuleEx.GetMarshal: IMarshal;
begin
if not Assigned(FMarshal) then
OleCheck(CoCreateFreeThreadedMarshaler(Self as IUnknown, FMarshal));
Result := FMarshal as IMarshal;
end;
{ TRemoteDataModuleEx public }
constructor TRemoteDataModuleEx.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FMarshal := nil;
end;
destructor TRemoteDataModuleEx.Destroy;
begin
FMarshal := nil;
inherited Destroy;
end;
end.
Note that I'm not checking for a controller object (in case the appserver itself is aggregated) but that's normally not used in DataSnap appservers. The correct implementation would also require a replacement for TComponentFactory
in the VclCom
unit.