Professional Documents
Culture Documents
2004
Volume 10 Number 4
INSIDE
ON THE COVER
.NET Developer
Moving to Delphi 8
Okay; so youve decided to make the move to .NET. Thats when the
questions really start. Like, Should I use VCL.NET? What about porting
VCL code to VCL.NET? Should I use the new Framework Class Library
(FCL) for .NET? Fortunately, Glenn Stephens provides answers to these
questions and many more.
Delphi Informant
www.DelphiZine.com
FEATURES
Columns & Rows
ADO.NET
Everyday
Form Techniques
Special C#PRO Insert
Everyday Delphi
14
Disconnected
Many Delphi developers spend a lot of time getting forms just so for clients. Thats why Rick Spence
thought it would be a good idea to share some user-pleasing-yet-generic UI techniques, from
changing a fields color when it receives focus (or highlighting it with a rectangle), to disabling
data-aware controls using RTTI, and more.
Just because .NET is a managed environment doesnt mean youre suddenly absolved from all your
resource management responsibilities, warns Bill Wagner. You still need to clean up some resources
in a timely fashion, rather than waiting for the garbage collector to be called in to tidy up after you.
The question is: Should I use a .resx or a .res file in my .NET application? The simple answer, replies
Richard Grimes, is that if you want to add resources to a managed application, you should add managed
resources. You do this through a .resx file. However, the simple answer only tells part of the story...
Reflection is a feature that gives developers good reason to think about securing their
components, cautions Michle Leroux Bustamante. She then goes on to discuss what can,
and cannot, be done to protect intellectual property, and even provides us with best practice
techniques for protecting components.
REVIEWS
29 PE Explorer
31
1
D E PA R T M E N T S
2 Toolbox
35 File | New by Alan C. Moore, Ph.D.
T O O L B O X
ProDelphi.Net Available for .NET Versions of Delphi
ProDelphi.Net from Helmuth J.H.
Adolph measures the run time of
programs written in Delphi for .NET.
This source code profiler gives you
the CPU-time consumed by the procedures of your program. The measurement is done based on CPU-cycles,
and works with a Pentium CPU or
Pentium-compatible CPU.
The principle of source instrumenting, the sophisticated measurement
correction algorithm, and the granularity of 1 CPU-cycle guarantee a high
measurement accuracy. Even small
or multiple nested functions are measured precisely. Source instrumenting
also ensures that idle times caused by
certain Delphi- or Windows-API functions (e.g. Sleep, MessageBox, WaitForSingleObject, etc.) are automatically
excluded from measurement.
Measurement results can be viewed
with a built-in viewer or exported to
a database. The user-friendly human
interface makes the profiling process
fast and easy; in particular, the sorting viewer enables the user to find the
bottlenecks at first glance. With one
mouse click the file with the measured
method is opened in Delphi and the
cursor is positioned at the beginning of
the measured method.
An optional call graph shows who
called a procedure and who is called
Web Tech Announces
New Delphi 8 for
.NET Training
Web Tech Training and Development announced a new five-day
training course: Delphi 8 for .NET.
Targeting existing Delphi developers, this course covers porting existing Delphi applications to Delphi 8,
ADO.NET, and ASP.NET.
The Delphi 8 course joins Web
Techs other VB .NET and C#
.NET courses to provide full coverage of the .NET platform. Courses
are held in St. Augustine, FL, and
Painswick, Gloucestershire, UK.
Courses are also available at client
sites throughout the world. For full
course details, schedules, and pricing visit www.WebTechCorp.co.uk or
www.WebTechCorp.com.
T O O L B O X
Gnostice Upgrades PDFtoolkit
Gnostice Information Technologies
or DataModule, set properties, then
released PDFtoolkit 1.02, an improved
call methods to fill or read form
version of its 100% VCL PDF document
values, compress, secure by setmanagement, manipulation, and PDF
ting password, append, or merge
eForms processing component set for
multiple PDF documents, rubber
Delphi and C++Builder. PDFtoolkit
stamp as Confidential, Draft,
supports filling and reading of PDF
etc., add bookmarks, and more.
forms; compressing, securing, appendThe final output can be received in
ing, and merging of multiple PDF docua memory stream or a disk file.
ments; stamping; setting bookmarks;
Enhancements in version 1.02
and many other functions that can be
include Unicode support for docuperformed on PDF documents. PDFtoolment information and bookmarks
kit operates on existing PDF documents
provided; embedding and sub-setand can create new ones by extracting
ting of True-Type fonts implementpages from existing documents. With
ed for text watermarks; form fields
the help of PDFtoolkit developers can
processing; merging of form fields;
embed PDF document management
modifying of appearance of filled form
functionality right into the business
fields implemented for viewing in Acroapplications they develop, making the
bat Reader and XPDFViewer; ENoAcroapplications more efficient and indepenFields exception introduced; removing of
dent of other external software.
form fields implemented; and more.
PDFtoolkit provides VCL components
PDFtoolkit 1.02 also includes
to link to the PDF documents that need
several fixes: the media box error
to be managed. The developer can place
for pages has been corrected; the
the PDFDocument component on a form
Invalid typecast error while insertUpdated Version of Visustin Released
Aivosto Oy has updated its flow chart
soft Visio 2002 for further editgenerator utility. Visustin 2 reverse engiing or to a word processor for
neers source code to flow charts. New
project documentation. Use the
features include Visio export, Web pubcharts in your project documenlication, print preview, and support for
tation in BMP, JPG, PNG, WMF,
T-SQL, PL/SQL, Ada, and Perl.
EMF, PS, or DOT image format.
Visustin creates an automatic flow
Other improvements include
chart layout by analyzing existing
multi-procedure visualization to
code. It works with the following landocument an entire module or the
guages: Pascal/Delphi, Visual Basic,
methods of a class, and options to
VB .NET, VBA, C/C++, C#, Java,
fit large charts into a small area.
JavaScript, COBOL, T-SQL, PL/SQL,
Visustin 2 supports Windows
Ada, and Perl. The flow diagrams can
95/98/ME/NT/2000/XP/2003. An evalube printed or published as Web pages. ation copy is available for free download
They can also be exported to Microat Aivostos Web site.
Aivosto Oy
Price: Single-user license, US$249.
Contact: vbshop@aivosto.com
Web Site: www.aivosto.com
.N E T
VCL
VCL.NET
D E V E L O P E R
DELPHI 7, 8
By Glenn Stephens
Moving to Delphi 8
Should You Use VCL.NET? the FCL? or Both?
time
are
major changes to the
Delphi language.
.NET
Developer
Moving to Delphi 8
var
sl: TStringList;
procedure TfrmUnsafeMain.AddItemToStringList(
AText: string; Value: integer);
begin
// This is an unsafe typecast.
sl.AddObject(AText, TObject(Value));
end;
Figure 3: Using PInvoke to make Win32 API calls from .NET code.
Figure 2: Using Delphi 7 to check that your code is ready for Delphi 8 for .NET.
.NET
Developer
Moving to Delphi 8
TfrmMain = class(TForm)
protected
procedure HandleResizeMessage(var Msg: TMessage);
message WM_MOVE;
end;
...
procedure TfrmMain.HandleResizeMessage(var Msg:
TMessage);
var
MoveMessage: TWMMove;
begin
MoveMessage := TWMMove.Create(Msg);
Caption := Format('X: %d; Y: %d',
[MoveMessage.XPos, MoveMessage.YPos]);
end;
Also, if your middle-tier relies on using the AppServer property to execute custom methods on your application server,
youll have to make sure the interface is imported to the client
machine, because you cannot call methods on a variant in
.NET. Instead, once you obtain the AppServer, youll need to
typecast it to the correct interface so you can access the business logic of your application server.
.NET
Developer
Moving to Delphi 8
Of course, not all platforms support
all of the functionality of the FCL. For
example, Windows CE smart phones
wont support all the display functionality of a WinForms application, and may
have limited support for other parts of
the FCL. This is because many of these
devices, such as the Windows CE-based
phones, dont implement support for
threaded classes. As a result, when you
develop an FCL application, youll need
to test that it will run on the platforms
youre targeting.
A single framework for every language. Apart from the FCL allowing you to use your code on new
platforms, there are other benefits
as well. One of the major benefits
of .NET is that the FCL allows many
programming languages to integrate
seamlessly. In the past, each programming language would have its own
framework. We had different compilers
with different frameworks, such as the
VCL for Delphi and C++Builder, and others such as the
Microsoft Foundation Classes (MFC) for Visual C++. With
.NET, there is only the one framework, the FCL, and every
programming language can use it.
A few years ago, a Visual C++ colleague might have
asked you how best to create a way of updating the caption every second. You might suggest the TTimer component, but because your colleague was using a different
framework (the MFC), that wasnt much help. Also, if
your project had both Delphi and Visual C++ modules,
youd have to deploy two frameworks that essentially do
the same thing. In the .NET world, everyone can use the
FCL, and because the .NET Framework will be deployed
with other .NET applications, theres less chance that
youll need to deploy the .NET runtime as well. In the
.NET world, with the FCL you could have just told your
colleague to use the System.Windows.Forms.Timer component. Then youd both be using the same classes and
could truly be working together.
This also means that you can integrate your Delphi apps
with the .NET language of your choice. If, for example,
youre developing an application that needs to integrate with
an expert system, you could develop that portion with a
Lisp or Prolog implementation of .NET, and develop the user
interface with Delphi 8 for .NET.
The Best of Both Worlds:
Mixing the VCL and the FCL
Once your application is running on .NET, you can mix
the VCL and FCL. If youve ported your VCL applications
to .NET, you may want to use some of the other technologies available in .NET, such as Web Services support,
encryption classes, or its remoting functionality. Because
youre programming in the .NET environment, youll have
access to all this functionality and can easily use these
.NET
Developer
Moving to Delphi 8
WinForm controls you want to use. The wizard then creates wrappers for the WinForm components so you can
use them in your VCL.NET applications. You can use this
wizard from inside Delphi 8 by selecting File | New | Other
and then selecting WinForm Controls Package.
Mixing frameworks is extremely handy, especially when
you have knowledge of how to do something in one
framework and want to use the best technique available.
Conclusion
Moving to .NET is a big step, but because .NET is the
future of Windows, its a necessary step for Windows
developers. Moving your existing Delphi applications to
.NET, however, shouldnt be a headache, and it isnt with
Delphi 8 for .NET. Yes, there will be bumps along the
migration path, but if you follow the advice in this article
your transition to .NET will be much smoother.
The projects referenced in this article are available for
download on the Delphi Informant Magazine Complete
Works CD located in INFORM\2004\APR\DI200404GS.
C O L U M N S
ADO.NET
&
R O W S
By Bill Todd
The DataAdapter
Figure 1 shows the most important properties of the
DataAdapter. The first four properties are Command objects.
The SelectCommand object contains the SQL SELECT statement
used to retrieve data from the database. The InsertCommand,
UpdateCommand, and DeleteCommand properties hold the
Command objects used to apply inserts, updates, and deletes to
the database. By performing inserts, updates, and deletes using
SQL statements that you can alter, the DataAdapter gives you
complete control. You can update tables directly, or you can
call stored procedures that perform the updates. If there are
fields that the user is allowed to enter in new records, but not
change in existing records, simply include those fields in the
InsertCommand objects INSERT statement and omit them from
the UpdateCommands UPDATE statement.
Since the SQL statement in the DataAdapters SelectSQL
Command object could select from a table, multiple tables,
Columns
&
Rows
10
Columns
&
Rows
Action
Description
Add
AddWithKey
Error
Ignore
where the ellipsis represents the names of the other columns. You will see an example of this later in this article.
Getting Schema Information
The DataTable object can enforce many of the data
constraints that you defined in your database. You can tell the
DataAdapter to get the primary key, MaxLength, AllowDbNull,
and AutoIncrement properties from the database when you
call the Fill method. Note that although the AutoIncrement
property will be set (if appropriate), the AutoIncrementStep
and AutoIncrementSeed properties will not.
Because getting the schema information for the constraints
is a relatively expensive operation, the DataAdapter
doesnt get this information by default. The DataAdapters
MissingSchemaAction property controls what information
is fetched when there are no DataColumn objects in the
DataTable. Figure 6 shows the four possible values for
MissingSchemaAction and explains what each one does.
If you want the constraint information added to the
Employee DataTable when you click the Open button, set
MissingSchemaAction to AddWithKey.
Another way to get the schema information is to call the
DataAdapters FillSchema method. Add another button to
the sample application, set its Text property to Fill Schema
and its name to FillSchemaBtn. Double-click the button and
add the code in Figure 7 to the OnClick event handler.
This code is identical to the code for the Open buttons
OnClick event handler shown in Figure 4 with two
Columns
&
Rows
procedure EmployeeForm.FillSchemaBtn_Click(
Sender: System.Object; e: System.EventArgs);
begin
if (EmployeeAdapter.TableMappings.Count = 0) then begin
EmployeeAdapter.TableMappings.Add('Table', 'Employee');
EmployeeAdapter.TableMappings[0].ColumnMappings.Add(
'EMP_NO', 'EMPLOYEE_NUMBER');
end; // if
EmployeeAdapter.FillSchema(EmployeeDataSet,
SchemaType.Mapped, 'Employee');
EmployeeAdapter.Fill(EmployeeDataSet, 'Employee');
EmployeeGrid.DataMember := 'Employee';
end;
procedure EmployeeForm.EmployeeAdapter_FillError(
Sender: System.Object;
e: System.Data.FillErrorEventArgs);
begin
MessageBox.Show('Error Filling Data Table',
'Error filling the ' + e.DataTable.TableName +
' table. ' + e.Errors.Message,
MessageBoxButtons.OK, MessageBoxIcon.Error);
e.Continue := False;
end;
DataAdapter Events
The DataAdapter has just three events, FillError,
RowUpdating, and RowUpdated. Figure 8 shows the
FillError event handler for the EmployeeDataAdapter in
the sample application. This event handler displays an
error message that includes the table name, and sets
the Continue property of the FillErrorEventArgs object
to False to stop any further processing of the data. The
FillErrorEventArgs object also has a Values property that
gives you access to the value in each field of the record
that caused the error. If you wanted to, you could write the
record that caused the error along with the error message
to a file or table, and set the Continue property to True to
continue processing the rest of the records.
The RowUpdating and RowUpdated events fire when you
call the DataAdapters Update method to submit changes
12
procedure EmployeeForm.OpenDeptBtn_Click(
Sender: System.Object; e: System.EventArgs);
begin
EmpDeptAdapter.GetFillParameters[0].Value := '671';
EmpDeptAdapter.Fill(EmployeeDataSet, 'Employee');
EmployeeGrid.DataMember := 'Employee';
end;
procedure EmployeeForm.CloseBtn_Click(
Sender: System.Object; e: System.EventArgs);
begin
if (EmployeeDataSet.Tables.Count > 0) then
EmployeeDataSet.Tables[0].Clear;
end;
Columns
&
Rows
the DataTable exists, a call to its Clear method removes all its
rows. After all its rows have been removed, you can call the
DataAdapters Fill method and get a new set of records.
Conclusion
The DataAdapter is the key to loading data into a DataSet
so users can work with the data. As you will see in future
articles, its also the key to applying the changes the user
makes back to the database. This article has only scratched
the surface of the DataSet object. The DataSet is the most
complex object in ADO.NET, and several articles in this series
will be devoted to getting the most from it.
The files referenced in this article are available for download
on the Delphi Informant Magazine Complete Works CD
located in INFORM\2004\APR\DI200404BT.
13
E V E R Y D A Y
FORMS
TIPS
D E L P H I
DELPHI 1-8
By Rick Spence
14
Everyday
Delphi
const
FOCUS_COLOR = clYellow;
// OnEnter event.
procedure TForm1.Edit1Enter(Sender: TObject);
begin
if Sender is TEdit then
begin
oldcolor := (Sender as TEdit).Color;
(Sender as TEdit).Color := FOCUS_COLOR;
end
else if (Sender is TRadioButton) then
begin
oldcolor := (Sender as TRadioButton).Color;
(Sender as TRadioButton).Color := FOCUS_COLOR;
end
else if (Sender is TCheckBox) then
begin
oldcolor := (Sender as TCheckBox).Color;
(Sender as TCheckBox).Color := FOCUS_COLOR;
end;
end;
// OnExit event.
procedure TForm1.Edit1Exit(Sender: TObject);
begin
if Sender is TEdit then
(Sender as TEdit).Color := oldcolor
else if (Sender is TRadioButton) then
(Sender as TRadioButton).Color := oldColor
else if (Sender is TCheckBox) then
(Sender as TCheckBox).Color := oldColor;
end;
Figure 2: Cumbersome code for OnEntry and OnExit events changing controls
background colors.
Note how SetOrdProp allows us to set a property of a particular object indirectly. That is, we call a function passing
(in this order) the object, the property in the object we
want to set (as a string), and the new value of the property. This relieves us from having to check the objects class
and typecast the result as we did in Figure 2.
15
uses TypInfo;
procedure TForm1.FormCreate(Sender: TObject);
begin
Screen.OnActiveControlChange := ControlChange;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
Screen.OnActiveControlChange := nil;
end;
// Called whenever focus switches to a new control.
procedure TForm1.ControlChange;
begin
oldControl := thisControl;
thisControl := Screen.ActiveControl;
ColorExit(oldControl);
ColorEnter(thisControl);
end;
procedure TForm1.ColorEnter(Sender: TObject);
begin
if Sender <> nil then
if IsPublishedProp(Sender, 'Color') then
begin
oldColor := GetOrdProp(Sender, 'Color');
SetOrdProp(Sender, 'Color', FOCUS_COLOR);
end;
end;
procedure TForm1.ColorExit(Sender: TObject);
begin
if Sender <> nil then
if IsPublishedProp(Sender, 'Color') then
SetOrdProp(Sender, 'Color', oldColor);
end;
// Previous control.
// Current control.
Everyday
Delphi
procedure TForm1.SetEnabledState(
ParentControl: TWinControl; State: Boolean);
var
i : Integer;
begin
for i := 0 to ParentControl.ControlCount - 1 do begin
ParentControl.Controls[i].Enabled := State;
// Recurse nested containers.
if ParentControl.Controls[i] is TWinControl then
Self.SetEnabledState(
TWinControl(ParentControl.Controls[i]), State);
end;
end;
const
BORDER_GAP = 1;
BORDER_SIZE = 2;
FOCUS_COLOR = clGreen;
implementation
{$R *.dfm}
procedure TForm1.focusChanged(Sender: TObject);
begin
Rect.Parent := Screen.ActiveControl.Parent;
Rect.Top := Screen.ActiveControl.Top BORDER_GAP - BORDER_SIZE;
Rect.Height := Screen.ActiveControl.Height +
(BORDER_GAP * 2) + (BORDER_SIZE * 2);
Rect.Left := Screen.ActiveControl.Left BORDER_GAP - BORDER_SIZE;
Rect.Width := Screen.ActiveControl.Width +
(BORDER_GAP * 2) + (BORDER_SIZE * 2);
Rect.Visible := True;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Rect := TShape.Create(Self);
Rect.Shape := stRectangle;
Rect.Visible := False;
Rect.Pen.Color := FOCUS_COLOR;
Rect.Pen.Width := BORDER_SIZE;
Screen.OnActiveControlChange := focusChanged;
end;
forms OnCreate event, set its pen color and width (the
pen is used to display the border of the rectangle), but
make it invisible. Then, when the active control changes
(well do this in the TScreen.ActiveControlChange event we
used earlier), well set the dimensions of the rectangle to
slightly larger than the active control.
Figure 6 shows the entire form; again, this code is available for download.
Change the constants for BORDER_GAP (the space
between the rectangle and the control), BORDER_SIZE (the
pen width, or how wide the line is), and FOCUS_COLOR to
your preference. Note how the custom focusChanged event
uses TScreen.ActiveControl to access the current control,
and how we use properties of this control to change the
rectangles dimensions.
Encapsulation with Forms
This tip focuses more on how you provide access to components on your form, rather than any specific GUI tip. If youve
read any books on object-oriented programming, or the Delphi
manuals, youve read about the principle of encapsulation.
For the uninitiated, it refers to the process of hiding the implementation details of a class from the class user. For example, a
person using the TStringList class doesnt need to know how
the class works internally (how it represents the strings). All
the class user needs to know is that it supports methods to
Everyday
Delphi
add and delete strings from this list, and that the list will grow
or shrink as necessary. The advantage of encapsulation is that
it allows the class implementer (the programmer writing the
class) to change the way the class works internally without
impacting the other programmers using the class.
A lot of Delphi developers have never created their own
classes; they use either the classes that come with the VCL,
or third-party components they buy on the open market.
For a lot of these developers, articles and books touting the
principles of object-oriented programming fall on deaf ears.
There are a couple of places, however, where these developers can benefit from encapsulation, even if they never
write their own classes. These relate to the form classes that
Delphis form designer generates for you.
As you know, when you create a form, Delphis form designer
generates a class for you. The components you place on your
form become instance variables in the new class. An important
question to consider is the scope of these instance variables.
Delphis form designer creates them as public, which means
theyre visible outside the class. This allows, for example, event
handlers of one form to change the properties of components
on another form (a common task).
Im suggesting, however, that maybe this isnt such a good
thing. It means that one form (lets call it frm1) has to have
knowledge of the components on another form (call this one
frm2). What if frm2 needs to change its components? Youll
have to change the code in frm1 as well. This is poor encapsulation, but is forced on us by the Delphi form designer.
Dont agree with me? Well, I have Microsoft on my side!
The Visual Studio .NET form designer generates code for
forms much as Delphi does, but by default the instance
variables used to store the forms components are declared
with a private scope, meaning you cannot access them from
outside the forms event handlers.
So how do .NET developers change components on other
forms? And how would Delphi developers change components on other forms if you follow my suggestion and
not directly reference the component? You write public
methods in the form to perform the changes to its components. Its forced on .NET developers, and Im recommending Delphi developers do the same thing.
17
www.C-SharpPRO.com
C#
By
Richard Grimes
By Bill Wagner
Protect Your
Intellectual Property
With Code
Access Security
By Michle Leroux Bustamante
Cover Story
By Bill Wagner
Cover Story
Figure 2. This listing shows the implementation for the stroke class. The
code inside the IDisposable region shows the proper implementation of
the IDisposable interface in a base class.
Cover Story
implement IDispose yourself. The only exception to this
rule is if you create a sealed class that implements IDispose. You no longer need to worry about derived classes
in those cases, as youll see in a moment.
Youll call this method from both your finalizer and your
IDisposable.Dispose method. It does the work necessary to
support both Finalize and Dispose, and because its virtual,
ensures that clients do not need to add their own finalizer nor
do they need to implement IDisposable. All derived classes
need to do is override this method, and provide the proper
implementation. You should factor out all the code from
IDisposable.Dispose and your finalizer into this method. In
essence, clean up managed and unmanaged resources when
isDisposing is true; clean up only unmanaged resources when
isDisposing is false. In both cases, call the base class Dispose
(bool) method to let it clean up its own resources.
IDisposable.Dispose and the finalizer are the public entry
points in your class, and both are defined in the uppermost
class that implements IDisposable. Both call the protected
virtual Dispose method. The isDisposing flag on the protected Dispose method is true if all resources should be freed;
its false if only unmanaged resources should be freed.
Lets go back to the drawing program I introduced you to
earlier. A Drawing object owns Stroke objects (see Figure 3).
Ive made the Drawing class a sealed class, and it owns a
set of strokes. In order to dispose of those strokes, it needs
to implement the IDisposable interface. Implementing the
IDisposable interface is simpler here, because Drawing is
a sealed class. I no longer need to be concerned with how
derived classes will free their resources. It is enough to
free the drawing resources in IDisposable.Dispose. And the
Drawing class does not hold any unmanaged resources, so
there is no need to add a finalizer.
Finally, take a look at the protected Dispose method in
the PocketDrawMain class:
_drawing.Dispose ();
}
//other details elided.
}
By Richard Grimes
Also, should you use .resx or .res files for application resources?
Q.
A.
class Data
{
public int result;
public void Proc()
{
result = 42;
}
static int CreateAndStartThread()
{
Data data = new Data();
Thread t = new Thread(new ThreadStart(data.Proc));
t.Start();
// what goes here???
return t.result;
}
}
Figure 1. This figure shows example code used to pass data to a thread
and return data from the thread. The code is not complete.
Q.
A.
Frameworks
Frameworks
svcUtil.GetType().InvokeMember("m_privateLicenseKey",
BindingFlags.GetField|BindingFlags.NonPublic|
BindingFlags.Instance|BindingFlags.Public, null,
svcUtil, null);
to this:
Worse, if the distributed code is not obfuscated, you
can open Intermediate Language Disassembler (ILDASM),
dump the IL into a text file, and clearly see this same private value clear as day:
//000014:
private string m_privateLicenseKey = "ad340d2301";
object [] args =
So, lets assume that you encrypt this value or use alternate
licensing methods for your Web services, that still doesnt
dalcComponent.GetType().InvokeMember("m_sqlGetImage",
namespace ImagingServices
{
public class ServiceUtil
{
private string m_privateLicenseKey = "ad340d2301";
public void SendImage(ImageInfoEx img)
{
SendImageInternal(img);
}
private void SendImageInternal(ImageInfoEx img)
{
// code to invoke ImageManager Web service
// using m_privateLicenseKey
return;
}
}
}
BindingFlags.SetField|BindingFlags.NonPublic|
BindingFlags.Instance|BindingFlags.Public,
null, dalcComponent, args);
Frameworks
With the help of CAS you can reject unauthorized callers and
help circumvent some of the potential misuses of reflection
in the process. Assemblies can be uniquely identified by their
strong name, so one way you can control access to types,
methods, and properties is to demand that callers have the
same strong name by using a StrongNameIdentityPermission
demand. In my example, all assemblies are signed with my
own key, mlbkey.snk; and this code puts a declarative demand
for that public key on the SaveImage method of the ImagingServices component:
[StrongNameIdentityPermission(SecurityAction.Demand,
PublicKey="0024000004800000940000000602000000240000
525341310004000001000100A7122EBA43D0ED4B7D5AA38517B
DC4D0ABECEFB455BF060A59560BEC50E238586A460AD53DD57F
9AB0EE8062BEC12BE51AB2CB5326ADBDB631E0F44717D2630AC
663A7F43A9617221691D09CC9217064800D7C4BED7B73EDEE46
B7A2A1D3B763BF19958A4B6B4410464816243D7AE559BE2DD69
0A65B370496A3A03DD0031CA8")]
private void SendImageInternal(ImageInfoEx img)
{
// code to invoke ImageManager Web service
// using m_privateLicenseKey
return;
}
What I did is apply a StrongNameIdentityPermissionAttribute to the method, telling it to perform a demand with
SecurityAction.Demand and providing the pubic key token
for the demand. This public key was extracted from the same
private key I use to sign my assemblies. A security demand
declared this way both adds the demand to the assemblys
metadata (so that administrators would see it if they actually
took the time to inspect the assembly) and causes a stack
walk every time this method is invoked. The stack walk will
ensure that every caller in the call stack has this permission,
which successfully prevents un-trusted callers from calling the
method. All calling assemblies must be signed with my key,
mlbkey.snk, which must be safely guarded.
This stack walk terminates when the runtime encounters a
stack frame that fails the permission demand (which throws
an exception), when the runtime successfully reaches the
topmost stack frame without exception, or when the runtime
encounters a security assertion for the requested permission. Assemblies with assertion permission can terminate a
demand stack walk early (and successfully) by claiming to
Premiere 2004 Issue
Frameworks
Only an assembly that is actually signed with a particular private key can assert its related public key in this way.
Makes sense right? Imagine if anyone could open ILDASM
and copy the public key token and then write un-trusted
code that asserts it? Regardless, assertions do open your
components up to luring attacks where now any client able
to invoke SaveImage will be granted access to the SendImage method that demands this strong name. Assertions can
improve performance by circumventing the stack walk;
however, they should be used sparingly (if at all) because
of possible security implications.
Demanding this strong name permission on the SendImage
method did not help me prevent access to the private license
key member stored inside the ServiceUtil object. As I demonstrated earlier in my EvilClientConsole example, this could
freely be hacked using reflection. In fact, most (if not all) permission attributes cannot be applied to fields, which means
in theory there is no way to isolate protection of a specific
field, even through its property accessor. You can, however,
achieve this by applying a security demand to the entire type,
or assembly.
If I move my StrongNameIdentityPermissionAttribute
declaration to the type level, all attempts to create the
ServiceUtil type and access any member (including private, protected, and public) will be rejected if the permission demand stack walk fails. This applies to both earlybound and late-bound access with reflection:
[StrongNameIdentityPermission(
SecurityAction.Demand,
PublicKey="0024...031CA8")]
public class ServiceUtil
{
private string m_privateLicenseKey = "ad340d2301";
// remainder of class definition
}
10
Frameworks
Resources
PublicKey="002400000480000094000000060200000024000
0525341310004000001000100A7122EBA43D0ED4B7D5AA38517
BDC4D0ABECEFB455BF060A59560BEC50E238586A460AD53DD57
F9AB0EE8062BEC12BE51AB2CB5326ADBDB631E0F44717D2630A
C663A7F43A9617221691D09CC9217064800D7C4BED7B73EDEE4
6B7A2A1D3B763BF19958A4B6B4410464816243D7AE559BE2DD6
90A65B370496A3A03DD0031CA8")]
11
N E W
&
U S E D
By Mike Riley
PE Explorer
Dig into Compiled Executable Resources with Ease
The most distinguishing feature that separates PE Explorer from other resource editors is its incredible ability to
perfectly render and visually represent an executables
menu and dialog structure for viewing and editing (see
Figure 1). Some editors simply read in string values and
coordinates; PE Explorer literally presents these visual
elements the same way they would appear in the running
application. This obviously makes editing and extracting
these elements considerably easier. Another benefit of this
approach is the education users receive when interrogating well-designed programs. Studying the clean, efficient
interfaces of commercial-grade apps can yield improved
GUIs in your own programs.
One of the more interesting uses of
the program is its ability to personalize or mod an application. In other
words, just as computer cases are
being decked out like the Funny Cars
of the 60s, PE Explorer allows creative
individuals the ability to fully edit and
replace strings, bitmaps, and icons
used by an application. Although this
probably infringes on many application
licenses, it nevertheless allows one to
alter Borland Delphi to My Favorite
Windows App Builder and insert cartoon character icons and family photo
bitmaps into toolbars and dialog boxes.
Figure 1: Check out the Delphi 7 development team photo uncovered by PE Explorers view of the
delphi32.exe resources.
29
New
&
Used
PE Explorer
In addition to the internal functions,
environment enhancements arrive in
the form of plug-ins via PE Explorers
plug-in API. Example source code is
included for Delphi and C, and the
API itself is fairly easy to leverage.
Hopefully Heaventools will post new
plug-ins on their Web site authored
by both the company and its
enthusiastic user base.
Figure 2: The disassembler is PE Explorers most powerful tool, providing developers with a deeper understanding
of an executables inner workings.
Conclusion
Power users will appreciate the plug-in API and ability
to dig into any executable, ActiveX, EXE, DLL, SYS,
DRV, MSSTYLE, CPL, OCX, BPL, DPL, or SCR file that
the program will allow. Some developers might argue
that even the modest price for PE Explorer is overpriced
compared to the free ResXplor example that ships
with Delphi, but the additional enhancements more
than compensate for the expense. However, the value
proposition proposed by PE Explorer is only validated if
developers leverage the more sophisticated tools such as
the disassembler or manifest wizard.
Figure 3: The Dependency Scanner tool is useful for determining the executable
components required by a program.
N E W
&
U S E D
By Bill Todd
amounts of paper that must be filed and stored. As mass storage prices have dropped, businesses have increasingly turned
to electronic document storage and retrieval systems.
But implementing a custom document storage system that integrates with the rest of your corporate data isnt easy, because
interfacing to a high-speed scanner with an automatic document feeder is complex. Fortunately, the developers at Skyline
Tools have done all the hard work for you. The best way to
explore some of the powerful features of ImageLib Corporate
Suite 7.0 is to build a document imaging application. I started
by dropping the following components on a form:
Coolbar
PrintDialog
ILDocImage
ILDocImageToolbar (on the Coolbar)
MMOpenDialog
MMSaveDialog
Document Imaging
The one type of imaging that more and more businesses need
is document imaging. In spite of the advances in moving to
a paperless environment, most businesses still generate vast
Property
Set To
DocumentImage
MMOpenDialog
MMSaveDialog
PrintDialog
31
New
&
Used
Figure 4: The scanned document from Figure 3 after anti-aliasing, and removing
the tilt and border.
New
&
Used
Button
Function
Image Enhancement
Combo
Open
Save
Prints a file.
Enables panning when down. With panning on you can pan around an image
that is larger than the component by dragging with the mouse.
Toggle Magnifier
Zoom In
Zoom Out
Reset Zoom
Best fit
Scan pages
Select Scanner
Toggle Annotation
Mode
When pressed you can right-click to display the annotation menu and annotate
the document.
Invert
Rotate 90 Degrees
Deskew
Remove Border
Navigator buttons
Update TIFF
Figure 6: The sample application with a thumbnail component added to the form.
Imaging Components
Working with color images, whether you scan them,
download them directly from a digital camera, or load
them from files, is just as easy as working with documents. Figure 8 shows an imaging application built by
dropping IlMultiImageToolbar, ImageLibThumbNails, and
PMultiImage components on a form and creating two simple event handlers. The toolbars AfterAction event handler loads into the thumbnail component all the files in
the same directory as the file the user opened. The ImageLibThumbNails components SelectThumb event handler
loads the image for the thumbnail the user selected into
the PMultiImage component.
Although the toolbar contains buttons to let you cut,
copy, paste, rotate, zoom, pan, invert, annotate, undo,
select scanner, scan, print, open, and save, the real power
is in the Effects Manager button. When you open the
Effects Manager, you can change image properties and
apply special effects, including AutoContrast, Bleed, Borders, Border Fade, Blur, Brightness, Color, Color Palette,
Darkness, Despeckle, Edge Detection, Engrave, Enhance,
Extrude, Gamma, Gray Area, Half Tone, Hue, Saturation,
Invert, Jiggle, Mirror, Mosaic, Motion Blur, Noisify, Oil
Paint, Page Curl, Paste Image, Pinch Hole, Polar, Rotate,
Sharpness, Spray, Softness, Tile Maker, Threshold, Transitions, Warp, Wave, and Whirlpool.
Documentation and Support
ImageLib Corporate Suite 7.0 is a technical tour de force
marred only by poor documentation. The only documentation supplied is the online help and the examples. There
are more than 40 examples, but they are undocumented.
The online help lists the examples and provides a brief
description for about two thirds of them. For the others,
only the name is given.
Examples, even examples with no commentary, were useful in the days before RAD tools. Examples built with
tools like Delphi that arent documented are, to me, an
exercise in frustration. Suppose you find an example
that does what you want using the ILDocImage component. Looking at the code alone does you no good. To
understand how the application was created you must
open a second instance of Delphi, drop an ILDocImage
New
&
Used
F I L E
N E W
Exploring Delphi 8
here has certainly been considerable interest in Microsofts new .NET platform. Not surprisingly, Delphi
developers have been waiting anxiously for their chance to
enter this exciting new world, with all of its well-publicized
benefits. The wait is over, of course, and Delphi 8 the
first Delphi version built specifically for Microsoft .NET
has finally arrived. This month Ill report on my first
explorations and initial reactions. Please bear in mind that
I will be describing the Architect version, so not every feature I discuss will be available in other versions.
You wont be too surprised to learn that the first thing to
catch my attention was the new look, one that reminded
me of Microsofts Visual Studio .NET. Upon opening Delphi 8 for the first time I saw much that was familiar: the
menu bar, tool bar, and an old friend the Object
Inspector. But the remainder of the desktop is filled with
additional windows, one of which is divided into several
tabs. These include a Project Manager, a central browserstyle window that starts its life as a Welcome page, and
a tool palette in the lower right-hand quadrant. Significantly, this desktop is much more configurable than those
of earlier Delphi versions.
I was pleased to find the essential information to get up
and running quickly, by simply clicking on Getting Started
in Delphis new HTML help system. Naturally there is
a description and overview of Delphi for .NET. A Tour
of the IDE (Integrated Development Environment) with
its various parts is also included. The good news is this:
With all the changes and the increased flexibility, building an application in this IDE isnt that different from
previous Delphi versions. The biggest change is in coding,
where we will have to get used to certain .NET practices.
Depending on the specific version you have, you can create a variety of application types, from the usual Windows desktop app, to ASP.NET Web applications. You can
also create .NET assemblies and custom components that
can be used by any .NET language, not just Delphi! Delphi developers can finally fully enter the .NET world.
The help resources include all the information that comes
with the .NET SDK, as well as information that is Delphi
35
File
New
Exploring Delphi 8
36