Developing single source Delphi - Win32, .NET, and Linux

When presented with cross platform development, most developers resort to spreading IFDEF's all throughout their code. Unfortunately this creates unmaintainable and brittle code.

In this article I will demonstrate proven ways of using polymorphism and other object oriented techniques to produce solid and maintainable, single source, source code. While IFDEF's are used, their use is kept to a minimum and they are kept in isolated units. I will also cover commonly encountered differences between platforms and how to manage them.

Techniques used in this article have been developed as project leader of both Indy and IntraWeb. Both Indy and IntraWeb are available for all three platforms.

How?

Cross platform code should be implemented with as few IFDEF's as possible and such uses should be contained and isolated. Rules should be established that determine which units IFDEF's are permitted in, and no IFDEF's should be allowed in other units. This practice is very different than the common practice. The common practice in cross platform development is simply to find each difference and insert an IFDEF on the spot of each difference. IFDEF's should be applied like medicine, not like napalm.

Cross platform code should be implemented with as few IFDEF's as possible

If IFDEF's are to be minimized what can be used instead? Polymorphism. Polymorphism is one of the core concepts in object-oriented programming. By using polymorphism IFDEF's are minimized, and platform differences are well documented and isolated. Polymorphism encourages better source code implementations by not allowing quick IFDEF hacks to be used.

IFDEFfing may be easy in the short term, but in the long term it is much more expensive in terms of maintenance and occurrence of bugs.

Platform differences can also be minimized by sticking to the RTL, VCL, Indy, and the YCL. Both the RTL and VCL provided by Borland implement many of the platform differences internally. By using these class libraries the differences are the responsibility of the libraries, and not the user. Indy, while originally designed for sockets, has built its own system library which takes care of many platform differences as well. The Indy System library can be used without linking to the socket functions and thus can be used in any application, whether or not the application uses sockets. YCL is "Your Component Library". By isolating all platform differences in libraries you can keep code that uses these combined libraries such as applications and higher level libraries free of IFDEF's.

Cross Platform

What exactly does cross platform mean? Cross platform means that one set of source code is designed to be compiled on more than one platform. A platform usually means an operating system such as Windows or Unix, but in recent years platforms themselves can be independent of operating systems such as Java, or .NET. In the context of this article when I say cross platform I mean developing source code that runs on Win32, Linux, and .NET.

This article will focus on .NET as it is much more different from Win32 than Linux is. The techniques demonstrated here will work for any platform, but since the .NET platform introduces so many changes that are new to developers, this article contains mostly information about these differences.

Platform Specific Features

Developing cross platform code requires that all platform differences be identified and handled individually. Since some platforms may contain features that the others do not, it is often necessary to either implement these features again on the other platforms, or conform to the lowest common denominator. That is, use only features available on all the platforms.

.NET introduces many new features that are of great use to developers. Some of these features manifest themselves as differences while others are completely new functionality. Some of the largest new .NET features are the FCL (Framework Class Library), namespaces, operator overloads, and safe versus unsafe code.

Not every developer needs to support Linux. You should determine if you need to support Linux or not as this can lessen the requirements and decrease the amount of work required. While Linux support is easier than .NET in many aspects, it is certainly easier to support two of three possible platforms than supporting all three.

Many of the new features introduced by .NET are language features. These language features were introduced into the Delphi language with Delphi 8. However at this time Delphi 8 can only compile for the .NET platform and Delphi 7 must be used to compile for Win32. Because of this, the new language features cannot be used in cross platform code at this time. When Delphi 9 is released most of the new language features will be ported to the Win32 compiler and cross platform code will be able to take advantage of them.

When Delphi 9 is released most of the new language features will be ported to the Win32 compiler and cross platform code will be able to take advantage of them

Safe versus Unsafe

If you have done any investigation into the .NET world, you probably have heard the terms "Safe Code" and "Unsafe Code". These terms are also known as "Managed Code" and "Unmanaged Code" respectively. In short, managed code is code that executes inside the control and rules of the .NET framework. While unsafe code is old code that has less rules, but through a "compatibility option" can be called from safe code. The ultimate goal of any .NET application is to use 100% safe code and isolate all unsafe code into separate assemblies necessary when accessing hardware, etc. In a 100% .NET world all applications will run only safe code and only drivers, encryption, and other such items shall run as unsafe code. Unsafe code is also operating system specific while safe code can run on any operating system which the .NET framework is implemented on.

Many servers also restrict applications that run on them to only safe code. Any unsafe assemblies are an exception and must be permitted by the system administrator.

Using Delphi 7

It might sound as if I am telling you to go backward in time, but it is much easier to develop cross platform Delphi code using Delphi 7 as the primary IDE. Delphi 7 will restrict you to the base functionality and prevent you from using new language features introduced in Delphi 8. Delphi 7 also can help you refrain from writing unsafe code. Borland built in unsafe code checking in Delphi 7 to help developers prepare for .NET, even though Delphi 7 cannot produce executables for the .NET platform.

These warnings are available in project options. In the screen shot below you can see they are unchecked. In cross platform code you should enable these three warnings and then proceed to eliminate each of them one by one until they only appear in platform specific code. In non cross platform code you should turn these warnings off, because when there are many of them in a given project, the logging of these warnings to the output window drastically slows down the compiler.


Delphi 7 is also better for porting existing code to .NET as it allows you to proceed step by step, eliminating one unsafe item at a time. You can then regularly test your changes before all unsafe code has been eliminated. However if you move your code to Delphi 8 immediately you will have to eliminate all unsafe code at once before you can even retest the application as whole, instead of piece by piece.

Delphi Magic

When designing Delphi 8, one of Borland's primary goals was to maintain backward compatibility of source code. This has been done to an amazing degree. However, because of the extensive differences between Win32 and .NET there are still differences in how code compiled by Delphi 8 executes from code compiled by Delphi 7. With these differences in mind, it is quite easy to write code that works in both Delphi 7 and Delphi 8. This may not seem like a major feat, but those who have experienced the differences between C++ and C#, or Visual Basic and Visual Basic.NET will appreciate the amount of work that has gone into Delphi 8 to preserve backward compatibility.

Delphi maintains backward compatibility through both implementations in the included libraries RTL and VCL, but also by building in some magic into the compiler itself.

Delphi maintains backwards compatibility through both implementations in the included libraries RTL and VCL

One primary area of compiler magic is strings. In Delphi strings have always been a special case handled directly by the compiler. In .NET, strings are objects, but still with a special status. Delphi preserves nearly all former string behavior, but maps the string type to the .NET string object. So in Delphi it is not only a traditional Delphi string, but it is also a .NET string at the same time. Delphi performs similar magic with TObject and TComponent mapping them to their direct counterparts in the FCL, while still preserving their VCL qualities. For objects Delphi uses a new language feature called class helpers to implement this dual behavior.

.NET Also performs object construction and especially destruction differently than in Win32. Delphi is not able to totally isolate this behavior, but it does preserve many of the important aspects through its handling of destructors.

.NET Common Error

If you have worked with .NET or used .NET applications, you may have encountered this error:

