I am absolutely new at calling functions from DLLs (call it bad programming habits, but I never needed to).
I have this C++ dll (CidGen32.dll at https://skydrive.live.com/redir?resid=4FA1892BF2106B62!1066) that is supposed to export a function with the following signature:
extern "C" __declspec(dllexport) int GetCid(const char* pid, char* cid);
What it should do is to get a 13 char string such as '1111111111118' and return a 20 char hash.
I have tried for the last couple of days to call this function in Delphi 6 but to no avail. I have desperately tried I guess 50+ combinations and I got quite close on one occasion but my computer froze and I lost all my effort. Since it was based on luck, I could not redo it anymore.
I am also aiming not to register the DLL, but rather place it in the same folder.
Anyway, the plan was to have something like this:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
function GenerateCID(Prm: string): string;
var
aCID: PAnsiChar;
uCID: AnsiString;
i: integer;
Hbar: Thandle;
GetCID: function (X: PAnsiChar; Y: PAnsiChar): integer; {$IFDEF WIN32} stdcall; {$ENDIF}
begin
ucid := '';
hbar := LoadLibrary('CidGen32.dll');
if Hbar >= 32 then
begin
#GetCID := GetProcAddress(HBar, 'GetCID');
if Assigned(GetCID) then
begin
i := GetCID(pAnsiChar(prm), aCID);
uCID := aCID;
end;
FreeLibrary(HBar);
end
else
begin
//ShowMessage('Error: could not find dll');
end;
result := uCID;
end;
begin
ShowMessage(GenerateCID('1111111111118'));
end;
end.
But it seems I am dead wrong.
You are using the wrong name to import the function. Its name is GetCid but you are trying to import GetCID. Letter case matters when you call GetProcAddress. If that still doesn't result in the GetProcAddress call succeeding, double check the name with which the function is exported using a tool like Dependency Walker.
The function is cdecl so you should declare it like this:
GetCID: function(pid, cid: PAnsiChar): Integer; cdecl;
And the other problem is that you are responsible for allocating the buffer behind cid. You did not do that. Do it like this:
SetLength(uCID, 20);
i := GetCID(pAnsiChar(prm), pAnsiChar(uCID));
And delete the aCID variable. And that >32 error check is wrong, compare against 0.
Related
hello i try load dll into memory and play sound file from resources (Delphi2009). In this example i load dll from HDD to memory (i plan to load dll from resources to memory) but i got an error after Button1Click
First chance exception at $76E2C41F. Exception class EAccessViolation with message 'Access violation at address 00000000. Read of address 00000000'. Process DemoApp.exe (3020)
Sound doesn't play at all :/
some of code i used from here: http://www.cyberforum.ru/blogs/14360/blog1682.html#a_codemodez
but i couldn't compile it due to custom units strUtilz, MemModuleUnicode
BTMemoryModule v0.0.41 includes BTMemoryModule and also examples
http://code.google.com/p/memorymodule/downloads/list
BTMemoryModule v.1 (old probably) (with BTMemoryModule + BTMemoryModuleUnicode)
http://www.delphibasics.info/home/delphibasicssnippets/btmemorymodule
unit Main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, BTMemoryModule, StdCtrls, xpman;
const // Constants :::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::
_s = '';
_n=#13#10; // line break
ver = '1.0 '; // Articles
tit = 'Bass Memory App' + ver; // title - the name of the application
msgYN=$04; msgERR=$10; msgINF=$40; // <-type codes posts
res1='dll'; // resource name with dllkoy
res2='snd'; // name of the resource with sound
type // TYPES :::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::
MemRes = record // structure for the projection of the resource in memory
p: pointer; // pointer to the memory
sz: int64; // size (length)
rd: cardinal; // hResData
ri: cardinal; // hResInfo
end;
type
TBASS_ChannelPlay = function (handle: cardinal; restart: bool): bool; stdcall;
TBASS_StreamCreateFile = function (mem: bool; f: Pointer; offset, length: int64; flags: cardinal): cardinal; stdcall;
TBASS_StreamFree = function (handle: cardinal): bool; stdcall;
TBASS_Init = function (device: integer; freq, flags: cardinal; win: cardinal; clsid: pGUID): bool; stdcall;
TBASS_Free = function: bool; stdcall;
TForm1 = class(TForm)
BtnFileCAll: TButton;
BtnMemCall: TButton;
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
mp_DllData : Pointer;
m_DllDataSize : Integer;
mp_MemoryModule: PBTMemoryModule;
//m_DllHandle: Cardinal;
m_BASS_ChannelPlay: TBASS_ChannelPlay;
m_BASS_StreamCreateFile: TBASS_StreamCreateFile;
//m_BASS_StreamFree: TBASS_StreamFree;
m_BASS_Init: TBASS_Init;
//m_BASS_Free: TBASS_Free;
public
{ Public declarations }
end;
var
Form1: TForm1;
wnd: cardinal; // window handle
ss: cardinal; // handle audio stream
snd: MemRes; // pointer to the audio file in memory
dll: MemRes; // pointer to memory dllku
bass: Pointer; // structure projection dll in memory
stp: word; // execution step (for debug)
st: boolean; // status of the audio stream
th: cardinal; // handle the flow of replacement buttons
ti: cardinal; // id flow
ms : TMemoryStream;
rs : TResourceStream;
implementation
{$R *.dfm}
{$R BassMem.RES} // snd CookieJarLoop.ogg RCData
function Res2Mem(hInst:cardinal;res:string;rtype:pChar):MemRes;
begin
result.p:=nil;
result.ri:=FindResource(hInst,pchar(res),rtype);
if result.ri=0 then exit;
result.sz:=SizeOfResource(hInst,result.ri);
if result.sz=0 then exit;
result.rd:=LoadResource(hInst,result.ri);
if result.rd=0 then exit;
result.p:=LockResource(result.rd);
end;
procedure TForm1.FormCreate(Sender: TObject);
var
MemoryStream: TMemoryStream;
begin
Position := poScreenCenter;
MemoryStream := TMemoryStream.Create;
MemoryStream.LoadFromFile('bass.dll');
MemoryStream.Position := 0;
m_DllDataSize := MemoryStream.Size;
mp_DllData := GetMemory(m_DllDataSize);
MemoryStream.Read(mp_DllData^, m_DllDataSize);
MemoryStream.Free;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FreeMemory(mp_DllData);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
mp_MemoryModule := BTMemoryLoadLibary(mp_DllData, m_DllDataSize);
try
if mp_MemoryModule = nil then showmessage('err1');
#m_BASS_Init := BTMemoryGetProcAddress(mp_MemoryModule, 'BASS_Init');
if #m_BASS_Init = nil then showmessage('err2');
#m_BASS_ChannelPlay := BTMemoryGetProcAddress(mp_MemoryModule, 'BASS_ChannelPlay');
if #m_BASS_ChannelPlay = nil then showmessage('err3');
m_BASS_Init(-1, 44100, 0, Handle, nil);
snd:=Res2Mem(hInstance, res2 ,RT_RCDATA);
ss:=m_BASS_StreamCreateFile(true,snd.p,0,snd.sz,4{=BASS_SAMPLE_LOOP});
if ss=0 then showmessage('err ss=0');
m_BASS_ChannelPlay(ss, false);
except
Showmessage('An error occoured while loading the dll: ' + BTMemoryGetLastError);
end;
if mp_MemoryModule <> nil then BTMemoryFreeLibrary(mp_MemoryModule);
end;
end.
You do not initialise m_BASS_StreamCreateFile. Consequently it has the value nil when you call it. Which explains the error message.
You need to add a call to BTMemoryGetProcAddress to initialise m_BASS_StreamCreateFile.
#m_BASS_StreamCreateFile := BTMemoryGetProcAddress(mp_MemoryModule,
'BASS_StreamCreateFile');
if #m_BASS_StreamCreateFile = nil then ....
This would have been simple enough to discover had you run the code under the debugger. The exception would have been trapped by the debugger and the call stack will have led to the call of m_BASS_StreamCreateFile. You could then have inspected its value to discover that it was nil.
Well, first of all: Nafalem, your code is terrible =\
As David Heffernan said before - there are missing initialization for m_BASS_StreamCreateFile; but also: what did you expected to do with if mp_MemoryModule <> nil then MemFreeLibrary(mp_MemoryModule); just right after m_BASS_ChannelPlay???
Just think a bit - you starting to play sound and then removing library from memory...
You need to move MemFreeLibrary into FormDestory before FreeMemory(mp_DllData);.
But sadly, even fixing your code isn't enough to make it work.
As i said in my article (http://www.cyberforum.ru/blogs/14360/blog1682.html (sry, i'm too lazy to translate it to English)):
there are a bug inside the BTMemoryModule:
if (l_section.Characteristics and IMAGE_SCN_MEM_DISCARDABLE) <> 0 then begin
// section is not needed any more and can safely be freed
VirtualFree(Pointer(l_section.Misc.PhysicalAddress), l_section.SizeOfRawData, MEM_DECOMMIT);
inc(longword(l_section), sizeof(TImageSectionHeader));
continue;
end;
this part of code frees sections with enabled Discardable-flag, but it shouldn't be done in our case!
As you can find in msdn, discardable-flag means that section can be discarded as needed, as you see it CAN be discarded, not MUST be... and it's for physical PE-files, which could be readed from file on demand!
If speak more bout this, Discardable-flag was used in 16-bit Windows and it was saying that its contents may be not uploaded into the swap, and readed from a file, if necessary. In the 32-bit Win OS and higher versions system looks priorly at IMAGE_SCN_MEM_NOT_PAGED, so just leave discardable-flag to low-core driver development, and never use it in user-mode PE-modules.
P.S. >
i couldn't compile it due to custom units strUtilz, MemModuleUnicode
just download archive from my article, it contains MemModule with my fixes, as to strUtilz - just replace it with SysUtils, i wrote in comments that it's simply a module with str/int conversion-routines coded in asm.
//Sorry for my dirty English =P
Delphi XE. Windows 7.
There is a function (please see a code below) or I:=0 that causes an AV error in a big project. There is no the error with the same function in a new project!!! I deleted everything from the big project, and I left only a button and that function. It still causes the error...
A line with the error:
if ISAeroEnabled then // this line is a cause
i:=0; // or this line
I set breakpoints everywhere (I checked the whole function, I set breakpoints on EACH LINE -> no errors in the function), a debugger shows me that the error is in i:=0;
If to delete a function (and leave i:=0;) -> all is ok!
The error message: First chance exception at $747FB727. Exception class EAccessViolation with message 'Access violation at address 004AE5AF in module 'MngProject.exe'. Write of address 0017FFF8'. Process MngProject.exe (4980)
Why does it work in a new project but not in mine?
Here's the whole project: http://www.2shared.com/file/UP22Om4j/Bug.html
The code:
unit MainFormModule;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
StdCtrls;
type
TMainForm = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
mainform:tmainform;
implementation
{$R *.dfm}
function ISAeroEnabled: Boolean;
type
_DwmIsCompositionEnabledFunc = function(IsEnabled: PBoolean): HRESULT; stdcall;
var
Flag : Boolean;
DllHandle : THandle;
OsVersion : TOSVersionInfo;
DwmIsCompositionEnabledFunc: _DwmIsCompositionEnabledFunc;
begin
Result:=False;
ZeroMemory(#OsVersion, SizeOf(OsVersion));
OsVersion.dwOSVersionInfoSize := SizeOf(TOSVERSIONINFO);
if ((GetVersionEx(OsVersion)) and (OsVersion.dwPlatformId = VER_PLATFORM_WIN32_NT) and (OsVersion.dwMajorVersion >= 6)) then //is Vista or Win7?
begin
DllHandle := LoadLibrary('dwmapi.dll');
if DllHandle <> 0 then
begin
#DwmIsCompositionEnabledFunc := GetProcAddress(DllHandle, 'DwmIsCompositionEnabled');
if (#DwmIsCompositionEnabledFunc <> nil) then
begin
DwmIsCompositionEnabledFunc(#Flag);
Result:=Flag;
end;
end;
FreeLibrary(DllHandle);
end;
end;
procedure Tmainform.Button1Click(Sender: TObject);
var i:integer;
begin
if ISAeroEnabled then // AV is here
i:=0; // Or here
end;
end.
Try changing PBoolean to PBOOL
function(IsEnabled: PBOOL): HRESULT; stdcall;
var
Flag: BOOL;
PBoolean is a pointer to a Pascal Boolean which is 1 byte in size. PBOOL is a pointer to a Windows (C based) BOOL, which is 4 bytes in size. You need to match the size expected by windows.
In general, when translating Windows API calls to Delphi, use the same named data type as the API. Windows.pas has type definitions mapping these to Delphi types, e.g. type BOOL = LongBool;
Also it is usual (but not required) in Delphi to change pointer parameters to var. A var parameter is Pascal syntactic sugar for pass-by-reference which isn't available in C.
function(var IsEnabled: BOOL): HRESULT; stdcall;
....
DwmIsCompositionEnabledFunc(Flag); // no # operator
NOTE: I can't test this, as I only have XP available.
I need to use a DLL file from qsBarcode http://www.qsbarcode.de/en/index.htm (here is the download link http://www.qsbarcode.de/en/download/qsbar39.zip). The dll will decode a bitmap image that contain barcode code39 into a string.
In their example there are only VB and C example, but I need to use it in Delphi.
here is the official example code in C:
#include <windows.h>
#include <stdio.h>
typedef int (WINAPI * CODE39_PROC)(char *, char *);
int main(int argc, char* argv[])
{
HINSTANCE hinstLib;
CODE39_PROC ProcAdd;
BOOL fFreeResult;
char cFileName[512] = "\0";
char cResult[512] = "\0";
int iReturn = 0;
if(argc < 2) return 0; //no bitmap filename in argv[1]
strcpy(cFileName,argv[1]);
hinstLib = LoadLibrary("qsBar39");
if (hinstLib == NULL) return -1; //can't load lib
ProcAdd = (CODE39_PROC) GetProcAddress(hinstLib, "ReadCode39");
if (NULL == ProcAdd) return -1; //can't access Proc
//dll Proc call
iReturn = (ProcAdd) (cFileName, cResult);
printf("%s", cResult);
fFreeResult = FreeLibrary(hinstLib);
return iReturn;
}
and this is what I try to code in Delphi
unit uRead;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Mask, JvExMask, JvToolEdit;
type
TDLLFunc = function(namafile: PChar; hasil:PChar):integer;
TForm2 = class(TForm)
JvFilenameEdit1: TJvFilenameEdit;
Edit1: TEdit;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
const
DLLFunc: TDLLFunc = nil;
var
Form2: TForm2;
DLLHandle: THandle;
implementation
{$R *.dfm}
procedure TForm2.Button1Click(Sender: TObject);
var
feedback : integer;
hasil:PChar;
begin
DLLHandle := LoadLibrary('qsBar39.dll');
if (DLLHandle < HINSTANCE_ERROR) then
raise Exception.Create('library can not be loaded or not found. ' + SysErrorMessage(GetLastError));
try
{ load an address of required procedure}
#DLLFunc := GetProcAddress(DLLHandle, 'ReadCode39');
{if procedure is found in the dll}
if Assigned(DLLFunc) then
feedback := DLLFunc(PChar(JvFilenameEdit1.Text), PChar(hasil));
showmessage(hasil);
finally
{unload a library}
FreeLibrary(DLLHandle);
end;
end;
end.
When I execute this code and debug, hasil only contains #$11'½
while it should return some character in the barcode image (you can get the file image in the zip file).
Please help me, thank you.
latest update:
#500, thanks, I have put stdcall
#dthorpe, thanks, done
Actually the advice is great, my code is supposed to running well, but I've mistakenly put JvFilenameEdit1.text instead of JvFilenameEdit1.FileName, my bad :)
Thank you again for the advice, so here is the working code:
unit uRead;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Mask, JvExMask, JvToolEdit;
type
TDLLFunc = function(namafile: PAnsiChar; hasil:PAnsiChar):integer; stdcall;
TForm2 = class(TForm)
JvFilenameEdit1: TJvFilenameEdit;
Edit1: TEdit;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
const
DLLFunc: TDLLFunc = nil;
var
Form2: TForm2;
DLLHandle: THandle;
implementation
{$R *.dfm}
procedure TForm2.Button1Click(Sender: TObject);
var
feedback : integer;
hasil: array [0..512] of char;
begin
DLLHandle := LoadLibrary('qsBar39.dll');
if (DLLHandle < HINSTANCE_ERROR) then
raise Exception.Create('library can not be loaded or not found. ' + SysErrorMessage(GetLastError));
try
{ load an address of required procedure}
#DLLFunc := GetProcAddress(DLLHandle, 'ReadCode39');
{if procedure is found in the dll}
if Assigned(DLLFunc) then
feedback := DLLFunc(PAnsiChar(JvFilenameEdit1.FileName), #hasil);
edit1.Text := StrPas(#hasil);
finally
{unload a library}
FreeLibrary(DLLHandle);
end;
end;
end.
If I were you I would take the opportunity to wrap this function call up in a more Delphi like wrapper.
function ReadCode39(FileName, Result: PAnsiChar): LongBool; stdcall;
external 'qsBar39';
function ReadCode(const FileName: string): string;
var
cResult: array [0..512-1] of AnsiChar;
begin
if not ReadCode39(PAnsiChar(AnsiString(FileName)), #cResult[0]) then
raise Exception.Create('ReadCode39 failed');
Result := string(cResult);
end;
Notes:
I'm using an implicit DLL import (using external) rather than an explicit GetProcAddress. This reduces the amount of boilerplate code considerably.
I'm converting the C style integer code error handling into a Delphi exception. Based on your comment I'm guessing that a non-zero return value means success. Older versions of C do not have a boolean type and use 0 to mean false and every non-zero value evaluates as true. The natural way to map this to a Delphi boolean type is with LongBool. This means that your calling code doesn't need to worry about error codes.
All the conversion to and from null-terminated strings is handled in one routine and your calling code again need not concern itself over such trivia.
I've written the code so that it is portable between both ANSI and Unicode versions of Delphi.
This allows your calling code to read much more clearly:
procedure TForm2.Button1Click(Sender: TObject);
var
hasil: string;
begin
hasil := ReadCode(JvFilenameEdit1.Text);
ShowMessage(hasil);
end;
Stick a stdcall; directive at the end of your TDLLFunc declaration to tell the compiler that it's using the WINAPI calling convention, and, as Dorin points out, if you're using a unicode-based version of Delphi you probably want to use PAnsiChar.
In addition to the stdcall mentioned in another answer, you also need to allocate space for the pchar pointers you're passing into the DLLFunc. Notice that in the C code the cResult var is defined as char cResult[512]; That means the caller is reserving space for a char buffer of 512 chars and passing the address of that buffer to the DLL func.
You're not doing the equivalent in your Delphi code.
Change your Delphi code to define hasil as an array of char:
var hasil: array [0..512] of char;
then pass the address of hasil to the DLLFunc call:
DLLFunc(PChar(JvFilenameEdit1.Text), #hasil);
I am having a problem passing a class reference as the parameter to the ThreadProc in a call to CreateThread. Here is a sample program that demonstrates the problem I am having:
program test;
{$APPTYPE CONSOLE}
uses
SysUtils, Windows, Dialogs;
type
TBlah = class
public
fe: Integer;
end;
function ThreadProc(param: Pointer) : DWORD;
begin
ShowMessage(IntToStr(TBlah(param).fe));
Result := 0;
end;
var
tID: DWORD;
handle: THandle;
b: TBlah;
begin
b := TBlah.Create;
b.fe := 54;
handle := CreateThread(nil, 0, #ThreadProc, Pointer(b), 0, tID);
WaitForSingleObject(handle, INFINITE);
end.
The call to ShowMessage pops up a message box that has something like 245729105 in it, not 54 like I expect.
This is probably just a basic misunderstanding of how Delphi works, so could someone please tell me how to get this working properly?
The problem here is that your thread function has the wrong calling convention. You need to declare it with the stdcall convention:
function ThreadProc(param: Pointer) : DWORD; stdcall;
Having said that, it would be more idiomatic to just use a TThread descendant which handles the OOP to C function back to OOP transitioning for you. That would look like this:
type
TBlah = class(TThread)
protected
procedure Execute; override;
public
fe: Integer;
end;
procedure TBlah.Execute;
begin
ShowMessage(IntToStr(fe));
end;
var
b: TBlah;
begin
b := TBlah.Create(True);
b.fe := 42;
b.Start;
b.WaitFor;
end.
Incidentally, does anyone know why Windows.pas declares TFNThreadStartRoutine as TFarProc rather than a proper typed function pointer?
You're forgetting the stdcall directive.
function ThreadProc(param: Pointer) : DWORD; stdcall;
And don't use Pointer cast in:
handle := CreateThread(nil, 0, #ThreadProc, **Pointer**(b), 0, tID);
b is already a Pointer (a Class, which is an Object Pointer)
Is there any way with the current delphi to implement.
a) String (as a class) with operator overloads (ie. +, =)
b) Class Helper's so one could add custom string methods
I gather the string is a native type so class helpers will not work without
setting up a class etc.
Yes, string is a native type with some special compiler magic added.
I don't know what operator overloading you would want. + and = already work as concatenation and equality operators.
However I've thought about doing something similar myself. It might work with a record type with implicit convertors and overloaded add and equals operators (in Win32 Delphi only records can have operator overloading. This is available in D2006 (?2005) only.)
I suspect there may be some performance hit as well.
The syntax would be something like the following:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TString = record
private
Value : string;
public
class operator Add(a, b: TString): TString;
class operator Implicit(a: Integer): TString;
class operator Implicit(const s: string): TString;
class operator Implicit(ts: TString): String;
function IndexOf(const SubStr : string) : Integer;
end;
var
Form1: TForm1;
implementation
class operator TString.Add(a, b : TString) : TString;
begin
Result.Value := a.Value + b.Value;
end;
class operator TString.Implicit(a: Integer): TString;
begin
Result.Value := IntToStr(a);
end;
class operator TString.Implicit(ts: TString): String;
begin
Result := ts.Value;
end;
function TString.IndexOf(const SubStr : string) : Integer;
begin
Result := Pos(SubStr, Value);
end;
class operator TString.Implicit(const s: string): TString;
begin
Result.Value := s;
end;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
ts : TString;
begin
ts := '1234';
ShowMessage(ts);
ShowMessage(IntToStr(Ts.IndexOf('2')));
end;
end.
Apparently you can have "record helpers" as well, but I've never tried it myself.
You can use operator overloading in Delphi (since Delphi 2006) only on records not on classes, and not on built-in native types like strings.
The reason is that Delphi does not have garbage collection, so operator overloading is limited to value types (types that are not living on the heap).
You can download the replay of my session "Nullable Types with Records, Methods and Operator Overloading" at the CodeRage III Replay download page.
Just search for the session name.
There is also a page with the download for the session samples and slides.
It contains quite a few examples that get you going, including a description of some issues in the Delphi 2006 compiler that have been solved in Delphi 2007 and up.
See also this question: Can I overload operators for my own classes in Delphi?
Isn't a better solution to write your custom functions / procedures?
For example
Function StrToBase64(AString): string;
Procedure StrToGridLayout(AString: string; AGrid: TDBGrid);
Function ExtractWord(aString): string;
Function GetStrColumn(aString: string; aCol: integer): string;
And if you want to group these functions / procedures which reside in the same unit in functional categories you can use records for this:
TStringConversions = record
class Function StrToBase64(AString): string;
class Procedure StrToGridLayout(AString: string; AGrid: TDBGrid);
end;
TStringParsing = record
class Function ExtractWord(aString): string;
class Function GetStrColumn(aString: string; aCol: integer): string;
end;
And then, you can call them in code in a much cleaner way:
myFirstWord := TStringParsing.ExtractWord('Delphi is a very good tool');
HTH