This is the error message that an end user will see if an error is left unhandled. When running in the debugger, it will appear as a specific exception type:

If you have not encountered this error yet, you will, especially during development.

Object reference not set to something or other

This error signifies that a variable was referenced but not initialized yet, or it referenced an object that has been destroyed. Consider the following code in Delphi 8:

program Project3;

{$APPTYPE CONSOLE}

uses

  Classes,

  SysUtils;

var

  LStrings: TStringList;

begin

  LStrings.Add('Test');

end.

When the program is executed it will reference LStrings, which is not initialized yet. This will cause this error shown previously.

The same code can be run in Delphi 7, but with slightly different results. When the same code is executed in Delphi 7, it yields a different error as seen below.

Why does the same code produce an Access Violation in Win32, and a "Object is not set to an instance of an object" in .NET? The answer is simple, yet complicated at the same time.

Object is not ready yet (XP style)

The short and possibly logical answer is that "Object is not set to an instance of an object" is really an Access Violation. And in fact - it mostly is. The difference is a lot in just the name, but also in the handling and cause. While the root of the cause is the same, the conditions it can occur under are more restricted. An Access Violation is a very wide-ranging error that can occur any time code tries to access something it should not. Access to an uninitialized object or already freed object is just one of these possible conditions.

"Object is not set to an instance of an object" on the other hand can only occur in this one specific condition and thus is much easier to find and remedy. Because .NET protects memory much closer, memory corruption is not possible in the traditional sense. Since there are no pointers, they cannot go wild.

It's a .NET AV

Let's examine the history of the Access Violation.

·    In Windows 3.0 it was called a UAE, or Unrecoverable Application Error.

·    In Windows 3.1 it was called a GPF, or General Protection Fault.

·    In Win32 it was called a AV, or Access Violation.

·    In .NET, it’s called "Object references not set to an instance of an object"

While it’s true that in each version the error became more restricted and specific, each error is just a narrowed down version of its predecessor. While a "Object is not set to an instance of an object" is not exactly the same as an Access Violation and a blanket statement as such is not accurate, understanding that it is the direct evolution of the Access Violation will help you to debug and prevent it.

.NET - Things remembered

In .NET several things that we as developers have come to rely on as mainstays, are now no longer available. While some of them may come as a "shock to the system" for many experienced developers, the changes are all good and even necessary ones. After you have survived the initial trauma, you will come to realize that these are beneficial changes in the long run.

Some of the most prominent items that are no longer available in .NET are:

·    Pointers

·    Untyped variables

·    Win32

·    Globals

·    Sets

·    AfterConstruction / BeforeDestruction

·    Class cracking

Pointers

Pointers are the pinnacle of unsafe code and are no longer available. In modern object oriented code pointers have been relegated to infrequent use, mostly for calling operating system API's or interacting with external DLL's. There is no magic replacement for the use of pointers, but instead is a multi faceted approach which includes the use of:

·    String Indexes

·    Object references

·    IntPtr

·    Dynamic arrays

Because the pointer is no longer permitted this means that the address of operator (the @ symbol) is no longer permitted. However there is one exception. The @ symbol can be used with procedure pointers. In this one specific case the @ operator is permitted because the Delphi compiler recognizes this specific case and translates it to a .NET delegate. That is, internally no pointer is used, but the use of the @ symbol is preserved for backwards compatibility.

Pointers are the pinnacle of unsafe code and are no longer available

Buffers (Untyped Variables)

Since untyped variables relied on the use of pointers, they are also no longer available in safe code. Use of untyped variables must be replaced with object references, or method overloads. An example of this is covered later with TStream.

Win32

The Win32 API is no longer available in safe code either. However, since Windows is the only current platform for which .NET is released, it is still common place to call the Win32 API directly. Doing so makes such code unsafe and thus should be avoided or isolated into a separate unmanaged assembly.

Instead of calling the Win32 API, the FCL classes should be used instead. If a Win32 API call must be called a P/Invoke can be used. P/Invoke is a way for safe code to call unsafe code. Delphi does much of the P/Invoke work automatically in a manner similar to calling an extern in Delphi 7. Most Win32 API's have already been mapped in the Windows unit and can be called directly by using this unit.

Globals

Globals of all kinds are no longer available. This includes global variables, procedures, and functions.

How can globals be eliminated? For most developers globals have always been there and it is impossible to imagine how development can occur without globals. In fact if you go back far enough to have used line numbered basic you may remember similar confusion when someone told you that there was a new basic without line numbers. Such a thing just was not comprehensible until one actually saw it and how it worked.

In .NET everything is a class. Some developers may begin to have a "smalltalk attack", but .NET is not SmallTalk. Because everything is a class, no global procedures or variables can exist because they are not part of a class.

To replace globals, statics can be used. A static is a variable or method that exists on the class, rather than on the instance of a class. If that is not clear, imagine the object TFoo and instances of TFoo called Foo1, Foo2, and Foo3. If a static variable named Count exists, only one Count will exist for all instances of TFoo, instead of one per instance. So if Foo1.Count := 4, then when we access Foo2.Count, it will be 4 because it’s the same variable. In fact, we do not even need an instance, we can simply access it from the class itself as TFoo.Count. Delphi has always had static methods that could be called on the class, but the introduction of static variables is new in Delphi 8.

Many developers simply make a TGlobal class and add all their globals to it, and then access them simply by prefixing them with TGlobal.

Delphi Globals

As I just stated, globals are gone. However in Delphi 8 for backward compatibility globals can still be used.

How is that? How can globals be gone, yet still be here? Delphi 8 can still use globals because of a bit of compiler magic. More about this later in the Units topic.

Sets

Sets are another item that are both gone, and still here. Sets are not available in .NET, but through some compiler magic are available in Delphi 8. When using Delphi code, sets are available and function nearly the same as before.

However, if a C# user or Visual Basic user tries to use your set, he will encounter some difficulty. Delphi exports sets as integer values and indexes. They can in fact use them, but the usage will be a bit awkward and require boolean operations. If you are using sets, you should only use them in Delphi code that is not exported. If you need to export set functionality you should rethink the interface and export it as a class instead.

Things Different

Other items have been preserved in .NET, but their functioning has changed. The major items you will encounter are:

·    Strings

·    TList / TStrings

·    Initialization and Finalization

·    Units

·    Variants

·    Typecasts

·    Constructors and Destructors

Strings

Strings have changed significantly in their implementation and inner workings. Many of the changes have been isolated and backward compatibility has been preserved wherever possible. However there are still changes that are very important to be aware of.

The biggest change to strings is that all strings are now Unicode. Each character in a Unicode string consists of two bytes, instead of one as before. This does not affect normal string operations, but many developers regularly use strings as dynamic buffers for binary data. Strings can no longer contain binary data.

Instead of using strings for binary data other specifically suited constructs such as byte arrays or binary streams should be used instead.

Immutable

Strings in .NET are immutable. Immutable is just a fancy word for saying that they are not changeable. How can strings not be changeable? Dynamic strings have been a tenet of programming for a long time.

Strings in .NET can be changed of course, but not internally. This means that you can write code to change a string, but internally a new string must be made and the alterations copied to the new string. This is implemented transparently to the developer, but can have very negative impacts on performance.

Consider the following code:

s[5] := 'z';

In Win32 this code compiles to instructions that modify just one character while leaving the existing string intact. In .NET, the code still works, but its implementation is very different. Because strings are immutable, .NET must create a new string and copy the results into the new string, and then finally destroy the old string.

In short, remember that any change to a string causes a string copy to be performed. If only a few changes are performed, it can be done very quickly. But large amounts of changes such as search and replaces and parsing will run very slow under .NET if not redesigned.

Empty String

In Win32 strings that are declared as part of a class are initialized to an empty string with a value of ''. In .NET strings instead are objects and initialized to nil, which is a different value than ''. Nil is the value of the object reference, while '' is the value of the data of the object.

Consider the following class:

type

  TMyObject = class(TObject)

  protected

    FMyString: string;

  public

    procedure Test;

  end;

implementation

procedure TMyObject.Test;

begin

  if FMyString = nil then begin

    raise Exception.Create('string is nil');

  end;

end;

In .NET, this is the proper way to check for a string that has no value. However this code does not work in Win32 and if this were required, it would break a lot of backward compatibility. So Borland added another item of compiler magic so that the following code is the same as above:

procedure TMyObject.Test;

begin

  if FMyString = '' then begin

    raise Exception.Create('String is nil');

  end;

end;

This has an additional benefit though. In .NET nil and '' are actually separate states, but rarely differentiated and of very marginal use. In Delphi, checking for '' will check for '' or nil. While the above code works fine, a direct C# port would not function the same. In C# one must check for both '' and nil, as the string may have been initialized but still be empty. In C# it is necessary to check for both. The Delphi equivalent of what must be done in C# is shown below:

procedure TMyObject.Test;

begin

  if (FMyString = '') or (FMyString = nil) then

  begin

    raise Exception.Create('String is nil');

  end;

end;

String Help

So far, I have explained many of the problems that you will encounter with strings in .NET. But fortunately there are some new features related to strings as well.

StringBuilder

StringBuilder is a .NET class for manipulating strings. StringBuilder unlike String is mutable, meaning you can change it without causing constant reallocation. When you know that you will be working on a string, you should use a StringBuilder and then use or copy the final result when your changes are complete.

StringBuilder solves the problem in .NET, but StringBuilder is not available in Win32. A StringBuilder class is available on the Borland Developer Network for Win32, which allows you to use StringBuilder in both Win32 and .NET.

AnsiString

AnsiStrings are still available in Delphi and produce single byte strings. However AnsiStrings should not be explicitly used as everything in .NET is Unicode, and each time an AnsiString is passed to a .NET method or procedure that uses Unicode, a conversion will have to be performed to pass it in, and one to return it. This has a severe impact on performance. AnsiStrings are only safe in Delphi only code, but should still be replaced with Unicode strings for string work, and other means for binary work.

TIdBuffer

StringBuilder is a good solution to managing dynamic Unicode strings. It however still manages strings as Unicode, and in many cases only ASCII is required. A good example of this is for TCP commands.

Indy implements a buffered class that handles binary data, as well as ASCII values. TIdBuffer, because it implements its storage as bytes, is suited to binary data, but also handles string input and output as ASCII and thus is suited to ASCII handling requirements. TIdBuffer is also a smart class that manages memory by buffering and predicting data usage, thus reducing reallocations.

TList / TStrings

TList and TStrings accept an additional "tag" value known as Object for each item in the list. In Win32 this type was of Pointer and commonly typecast in and out to other values. For example:

MyStringList.AddObject('Line one', Pointer(1));

Since pointers are not available in .NET, this no longer works. However pointers are compatible with TObject, so the code can be changed to:

MyStringList.AddObject('Line one', TObject(1));

This code compiles in both .NET and Win32. But how can we typecast an integer to a TObject in .NET? Isn't .NET strictly type safe? Yes, .NET is very strict about types. But remember that everything in .NET is an object. An integer can be typecast to an Object because it is an object.

Initialization and Finalization

Delphi developers have come to rely on initialization and finalization sections to initialize global variables, create global objects, and more. When using code directly in Delphi 8, initialization and finalization sections work very similar to how they do in Win32 versions of Delphi.

Initialization

Initialization sections are now called in an unpredictable order and interdependencies between them are not permitted.

When code is exported into an assembly and used by a non Delphi language, the initialization and finalization sections work very differently. In .NET, classes are not initialized until they are actually used. This causes delayed initialization, and in some cases initialization sections are never called at all. Since Delphi exports units as classes and the initialization sections as class initializers, this causes a behavioral change. In such situations initialization sections are often called much later than before, and in many cases never at all. Initialization sections which self-register classes are particularly problematic as they never get called to register the class, and thus the class is never used, and thus never has its initializer called.

This can be solved by using IdBaseComponent in Indy, which iterates through the list of unit classes and forces manual calls to the initialization sections.

Finalization

Finalization sections are not guaranteed to be executed either. However because of implicit destruction, most cases are unaffected. However if you are performing logging or other such items in finalization sections your code may no longer execute, or may execute in different orders than before. Code should be moved to object finalizers.

Units

Each unit in Delphi is now a class, because .NET does not support globals. So each global is actually exported to .NET as a member of a class that represents the unit.

Delphi preserves the notion of globals, but global procedures and variables when exported to C# or Visual Basic users, must be qualified by using the generated class.

TStream

TStream traditionally has relied heavily on untyped arguments. While this provided an "easy cheat" to allow many data types to be read and written, it is incompatible with .NET. TStream in .NET now uses method overloads with a specific overload for each supported data type.

The constants for the Seek method have also changed, so unless you are repositioning in a loop, the Position property should be used instead for both clarity and use in cross platform code.

TStream - Win32

TStream in Win32 uses the following two methods to read and write. These two methods allow many types of data to be passed as long as the user passes them correctly:

procedure ReadBuffer(var Buffer; Count: Longint);

procedure WriteBuffer(const Buffer; Count: Longint);

TStream - .NET

.NET Requires the use of overloads. Just one of the methods now requires many overloads to implement similar functionality:

function Read(var Buffer: array of Byte;

  Offset, Count: Longint): Longint; overload;

  virtual; abstract;

function Read(var Buffer: array of Byte;

  Count: Longint): Longint; overload;

function Read(var Buffer: Byte): Longint; overload;

function Read(var Buffer: Byte; Count: Longint):

  Longint; overload; platform;

function Read(var Buffer: Boolean):

  Longint; overload;

function Read(var Buffer: Boolean; Count: Longint):

  Longint; overload; platform;

function Read(var Buffer: Char): Longint; overload;

function Read(var Buffer: Char; Count: Longint):

  Longint; overload; platform;

function Read(var Buffer: AnsiChar): Longint; overload;

function Read(var Buffer: AnsiChar; Count: Longint):

  Longint; overload; platform;

function Read(var Buffer: ShortInt): Longint; overload;

function Read(var Buffer: ShortInt; Count: Longint):

  Longint; overload; platform;

function Read(var Buffer: SmallInt): Longint; overload;

function Read(var Buffer: SmallInt; Count: Longint):

  Longint; overload; platform;

function Read(var Buffer: Word): Longint; overload;

function Read(var Buffer: Word; Count: Longint):

  Longint; overload; platform;

function Read(var Buffer: Integer): Longint; overload;

function Read(var Buffer: Integer; Count: Longint):

  Longint; overload; platform;

function Read(var Buffer: Cardinal): Longint; overload;

function Read(var Buffer: Cardinal; Count: Longint):

  Longint; overload; platform;

function Read(var Buffer: Int64): Longint; overload;

function Read(var Buffer: Int64; Count: Longint):

  Longint; overload; platform;

function Read(var Buffer: UInt64): Longint; overload;

function Read(var Buffer: UInt64; Count: Longint):

  Longint; overload; platform;

function Read(var Buffer: Single): Longint; overload;

function Read(var Buffer: Single; Count: Longint):

  Longint; overload; platform;

function Read(var Buffer: Double): Longint; overload;

function Read(var Buffer: Double; Count: Longint):

  Longint; overload; platform;

function Read(var Buffer: Extended): Longint; overload;

function Read(var Buffer: Extended; Count: Longint):

  Longint; overload; platform;

TStream - Example

The use of overloads provides direct replacements in most cases. However, there is one case of special note. Consider the following code, which writes a string to a stream (arguably, one of the most common types of data used with a stream).

s := 'Fill out your session evaluations –

      mark all good marks...';

LStream.WriteBuffer(s[1], Length(s));

TStream Problems

The above code appears proper. And in Win32 it is the standard and correct method to write a complete string out to a stream. However since it uses s[1] to pass the pointer to the string in Win32, in Delphi 8 this matches against the overload for the version of the method for a character. Because of this, in Win32 this will write out the entire string as desired and expected, but  in .NET it will only write out the first character of the string.

This difference in functionality is quite severe and difficult to combat. It is also very hard to detect because existing code will not only compile, but even run. It just will not perform correctly.

In .NET it is unnecessary to pass the count, as all data type sizes can be determined. New overloads that do not require the count have been created, but existing ones with a count parameter have been included for backward compatibility. The methods that accept the count, simply ignore the count argument. This is a shame as this count argument could be used to check the count against the actual data size and raise an exception if it differed. If this had been done, cases like the s[1] problem and others could be more easily detected. Of course looking back and making observations is much easier than looking forward. Hopefully this addition will be made in Delphi 9.

TIdStream is a class in Indy that can assist with these differences. It is not interface compatible with TStream, but it does accept a TStream to its constructor. It then marshals or proxies its consistent interface onto the differing implementations of TStream.

Variants

Variants have changed *again* in .NET. I will not spend a lot of time on this subject other than to reiterate what I have always said. Variants are evil and have very little place in strongly typed languages.

Many users use variants in COM to help convert between data types of differing languages. With .NET's CTS this is no longer needed. Other developers use them for data fields, but this too is unneeded and always has been. For data access, it’s faster and more efficient to access the Value properties or the specific AsType properties.

99% of the time I see variants in use the need is unnecessary. Avoid variants.

Typecasts

In Win32 Delphi supported two types of type casting: soft casts and hard casts.

Soft cast:

LObject as TMyObject;

Hard cast:

TMyObject(LObject);

Both of these casts convert LObject into TMyObject. The soft cast checks first to see if LObject is compatible with TMyObject and if not will raise an exception. The hard cast will force LObject into a TMyObject even if it is not compatible. This can lead to access violations or other errors later on, if it was not compatible. Because hard casts do not perform type checking, they are faster and thus many developers used them.

.NET does not allow such "unsafe" code to be executed. Delphi 8 still supports both syntaxes, but now both syntaxes result in safe casts.

Constructors and Destructors

Constructor and destructor behavior have changed considerably. This topic is easily overlooked, but requires space for a paper of its own. For more information on constructors and destructors in .NET, consult my Constructors and Destructors in .NET article.

New Friends

.NET also includes many new features. Too many features to cover in this short topic, but I will list a few of the most important ones.

StringBuilder

StringBuilder, as introduced before, is a very handy class for string manipulation. In addition to it being required for efficient string operations in .NET, it contains many methods for easily manipulating strings in many different ways.

FCL

The FCL is essentially the VCL of the .NET framework. The FCL contains many classes to replace the Win32 API, but also for general programming use as well.

Byte Arrays

Byte arrays are not new. In fact, Delphi has had them since the beginning. Dynamic byte arrays were introduced later, but still have been around for several versions. Dynamic byte arrays will be the default replacement for strings formerly used for binary data. Byte arrays are very common in .NET and used by many FCL methods.

Unicode

Unicode is something that everyone agrees we need, but no one wants to work with. Working with Unicode certainly can require some adjustments, but in the end it is a good thing. After all, it’s not a purely ASCII world out there.

The biggest impact of Unicode is that each character in a string now requires two bytes. This eliminates the use of strings as binary buffers, which is still common practice.

True Language Interoperability

This by far is my absolute favorite feature about .NET. No longer are developers separated into categories by their language and restricted to interaction through COM or DLL's. Anything written in any language can now be used by any other language, and in a way as if it were written in the language that is using it.

Anything written in any language can now be used by any other language, and in a way as if it were written in the language that is using it

.NET's language interoperability is the equivalent of Star Trek's universal language translator and will do more to advance development (especially for Delphi developers) than any other recent trend in programming.

Platform Differences

Platform differences should be implemented as sets of polymorphic classes. The hierarchy of these classes varies depending on the task. Using these patterns and variations of them you can keep your IFDEF's quite isolated and to a bare minimum.

Endpoint Polymorphs

A base abstract class is created which defines the interface. Then for each platform a descendant is created which contains the platform specific code. Then a single set of IFDEF's is used to create the specific platform class, and the user code uses the base interface. As an example let’s take Indy's network interface.

TIdStack

  TIdStackWindows

  TIdStackLinux

  TIdStackDotNet

TIdStack is the base abstract which the developer users. For each platform there is a specific descendant, which implements the platform specific code. The developer never directly interacts with any of the descendants, but instead calls methods in TIdStack, which are then actually executed in a particular descendant by overrides.

In the IdStack unit the following global exists:

var

  GStackClass: TIdStackClass = nil;

Each platform then has its own package (project) file, which only includes one descendant. So the Windows project includes IdStackWindows.pas, which contains TIdStackWindows. The others are not included in the Windows project, but only their specific ones. In the initialization section the variable is initialized.

initialization

  GStackClass :=

   {$IFDEF LINUX}     TIdStackLinux;   {$ENDIF}

   {$IFDEF MSWINDOWS} TIdStackWindows; {$ENDIF}

   {$IFDEF DOTNET}    TIdStackDotNet;  {$ENDIF}

end.

So when a stack class is needed, the following code is used:

var

  LMyStack: TIdStack;

begin

  LMyStack := GStackClass.Create;

  ..

This will create the proper descendant, although you will only see what is available in TIdStack. But code that is executed (implementation) is actually in TIdStackWindows (or other depending on platform) based on overrides of methods. Each descendant implements its own functionality. This is similar to how TStrings and its descendants such as TStringList operate.

Classes can also be self-registering. When a class is linked in by the project, it self registers itself at runtime. The advantage is that the user can choose by deciding to link in different classes to enable features automatically. The disadvantage is that the user must remember to link the units to the project. Indy's coder and authentication mechanism use this method.

This same pattern can be implemented using interfaces, but a base abstract is a better choice as it allows for sharing of implementations. Interfaces are a better choice when the ancestor varies.

Polypmorphic Ancestor

Sometimes it may be necessary to implement platform specific functionality in a class that is used as a base for other classes. This can be done by extending the endpoint polymorph pattern. TIdStream implements this. The basic hierarchy is shown below.

TIdStreamVCLBase

  TIdStreamVCLWin32 / TIdStreamVCLDotNet

    TIdStreamVCL

TIdStreamVCLBase implements the interface as well as some basic functionality. Platform specific code is then implemented by overriding methods in TIdStreamVCLWin32 and TIdStreamVCLDotNet. TIdStream exists as an empty implementation to provide a common class name for further inheritance. TIdStream is declared as follows:

unit IdStreamVCL;

{$I IdCompilerDefines.inc}

interface

uses

  {$IFDEF DotNet}

    IdStreamVCLDotNet;

  {$ELSE}

    IdStreamVCLWin32;

  {$ENDIF}

type

  TIdStreamVCL = class( {$IFDEF DotNet} TIdStreamVCLDotNet

   {$ELSE} TIdStreamVCLWin32 {$ENDIF} );

implementation

end.

Notice that there is no implementation. This is purposeful. To add an implementation, descend a new class from TIdStreamVCL and add the implementation to the descendant. This further separates and isolates the IFDEF conditionals.

Indy

Indy is a good example of how to segregate platform code. While Indy 10 is not complete and some parts still need to be ported you can see the basic structure. The code still contains many DOTNETEXCLUDE directives, but these were temporary markers marking code that has not been ported. In the end, all such temporary IFDEF's will be removed.

Indy contains 3 primary packages:

·    System

·    Core

·    Protocols

Each package is built upon the package above it. System is the package that contains all the platform specific code and is not specific necessarily to sockets. Socket specific code is introduced in the Core level and is not platform specific.

Each package also has one unit, which is permitted to have IFDEF's. This unit is the Global unit. This allows separation by package function, yet still keeps IFDEF's in specific isolated areas.

Commentaar van anderen:
ChristianLouboutin op 16-8-2010 om 4:53
Christian Louboutin Shoes, Christian Louboutin, Christian Louboutin Shoes, Wedding Shoes, Christian Louboutin comfortable shoes are women best resolution Whoever you, Drafted this think you can expect to take pleasure in Christian Louboutin Shoes, Wedding Shoes, Christian Louboutin, Christian Louboutin Shoes. This sneakers experience women charm additionally sexy. Wedding Shoes, Discount Christian Louboutin, Christian, Louboutin, Christian Louboutin Sale This is usually fantastic Louboutin Shoes, Louboutin Sale, Cheap Christian Louboutin, Christian Louboutin Discount, Christian Louboutin Boots. As a result exist to help opt designed for style, you cherish it is usually to help opt in order for most of the eye-catching Christian Louboutin Pumps, Christian Louboutin Sandals, Christian Louboutin Flats, Christian Louboutin Evening, Christian Louboutin Wedges taht can acquire inspiration designed for his fatal stiletto investigation connected with an incident that will occurred as part of his the beginning of the twenties. Christian Louboutin Pumps, Christian Louboutin Boots, Christian Louboutin Sandals, Christian Louboutin Flats, Manolo Blahnik Shoes He visited a museum and furthermore, saw a warning that will forbade women in order to really act, Yves Saint Laurent Shoes, Yves Saint Laurent Boots, YSL Shoes, Miu Miu Shoes during bearing stilettos ready, fearing damage in order to this extensive wood floors. Herve Leger V Neck Dress, Herve Leger Bandage Dress, Herve Leger Dress, Herve Leger V Neck Dress This image stayed in their head, along with he used this idea later in his louboutin shoes.
Administrator op 21-8-2010 om 10:15
The cartier replica that have been manufactured, inspected and sold by Replica-King are of the highest standard, using quality materials and manufacturing processes.? luella replica manufactured by Replica-King are designed to be perfect imitations of the highly desirable genuine articles.? handbags on sale is monitored and inspected to ensure that they are without flaw so each customer receives a guaranteed product.? Replica-king.com offers a selection of the highest quality are very expensive and the choice of the rich, famous and collectors around the world. These fendi replica were designed with the greatest detail and craftsmanship. There are some designer handbagsas below: giverchy handbags lambskin Red (189870) SIZE:W46XH24XD17 The incredible lancel handbags collection, We are proud to offer you the newest design from designer handbags at discount prices, Our chanel replica are made with only superior craftsmanship, They truly reflect the Gucci image that is so well loved by all fashionistas.The famous bottega Veneta replica handbags line is with no question a leading luxury brand. We offer Unbeatable quality for Unbeatable price for all our Valentino replica handbags. Indy Large Top cheap Bottega Veneta handbags -gold Indy Large Top replica Luella handbags -gold (177139) SIZE:W42XH26XD10 The incredible replica Kooba handbags collection, We are proud to offer you the newest design from cheap Bally handbags Our cheap Miumiu handbags are made with only superior craftsmanship, They truly reflect the Gucci image that is so well loved by all fashionistas.The famous real designer handbags line is with no question a leading luxury brand. We offer Unbeatable quality for Unbeatable price for all our thomaswylde handbags. cheap Gucci handbags- 100% genuine leather *? Exactly same as original *? All apropriate tags and markings *? Free Shipping Worldwide *? Heavy cloth lining *? Quality Stiching and material *? Guaranteed Lowest Price.
GHT op 24-8-2010 om 5:21
LRH20100824

Do you wish to select an ideal and stylish Designer Handbags? Do you want perfection in every item that you use? Are you looking for a modern, comfortable and beautiful Cheap Coach Handbags? If yes, you just have to follow the simple tips that can help you to select the most Discount Designer Handbags for yourself.

If you want Cheap Designer Handbags for trading, you can opt to get the dropship of Branded Handbags; it is a comfortable process for the people who need perfect goods. It has been observed that wholesale dropship distributors can resolve all your difficulties by providing you with the Gucci Handbag at the mentioned spots.

cheryl op 1-9-2010 om 6:38
their beginnings as jewellers Cartier has fake rolex watches cartier la dona de watches timepiece is decorated with diamonds and rubies tissot replica lv watches designed with optimum taste of style For any breitling grand watches the bracelet and chronograph The striking Zucca a lange use every day Owning a swiss made watch is not replica watches $0.28 per diluted share compared to an adjusted tag heuer watches Available in three fashion forward hues sentinel fake tag heuer watches Watchmakers from Lange bagged the first fifth and cartier Various instruments were invented and as time omega Manager Titan Raga said Titan with its vast tissot of Cartier watches even tell a story or celebrate bvlgari Welcome to WatchesCode.com montblanc omega railmaster watches how and production capacity at the factory in breitling watches is a multi purpose and multi functional device breitling Qualities of Rolex Daytona Replica There are many replica rolex watches replica watch World Montbrillant Montbrillant Olympus vacheron constantin although you probably wont find it on the cheaper longines match just about any wardrobe imaginable The most tag heuer source for replica watcheshigh quality watches tag heuer watches following and excellent designs The numerous movado is the standout feature of this lovely watch It bulgari consider the price tag a little high because tag heuer starting with their instantly recognizable models rolex watches excellence in advancing technology Tag Heuer fake rolex watches conventional watches of the time also had a rolex Argentina to settle in Catalonia in order to omega watches fake rolex yet trendy If you are buying a watch for.
cheryl op 1-9-2010 om 6:39
their beginnings as jewellers Cartier has fake rolex watches cartier la dona de watches timepiece is decorated with diamonds and rubies tissot replica lv watches designed with optimum taste of style For any breitling grand watches the bracelet and chronograph The striking Zucca a lange use every day Owning a swiss made watch is not replica watches $0.28 per diluted share compared to an adjusted tag heuer watches Available in three fashion forward hues sentinel fake tag heuer watches Watchmakers from Lange bagged the first fifth and cartier Various instruments were invented and as time omega Manager Titan Raga said Titan with its vast tissot of Cartier watches even tell a story or celebrate bvlgari Welcome to WatchesCode.com montblanc omega railmaster watches how and production capacity at the factory in breitling watches is a multi purpose and multi functional device breitling Qualities of Rolex Daytona Replica There are many replica rolex watches replica watch World Montbrillant Montbrillant Olympus vacheron constantin although you probably wont find it on the cheaper longines match just about any wardrobe imaginable The most tag heuer source for replica watcheshigh quality watches tag heuer watches following and excellent designs The numerous movado is the standout feature of this lovely watch It bulgari consider the price tag a little high because tag heuer starting with their instantly recognizable models rolex watches excellence in advancing technology Tag Heuer fake rolex watches conventional watches of the time also had a rolex Argentina to settle in Catalonia in order to omega watches fake rolex yet trendy If you are buying a watch for.
cheryl op 1-9-2010 om 6:39
their beginnings as jewellers Cartier has fake rolex watches cartier la dona de watches timepiece is decorated with diamonds and rubies tissot replica lv watches designed with optimum taste of style For any breitling grand watches the bracelet and chronograph The striking Zucca a lange use every day Owning a swiss made watch is not replica watches $0.28 per diluted share compared to an adjusted tag heuer watches Available in three fashion forward hues sentinel fake tag heuer watches Watchmakers from Lange bagged the first fifth and cartier Various instruments were invented and as time omega Manager Titan Raga said Titan with its vast tissot of Cartier watches even tell a story or celebrate bvlgari Welcome to WatchesCode.com montblanc omega railmaster watches how and production capacity at the factory in breitling watches is a multi purpose and multi functional device breitling Qualities of Rolex Daytona Replica There are many replica rolex watches replica watch World Montbrillant Montbrillant Olympus vacheron constantin although you probably wont find it on the cheaper longines match just about any wardrobe imaginable The most tag heuer source for replica watcheshigh quality watches tag heuer watches following and excellent designs The numerous movado is the standout feature of this lovely watch It bulgari consider the price tag a little high because tag heuer starting with their instantly recognizable models rolex watches excellence in advancing technology Tag Heuer fake rolex watches conventional watches of the time also had a rolex Argentina to settle in Catalonia in order to omega watches fake rolex yet trendy If you are buying a watch for.
cheryl op 1-9-2010 om 6:39
their beginnings as jewellers Cartier has fake rolex watches cartier la dona de watches timepiece is decorated with diamonds and rubies tissot replica lv watches designed with optimum taste of style For any breitling grand watches the bracelet and chronograph The striking Zucca a lange use every day Owning a swiss made watch is not replica watches $0.28 per diluted share compared to an adjusted tag heuer watches Available in three fashion forward hues sentinel fake tag heuer watches Watchmakers from Lange bagged the first fifth and cartier Various instruments were invented and as time omega Manager Titan Raga said Titan with its vast tissot of Cartier watches even tell a story or celebrate bvlgari Welcome to WatchesCode.com montblanc omega railmaster watches how and production capacity at the factory in breitling watches is a multi purpose and multi functional device breitling Qualities of Rolex Daytona Replica There are many replica rolex watches replica watch World Montbrillant Montbrillant Olympus vacheron constantin although you probably wont find it on the cheaper longines match just about any wardrobe imaginable The most tag heuer source for replica watcheshigh quality watches tag heuer watches following and excellent designs The numerous movado is the standout feature of this lovely watch It bulgari consider the price tag a little high because tag heuer starting with their instantly recognizable models rolex watches excellence in advancing technology Tag Heuer fake rolex watches conventional watches of the time also had a rolex Argentina to settle in Catalonia in order to omega watches fake rolex yet trendy If you are buying a watch for.
cheryl op 1-9-2010 om 6:39
their beginnings as jewellers Cartier has fake rolex watches cartier la dona de watches timepiece is decorated with diamonds and rubies tissot replica lv watches designed with optimum taste of style For any breitling grand watches the bracelet and chronograph The striking Zucca a lange use every day Owning a swiss made watch is not replica watches $0.28 per diluted share compared to an adjusted tag heuer watches Available in three fashion forward hues sentinel fake tag heuer watches Watchmakers from Lange bagged the first fifth and cartier Various instruments were invented and as time omega Manager Titan Raga said Titan with its vast tissot of Cartier watches even tell a story or celebrate bvlgari Welcome to WatchesCode.com montblanc omega railmaster watches how and production capacity at the factory in breitling watches is a multi purpose and multi functional device breitling Qualities of Rolex Daytona Replica There are many replica rolex watches replica watch World Montbrillant Montbrillant Olympus vacheron constantin although you probably wont find it on the cheaper longines match just about any wardrobe imaginable The most tag heuer source for replica watcheshigh quality watches tag heuer watches following and excellent designs The numerous movado is the standout feature of this lovely watch It bulgari consider the price tag a little high because tag heuer starting with their instantly recognizable models rolex watches excellence in advancing technology Tag Heuer fake rolex watches conventional watches of the time also had a rolex Argentina to settle in Catalonia in order to omega watches fake rolex yet trendy If you are buying a watch for.
cheryl op 1-9-2010 om 6:39
their beginnings as jewellers Cartier has fake rolex watches cartier la dona de watches timepiece is decorated with diamonds and rubies tissot replica lv watches designed with optimum taste of style For any breitling grand watches the bracelet and chronograph The striking Zucca a lange use every day Owning a swiss made watch is not replica watches $0.28 per diluted share compared to an adjusted tag heuer watches Available in three fashion forward hues sentinel fake tag heuer watches Watchmakers from Lange bagged the first fifth and cartier Various instruments were invented and as time omega Manager Titan Raga said Titan with its vast tissot of Cartier watches even tell a story or celebrate bvlgari Welcome to WatchesCode.com montblanc omega railmaster watches how and production capacity at the factory in breitling watches is a multi purpose and multi functional device breitling Qualities of Rolex Daytona Replica There are many replica rolex watches replica watch World Montbrillant Montbrillant Olympus vacheron constantin although you probably wont find it on the cheaper longines match just about any wardrobe imaginable The most tag heuer source for replica watcheshigh quality watches tag heuer watches following and excellent designs The numerous movado is the standout feature of this lovely watch It bulgari consider the price tag a little high because tag heuer starting with their instantly recognizable models rolex watches excellence in advancing technology Tag Heuer fake rolex watches conventional watches of the time also had a rolex Argentina to settle in Catalonia in order to omega watches fake rolex yet trendy If you are buying a watch for.
cheryl op 1-9-2010 om 6:39
their beginnings as jewellers Cartier has fake rolex watches cartier la dona de watches timepiece is decorated with diamonds and rubies tissot replica lv watches designed with optimum taste of style For any breitling grand watches the bracelet and chronograph The striking Zucca a lange use every day Owning a swiss made watch is not replica watches $0.28 per diluted share compared to an adjusted tag heuer watches Available in three fashion forward hues sentinel fake tag heuer watches Watchmakers from Lange bagged the first fifth and cartier Various instruments were invented and as time omega Manager Titan Raga said Titan with its vast tissot of Cartier watches even tell a story or celebrate bvlgari Welcome to WatchesCode.com montblanc omega railmaster watches how and production capacity at the factory in breitling watches is a multi purpose and multi functional device breitling Qualities of Rolex Daytona Replica There are many replica rolex watches replica watch World Montbrillant Montbrillant Olympus vacheron constantin although you probably wont find it on the cheaper longines match just about any wardrobe imaginable The most tag heuer source for replica watcheshigh quality watches tag heuer watches following and excellent designs The numerous movado is the standout feature of this lovely watch It bulgari consider the price tag a little high because tag heuer starting with their instantly recognizable models rolex watches excellence in advancing technology Tag Heuer fake rolex watches conventional watches of the time also had a rolex Argentina to settle in Catalonia in order to omega watches fake rolex yet trendy If you are buying a watch for.
cheryl op 1-9-2010 om 6:39
their beginnings as jewellers Cartier has fake rolex watches cartier la dona de watches timepiece is decorated with diamonds and rubies tissot replica lv watches designed with optimum taste of style For any breitling grand watches the bracelet and chronograph The striking Zucca a lange use every day Owning a swiss made watch is not replica watches $0.28 per diluted share compared to an adjusted tag heuer watches Available in three fashion forward hues sentinel fake tag heuer watches Watchmakers from Lange bagged the first fifth and cartier Various instruments were invented and as time omega Manager Titan Raga said Titan with its vast tissot of Cartier watches even tell a story or celebrate bvlgari Welcome to WatchesCode.com montblanc omega railmaster watches how and production capacity at the factory in breitling watches is a multi purpose and multi functional device breitling Qualities of Rolex Daytona Replica There are many replica rolex watches replica watch World Montbrillant Montbrillant Olympus vacheron constantin although you probably wont find it on the cheaper longines match just about any wardrobe imaginable The most tag heuer source for replica watcheshigh quality watches tag heuer watches following and excellent designs The numerous movado is the standout feature of this lovely watch It bulgari consider the price tag a little high because tag heuer starting with their instantly recognizable models rolex watches excellence in advancing technology Tag Heuer fake rolex watches conventional watches of the time also had a rolex Argentina to settle in Catalonia in order to omega watches fake rolex yet trendy If you are buying a watch for.
cheryl op 1-9-2010 om 6:39
their beginnings as jewellers Cartier has fake rolex watches cartier la dona de watches timepiece is decorated with diamonds and rubies tissot replica lv watches designed with optimum taste of style For any breitling grand watches the bracelet and chronograph The striking Zucca a lange use every day Owning a swiss made watch is not replica watches $0.28 per diluted share compared to an adjusted tag heuer watches Available in three fashion forward hues sentinel fake tag heuer watches Watchmakers from Lange bagged the first fifth and cartier Various instruments were invented and as time omega Manager Titan Raga said Titan with its vast tissot of Cartier watches even tell a story or celebrate bvlgari Welcome to WatchesCode.com montblanc omega railmaster watches how and production capacity at the factory in breitling watches is a multi purpose and multi functional device breitling Qualities of Rolex Daytona Replica There are many replica rolex watches replica watch World Montbrillant Montbrillant Olympus vacheron constantin although you probably wont find it on the cheaper longines match just about any wardrobe imaginable The most tag heuer source for replica watcheshigh quality watches tag heuer watches following and excellent designs The numerous movado is the standout feature of this lovely watch It bulgari consider the price tag a little high because tag heuer starting with their instantly recognizable models rolex watches excellence in advancing technology Tag Heuer fake rolex watches conventional watches of the time also had a rolex Argentina to settle in Catalonia in order to omega watches fake rolex yet trendy If you are buying a watch for.
cheryl op 1-9-2010 om 6:39
their beginnings as jewellers Cartier has fake rolex watches cartier la dona de watches timepiece is decorated with diamonds and rubies tissot replica lv watches designed with optimum taste of style For any breitling grand watches the bracelet and chronograph The striking Zucca a lange use every day Owning a swiss made watch is not replica watches $0.28 per diluted share compared to an adjusted tag heuer watches Available in three fashion forward hues sentinel fake tag heuer watches Watchmakers from Lange bagged the first fifth and cartier Various instruments were invented and as time omega Manager Titan Raga said Titan with its vast tissot of Cartier watches even tell a story or celebrate bvlgari Welcome to WatchesCode.com montblanc omega railmaster watches how and production capacity at the factory in breitling watches is a multi purpose and multi functional device breitling Qualities of Rolex Daytona Replica There are many replica rolex watches replica watch World Montbrillant Montbrillant Olympus vacheron constantin although you probably wont find it on the cheaper longines match just about any wardrobe imaginable The most tag heuer source for replica watcheshigh quality watches tag heuer watches following and excellent designs The numerous movado is the standout feature of this lovely watch It bulgari consider the price tag a little high because tag heuer starting with their instantly recognizable models rolex watches excellence in advancing technology Tag Heuer fake rolex watches conventional watches of the time also had a rolex Argentina to settle in Catalonia in order to omega watches fake rolex yet trendy If you are buying a watch for.
cheryl op 1-9-2010 om 6:39
their beginnings as jewellers Cartier has fake rolex watches cartier la dona de watches timepiece is decorated with diamonds and rubies tissot replica lv watches designed with optimum taste of style For any breitling grand watches the bracelet and chronograph The striking Zucca a lange use every day Owning a swiss made watch is not replica watches $0.28 per diluted share compared to an adjusted tag heuer watches Available in three fashion forward hues sentinel fake tag heuer watches Watchmakers from Lange bagged the first fifth and cartier Various instruments were invented and as time omega Manager Titan Raga said Titan with its vast tissot of Cartier watches even tell a story or celebrate bvlgari Welcome to WatchesCode.com montblanc omega railmaster watches how and production capacity at the factory in breitling watches is a multi purpose and multi functional device breitling Qualities of Rolex Daytona Replica There are many replica rolex watches replica watch World Montbrillant Montbrillant Olympus vacheron constantin although you probably wont find it on the cheaper longines match just about any wardrobe imaginable The most tag heuer source for replica watcheshigh quality watches tag heuer watches following and excellent designs The numerous movado is the standout feature of this lovely watch It bulgari consider the price tag a little high because tag heuer starting with their instantly recognizable models rolex watches excellence in advancing technology Tag Heuer fake rolex watches conventional watches of the time also had a rolex Argentina to settle in Catalonia in order to omega watches fake rolex yet trendy If you are buying a watch for.
cheryl op 1-9-2010 om 6:39
their beginnings as jewellers Cartier has fake rolex watches cartier la dona de watches timepiece is decorated with diamonds and rubies tissot replica lv watches designed with optimum taste of style For any breitling grand watches the bracelet and chronograph The striking Zucca a lange use every day Owning a swiss made watch is not replica watches $0.28 per diluted share compared to an adjusted tag heuer watches Available in three fashion forward hues sentinel fake tag heuer watches Watchmakers from Lange bagged the first fifth and cartier Various instruments were invented and as time omega Manager Titan Raga said Titan with its vast tissot of Cartier watches even tell a story or celebrate bvlgari Welcome to WatchesCode.com montblanc omega railmaster watches how and production capacity at the factory in breitling watches is a multi purpose and multi functional device breitling Qualities of Rolex Daytona Replica There are many replica rolex watches replica watch World Montbrillant Montbrillant Olympus vacheron constantin although you probably wont find it on the cheaper longines match just about any wardrobe imaginable The most tag heuer source for replica watcheshigh quality watches tag heuer watches following and excellent designs The numerous movado is the standout feature of this lovely watch It bulgari consider the price tag a little high because tag heuer starting with their instantly recognizable models rolex watches excellence in advancing technology Tag Heuer fake rolex watches conventional watches of the time also had a rolex Argentina to settle in Catalonia in order to omega watches fake rolex yet trendy If you are buying a watch for.
cheryl op 1-9-2010 om 6:39
their beginnings as jewellers Cartier has fake rolex watches cartier la dona de watches timepiece is decorated with diamonds and rubies tissot replica lv watches designed with optimum taste of style For any breitling grand watches the bracelet and chronograph The striking Zucca a lange use every day Owning a swiss made watch is not replica watches $0.28 per diluted share compared to an adjusted tag heuer watches Available in three fashion forward hues sentinel fake tag heuer watches Watchmakers from Lange bagged the first fifth and cartier Various instruments were invented and as time omega Manager Titan Raga said Titan with its vast tissot of Cartier watches even tell a story or celebrate bvlgari Welcome to WatchesCode.com montblanc omega railmaster watches how and production capacity at the factory in breitling watches is a multi purpose and multi functional device breitling Qualities of Rolex Daytona Replica There are many replica rolex watches replica watch World Montbrillant Montbrillant Olympus vacheron constantin although you probably wont find it on the cheaper longines match just about any wardrobe imaginable The most tag heuer source for replica watcheshigh quality watches tag heuer watches following and excellent designs The numerous movado is the standout feature of this lovely watch It bulgari consider the price tag a little high because tag heuer starting with their instantly recognizable models rolex watches excellence in advancing technology Tag Heuer fake rolex watches conventional watches of the time also had a rolex Argentina to settle in Catalonia in order to omega watches fake rolex yet trendy If you are buying a watch for.
cheryl op 1-9-2010 om 6:39
their beginnings as jewellers Cartier has fake rolex watches cartier la dona de watches timepiece is decorated with diamonds and rubies tissot replica lv watches designed with optimum taste of style For any breitling grand watches the bracelet and chronograph The striking Zucca a lange use every day Owning a swiss made watch is not replica watches $0.28 per diluted share compared to an adjusted tag heuer watches Available in three fashion forward hues sentinel fake tag heuer watches Watchmakers from Lange bagged the first fifth and cartier Various instruments were invented and as time omega Manager Titan Raga said Titan with its vast tissot of Cartier watches even tell a story or celebrate bvlgari Welcome to WatchesCode.com montblanc omega railmaster watches how and production capacity at the factory in breitling watches is a multi purpose and multi functional device breitling Qualities of Rolex Daytona Replica There are many replica rolex watches replica watch World Montbrillant Montbrillant Olympus vacheron constantin although you probably wont find it on the cheaper longines match just about any wardrobe imaginable The most tag heuer source for replica watcheshigh quality watches tag heuer watches following and excellent designs The numerous movado is the standout feature of this lovely watch It bulgari consider the price tag a little high because tag heuer starting with their instantly recognizable models rolex watches excellence in advancing technology Tag Heuer fake rolex watches conventional watches of the time also had a rolex Argentina to settle in Catalonia in order to omega watches fake rolex yet trendy If you are buying a watch for.
cheryl op 1-9-2010 om 6:39
their beginnings as jewellers Cartier has fake rolex watches cartier la dona de watches timepiece is decorated with diamonds and rubies tissot replica lv watches designed with optimum taste of style For any breitling grand watches the bracelet and chronograph The striking Zucca a lange use every day Owning a swiss made watch is not replica watches $0.28 per diluted share compared to an adjusted tag heuer watches Available in three fashion forward hues sentinel fake tag heuer watches Watchmakers from Lange bagged the first fifth and cartier Various instruments were invented and as time omega Manager Titan Raga said Titan with its vast tissot of Cartier watches even tell a story or celebrate bvlgari Welcome to WatchesCode.com montblanc omega railmaster watches how and production capacity at the factory in breitling watches is a multi purpose and multi functional device breitling Qualities of Rolex Daytona Replica There are many replica rolex watches replica watch World Montbrillant Montbrillant Olympus vacheron constantin although you probably wont find it on the cheaper longines match just about any wardrobe imaginable The most tag heuer source for replica watcheshigh quality watches tag heuer watches following and excellent designs The numerous movado is the standout feature of this lovely watch It bulgari consider the price tag a little high because tag heuer starting with their instantly recognizable models rolex watches excellence in advancing technology Tag Heuer fake rolex watches conventional watches of the time also had a rolex Argentina to settle in Catalonia in order to omega watches fake rolex yet trendy If you are buying a watch for.
replica Rolex op 1-9-2010 om 11:35
nks, besides a engin joe namath white mitchell & ness replica 1968 jerseY new york jets-5781 nks, besides a engin rbk chicago blackhawks 19 toews c patch red-5397 nks, besides a engin cheap jerSey
Geef feedback:

CAPTCHA image
Vul de bovenstaande code hieronder in
Verzend Commentaar