You are not logged in.
Pages: 1
Thanks Igor and Arnaud!
for DB request, services are easier to use than these direct access.
I'm not quite sure what you mean; how would you implement this for the FishFacts demo for example?
BTW for static files, take a look at this topic: https://synopse.info/forum/viewtopic.php?id=3365
That looks very interesting, thanks Igor!
(Unfortunately it isn't compatible with Delphi 7, as it has records with methods).
In situations where a dedicated webserver is impractical, it would be useful to have an application that can serve the static client files (.html, .css, .js etc.) as well as the database requests.
The following approach seems to work however it feels like a kludge; what is the best way to do this?
Example: start with FishFacts demo (Sample #19)
Define custom server
TCustomServer = class(TSQLHttpServer)
public
function Request(Ctxt: THttpServerRequest): cardinal; override;
end;
function TCustomServer.Request(Ctxt: THttpServerRequest): cardinal;
var
FileName: TFileName;
isDynamic: Boolean;
begin
isDynamic := True;
if (Ctxt.Method='GET') then
begin
FileName := Ctxt.URL;
if (FileName ='/') then
FileName := '/index.html';
FileName := ExeVersion.ProgramFilePath + 'html5' + FileName;
if FileExists(FileName) then
begin
// Serve the static files
isDynamic := False;
Ctxt.OutContent := StringToUTF8(FileName);
Ctxt.OutContentType := HTTP_RESP_STATICFILE;
result := 200;
end;
end;
if isDynamic then
// call the associated TSQLRestServer instance(s)
result := inherited Request(Ctxt);
end;
Change server definition and creation
//Server: TSQLHttpServer;
Server: TCustomServer;
Server := TCustomServer.Create('8080',[DB],'+',useHttpApiRegisteringURI);
In client browser
Simply open 192.168.0.63:8080 to start the client application.
(Where application server's IP address is 192.168.0.63)
I've noticed fairly frequent 10060 WSAETIMEDOUT errors when using the Chrome browser as a client with mORMot applications (for example the FishFacts demo 19).
How would I go about debugging these errors, and are they anything to worry about?
I haven't seen them with Firefox or I.Explorer.
20180702 07271154 EXC ECrtSocket ("SockRecvLn 10060 WSAETIMEDOUT [A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond]")
at 004534EE SynCrtSock.TCrtSocket.SockRecvLn (4891)
stack trace
00455C7F SynCrtSock.GetRemoteIP (6376)
004528C5 SynCrtSock.TCrtSocket.AcceptRequest (4421)
0045645C SynCrtSock.TSynThreadPoolTHttpServer.Task (6629)
004562BA SynCrtSock.TSynThreadPoolSubThread.Execute (6576)
0041FD17 Classes.ThreadProc 00403B1A System.ThreadWrapper
,----
| Using mORMot 1.18.2790 FTS3
| Running on Windows 10 64bit (10.0.10586) with code page 1252
| TSQLite3LibraryStatic 3.13.0 with internal MM
| Generated with: Delphi 7 compiler
`----
Several tests fail the following test:
CheckSame(L.StartDateTime,40640.502882,1E-10);
because fStartDateTime is 0.
I traced the problem to the following code in procedure TSynLogFile.LoadFromMap(AverageLineLength: integer=32);
if i>19 then begin
SetString(fFramework,PAnsiChar(P),i-1);
Iso8601ToDateTimePUTF8CharVar(P+i,19,fStartDateTime);
end;
What is the significance of 19 in the i>19 condition?
If I change the condition to i>17 all tests complete with no failures.
if i>17 then begin
SetString(fFramework,PAnsiChar(P),i-1);
Iso8601ToDateTimePUTF8CharVar(P+i,19,fStartDateTime);
end;
I guess the condition should be
if i>0 then begin
There is a problem with the TJvDBGrid component from the Jedi project caused by the following bit of code in grids.pas:
procedure TCustomGrid.Paint;
[...]
if DefaultDrawing and not ThemeServices.ThemesEnabled then begin
// AB: don't draw black lines for Fixed cells: use XP theme
DrawLines(goFixedHorzLine in Options, goFixedVertLine in Options,
0, 0, [0, 0, Horz.FixedBoundary, Vert.FixedBoundary], clBlack, FixedColor);
DrawLines(goFixedHorzLine in Options, goFixedVertLine in Options,
LeftCol, 0, [Horz.FixedBoundary, 0, Horz.GridBoundary,
Vert.FixedBoundary], clBlack, FixedColor);
DrawLines(goFixedHorzLine in Options, goFixedVertLine in Options,
0, TopRow, [0, Vert.FixedBoundary, Horz.FixedBoundary,
Vert.GridBoundary], clBlack, FixedColor);
end;
When the application is running with the Windows Classic theme, the fixed cell lines are not drawn. In fact nothing is drawn there, the area is not even cleared. This results in whatever was previously on the screen appearing where those lines should be.
The reason is that with a TJvDbGrid component, the inherited DefaultDrawing property is always FALSE, regardless of the setting of JvDbGrid.DefaultDrawing.
So a simple fix is to change the if statement like so:
if not ThemeServices.ThemesEnabled then begin
// AB: don't draw black lines for Fixed cells: use XP theme
[...]
I don't know why the Jedi guys have overridden the DefaultDrawing property, but the original Grids.pas code always drew the black lines, regardless of the DefaultDrawing setting, so it seems to me this change is correct.
(And in case anyone is wondering: the Windows Classic theme is the default theme used in terminal server sessions).
AFAIR "-O+" is to enable optimization.
But presumably not the same as the -$O+ switch, which is enabled anyway by default?
I found a utility called DCCShell which indicates the compiler options -O3, -O4, -O5 and -O6 are for optimisations targeting particular CPUs (i386 to Pentium Pro), so I guess -O+ could be the same as -O6, or possibly for later CPUs?
Also on the same subject, do you (or anyone else here) know what compiler options are needed to rebuild the .DCUs exactly as provided by Borland?
There is a makefile provided by Borland for the RTL .DCUs, but not for the VCL or anything else, and Borland seems to use different options for individual units.
For their system.dcu they use "-q -m -y -z" like you, but not "-O+", and for sysutils they use "-q -z"
DCC = dcc32 -q
[...]
$(LIB)\system.dcu: sys\system.pas sys\sysinit.pas sys\getmem.inc
$(DCC) sys\system -m -y -z $(RTLDEBUG) -n$(LIB)
$(LIB)\sysutils.dcu: sys\sysutils.pas $(LIB)\system.dcu $(LIB)\windows.dcu
$(DCC) sys\sysutils -z $(RTLDEBUG) -u$(LIB) -r$(LIB) -n$(LIB)
Currently, this bat file looks like this:
del *.dcu /s "c:\program files\borland\delphi7\bin\dcc32.exe" -O+ -Q -M -Y -Z -$D+ System.pas "c:\program files\borland\delphi7\bin\dcc32.exe" -O+ -Q -M -Y -Z -DLVCL -NLVCL -$D+ System.pas "c:\program files\borland\delphi7\bin\dcc32.exe" -O+ -Q -M -Y -Z -DLVCL -N..\ictus3\LVCL -$D+ System.pas pause
[...]
I provided the syscom.bat file only to show the right command line switchs to be used (-O+ -Q -M -Y -Z -$D+). Because they are not well documented.
Hi Arnaud, could you please explain what these command line options do exactly? "-Y" isn't even shown as an option for the dcc32 that comes with Delphi 7, and "-O" is shown as being for "Object directories".
They certainly aren't well documented .
Also on the same subject, do you (or anyone else here) know what compiler options are needed to rebuild the .DCUs exactly as provided by Borland?
Borland Delphi Version 15.0
Copyright (c) 1983,2002 Borland Software Corporation
Syntax: dcc32 [options] filename [options]
-A<unit>=<alias> = Set unit alias -LU<package> = Use package
-B = Build all units -M = Make modified units
-CC = Console target -N<path> = DCU output directory
-CG = GUI target -O<paths> = Object directories
-D<syms> = Define conditionals -P = look for 8.3 file names also
-E<path> = EXE output directory -Q = Quiet compile
-F<offset> = Find error -R<paths> = Resource directories
-GD = Detailed map file -U<paths> = Unit directories
-GP = Map file with publics -V = Debug information in EXE
-GS = Map file with segments -VR = Generate remote debug (RSM)
-H = Output hint messages -W = Output warning messages
-I<paths> = Include directories -Z = Output 'never build' DCPs
-J = Generate .obj file -$<dir> = Compiler directive
-JP = Generate C++ .obj file --help = Show this help screen
-K<addr> = Set image base addr --version = Show name and version
Compiler switches: -$<letter><state> (defaults are shown below)
A8 Aligned record fields P+ Open string params
B- Full boolean Evaluation Q- Integer overflow checking
C+ Evaluate assertions at runtime R- Range checking
D+ Debug information T- Typed @ operator
G+ Use imported data references U- Pentium(tm)-safe divide
H+ Use long strings by default V+ Strict var-strings
I+ I/O checking W- Generate stack frames
J- Writeable structured consts X+ Extended syntax
L+ Local debug symbols Y+ Symbol reference info
M- Runtime type info Z1 Minimum size of enum types
O+ Optimization
Not sure if something is wrong with my setup (Delphi 7 with EnhancedRTL, CPU32), or if a recent change to SynPdf has changed the hard-coded hash values, but when I run the TestSQL3 project there are 3 failures in the PDF tests:
TTestSynopsePDF._TPdfDocument:
embed=False
Hash32(MS.Memory,MS.Position) = 3FC74CB0 (not 1780F68C)
embed=True
Hash32(MS.Memory,MS.Position) = 87966EAD (not A1201D84)
TTestSynopsePDF._TPdfDocumentGDI
H = B58F47C9 (not F6B2289F)
You do not check the source end.
Ah, of course, thanks! I didn't pay attention to "at most" in the Delphi Help description of the function.
StrLCopy copies at most MaxLen characters from Source to Dest, then adds a null terminator to Dest and returns Dest.
Thank you Arnaud!
Although I assume John O'Harrow's version of Move() is highly optimised; do you think there is something wrong with my proposed solution?
function StrLCopy(Dest: PChar; const Source: PChar; MaxLen: Cardinal): PChar;
asm
or edx,edx // check Source
jz @z // abort if nil
mov byte ptr [eax+ecx],0 // null-terminate Dest
push eax // save Dest
xchg eax,edx // swap Source & Dest for Move()
call Move // do the move
pop eax // restore Dest
@z:
end;
This version should work as you expect, I suppose
Much better! But it's not correct when MaxLen is 0.
I wonder how this one compares, in terms of speed, with the version calling the Move routine? Probably depends on the size of the data being copied.
"assembler" is a deprecated, and ignored keyword.
Ah, thanks!
I think StrLCopy() as included in the zip should be fixed, isn't it?
It looks the same to me; it stops the copy at the first null in the source, but does not set a null value at the end of the destination buffer:
function StrLCopy(Dest: PChar; const Source: PChar; MaxLen: Cardinal): PChar;
asm // faster version by AB
or edx,edx
jz @z
push eax
push ebx
xchg eax,edx
mov ebx,ecx
xor ecx,ecx
@1: cmp byte ptr [eax+ecx],0
lea ecx,ecx+1 // copy last #0
je @s
cmp ecx,ebx
jb @1
@s: pop ebx
call Move
pop eax
@z:
end;
I notice you haven't updated StrLCopy though - have you tried running my test application illustrating the problem?
Incidentally, what is the purpose of the "assembler;" directive on the original Borland version of StrLCopy?
The version of the StrPCopy function in SysUtils.pas has the same bug I reported for the StrLCopy function - it assumes the destination buffer already has a null terminator, and does not add one:
function StrPCopy(Dest: PChar; const Source: string): PChar;
asm // faster version by AB
or edx,edx
push eax
xchg eax,edx
jz @z
mov ecx,[eax-4]
inc ecx // copy last #0
call move
@z: pop eax
end;
The solution is to correct the assembler above, or simply revert to the original Borland version of the function:
function StrPCopy(Dest: PChar; const Source: string): PChar;
begin
Result := StrLCopy(Dest, PChar(Source), Length(Source));
end;
NB of course making sure you use the corrected version of StrLCopy I supplied in my last topic about StrLCopy().
What puzzles me is why this hasn't been mentioned before, because any standard database application using TStringField.SetAsString (i.e. StrField.AsString := 'x') will highlight the problem.
Simple test unit:
Unit1.pas:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
btnTestBorland: TButton;
edtBorland: TLabeledEdit;
edtSynopse: TLabeledEdit;
edtSize: TLabeledEdit;
edtSource: TLabeledEdit;
btnTestSynopse: TButton;
btnTestNew: TButton;
edtNew: TLabeledEdit;
procedure edtSizeChange(Sender: TObject);
procedure btnTestBorlandClick(Sender: TObject);
procedure btnTestSynopseClick(Sender: TObject);
procedure btnTestNewClick(Sender: TObject);
private
{ Private declarations }
Size: Cardinal;
Buffer: array[0..128] of Char;
procedure PrepareBuffer;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function SynopseStrLCopy(Dest: PChar; const Source: PChar; MaxLen: Cardinal): PChar;
asm // faster version by AB
or edx,edx
jz @z
push eax
push ebx
xchg eax,edx
mov ebx,ecx
xor ecx,ecx
@1: cmp byte ptr [eax+ecx],0
lea ecx,ecx+1 // copy last #0
je @s
cmp ecx,ebx
jb @1
@s: pop ebx
call Move
pop eax
@z:
end;
function NewStrLCopy(Dest: PChar; const Source: PChar; MaxLen: Cardinal): PChar;
asm
or edx,edx // check Source
jz @z // abort if nil
or eax,eax // check Dest
jz @z // abort if nil
mov byte ptr [eax+ecx],0 // null-terminate Dest
push eax // save Dest
xchg eax,edx // swap Source & Dest for Move()
call Move // do the move
pop eax // restore Dest
@z:
end;
function BorlandStrLCopy(Dest: PChar; const Source: PChar; MaxLen: Cardinal): PChar;
// original Borland version
asm
PUSH EDI
PUSH ESI
PUSH EBX
MOV ESI,EAX
MOV EDI,EDX
MOV EBX,ECX
XOR AL,AL
TEST ECX,ECX
JZ @@1
REPNE SCASB
JNE @@1
INC ECX
@@1: SUB EBX,ECX
MOV EDI,ESI
MOV ESI,EDX
MOV EDX,EDI
MOV ECX,EBX
SHR ECX,2
REP MOVSD
MOV ECX,EBX
AND ECX,3
REP MOVSB
STOSB
MOV EAX,EDX
POP EBX
POP ESI
POP EDI
end;
procedure TForm1.edtSizeChange(Sender: TObject);
begin
Size := StrToInt(edtSize.Text);
end;
procedure TForm1.PrepareBuffer;
var
i: Integer;
begin
for i := 0 to Size-1 do
Buffer[i] := Char(i);
Buffer[Size] := '!';
end;
procedure TForm1.btnTestBorlandClick(Sender: TObject);
begin
PrepareBuffer;
BorlandStrLCopy(Buffer, PChar(edtSource.Text), Size);
edtBorland.Text := Buffer;
end;
procedure TForm1.btnTestSynopseClick(Sender: TObject);
begin
PrepareBuffer;
SynopseStrLCopy(Buffer, PChar(edtSource.Text), Size);
edtSynopse.Text := Buffer;
end;
procedure TForm1.btnTestNewClick(Sender: TObject);
begin
PrepareBuffer;
NewStrLCopy(Buffer, PChar(edtSource.Text), Size);
edtNew.Text := Buffer;
end;
end.
Unit1.dfm:
object Form1: TForm1
Left = 585
Top = 173
Width = 374
Height = 296
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object btnTestBorland: TButton
Left = 56
Top = 96
Width = 89
Height = 25
Caption = 'btnTestBorland'
TabOrder = 0
OnClick = btnTestBorlandClick
end
object edtBorland: TLabeledEdit
Left = 160
Top = 96
Width = 121
Height = 21
EditLabel.Width = 51
EditLabel.Height = 13
EditLabel.Caption = 'edtBorland'
TabOrder = 1
end
object edtSynopse: TLabeledEdit
Left = 160
Top = 144
Width = 121
Height = 21
EditLabel.Width = 56
EditLabel.Height = 13
EditLabel.Caption = 'edtSynopse'
TabOrder = 2
end
object edtSize: TLabeledEdit
Left = 216
Top = 40
Width = 65
Height = 21
EditLabel.Width = 20
EditLabel.Height = 13
EditLabel.Caption = 'Size'
TabOrder = 3
OnChange = edtSizeChange
end
object edtSource: TLabeledEdit
Left = 56
Top = 40
Width = 129
Height = 21
EditLabel.Width = 49
EditLabel.Height = 13
EditLabel.Caption = 'edtSource'
TabOrder = 4
Text = 'ABCDEFGHIJKLMNOP'
end
object btnTestSynopse: TButton
Left = 56
Top = 144
Width = 89
Height = 25
Caption = 'btnTestSynopse'
TabOrder = 5
OnClick = btnTestSynopseClick
end
object btnTestNew: TButton
Left = 56
Top = 192
Width = 89
Height = 25
Caption = 'btnTestNew'
TabOrder = 6
OnClick = btnTestNewClick
end
object edtNew: TLabeledEdit
Left = 160
Top = 192
Width = 121
Height = 21
EditLabel.Width = 37
EditLabel.Height = 13
EditLabel.Caption = 'edtNew'
TabOrder = 7
end
end
Searching for null is for safety: you copy up to MaxLen bytes, but you copy only source chars len, with a MaxLen value set to the destination buffer.
Goal is to avoid any potential destination buffer overflow, for security reasons.
That sounds reasonable, but if so why not add similar checks in the Move routine?
Yours sounds like a nice alternative, but does not work as expected: you will append a #0 at MaxLen position.
I'm not sure what you mean; in my tests it behaves exactly the same as the standard Delphi version (including when MaxLen=0).
The original Delphi7 code produces an access violation if either the source or the destination is nil, so I think this is the logical equivalent:
function StrLCopy(Dest: PChar; const Source: PChar; MaxLen: Cardinal): PChar;
asm
mov byte ptr [eax+ecx],0 // null-terminate Dest
push eax // save Dest
xchg eax,edx // swap Source & Dest for Move()
call Move // do the move
pop eax // restore Dest
end;
I don't understand why you scan the Source for nulls first; is there any reason why the function can't be as simple as this? :
function SynopseStrLCopy(Dest: PChar; const Source: PChar; MaxLen: Cardinal): PChar;
asm
or edx,edx // check Source
jz @z // abort if nil
or eax,eax // check Dest
jz @z // abort if nil
mov byte ptr [eax+ecx],0 // null-terminate Dest
push eax // save Dest
xchg eax,edx // swap Source & Dest for Move()
call Move // do the move
pop eax // restore Dest
@z:
end;
(Also, the original Delphi7 version doesn't appear to check for nils).
Unless I'm doing something very silly, there is a bug in the SynopseRTL version of StrLCopy().
The Borland version always adds a null terminator to Dest, the Synopse version does not in my tests.
Who will run Windows 95/98/Me nowadays?
Good question
I've merged Steve's version of printers.pas with yours; would you like me to email you a copy?
There appears to be a good solution on "Steve's Blog" - originally adapted Delphi5 version but there weren't many changes for Delphi7.
I notice he doesn't attempt to load GetDefaultPrinter dynamically however so it will need re-writing to work with OS's that do not have the API.
The Delphi 7 version of Printers.pas - including the one as patched in this SynopseRTL - does not use the recommended Windows GetDefaultPrinter API, and this causes problems in certain terminal services situations, where the application is unable to find the user's default printer.
And there's also a problem with the default printer settings, as explained by Fernando Ruiz Casas on QualityCentral.
Has anyone here got a "definitive" version of Printers.pas that fixes all known issues? It would be good to have all the fixes in this library.
From the asm point of view, const or not const is exactly the same for a TDateTime kind of parameter.
OK, so why remove it? Doesn't the lack of it result in extra overheads? I like to understand things
The procedure entry point @Sysutils@DecodeTime$qqrx16System@TDateTimerust2t2t2 could not be located in the dynamic link library rtl70.bpl.
I see now this is because you've changed the declaration of the DecodeTime function from
procedure DecodeTime(const DateTime: TDateTime; ...
to
procedure DecodeTime(DateTime: TDateTime; ...
I thought using "const" was faster; could you please explain why you removed it? (I guess it might be required for your asm code?).
But you will need to recompile every .bpl in your computer, so it could not be feasible if you miss some components source code...
Yep: in order to rebuild the JVCL components with SynopseRTL I needed to first rebuild the JCL libraries, and that seems to mean rebuilding Delphi's designide too, and the source for that does not appear to be available
My advice is to use the default RTL files for IDE packages and third-party components, then use the enhanced versions only at compile time of your applications.
Do you think that is actually possible with the JVCL components? Maybe I'm being stupid, but I get the problem I reported in my first post.
I'm beginning to think that it would be best to avoid any changes to the interfaces in this SynopseRTL.
New problem: I placed the resulting rtl70.bpl file in the system32 directory as recommended by Dave Nottage, but this causes the Delphi IDE to throw the following error:
---------------------------
delphi32.exe - Entry Point Not Found
---------------------------
The procedure entry point @Sysutils@DecodeTime$qqrx16System@TDateTimerust2t2t2 could not be located in the dynamic link library rtl70.bpl.
Questions:
1) Does that mean I've built the .DCUs wrongly, or just the .BPL?
2) Will it matter if I keep the original .bpl files in system32?
Warning about those .pas files: they break the Delphi license, and should not be published.
I know that for the main RTL source, but that's not true of those 2 missing units:
{ *************************************************************************** }
{ }
{ Delphi/C++Builder Runtime Library }
{ Helpers for C++ Variant binding. }
{ }
{ Copyright (c) 2002 Borland Software Corporation }
{ }
{ This file may be distributed and/or modified under the terms of the GNU }
{ General Public License (GPL) version 2 as published by the Free Software }
{ Foundation and appearing at http://www.borland.com/kylix/gpl.html. }
{ }
{ *************************************************************************** }
I've found it on Koders.com, which also has StrHlpr.pas (also referenced in rtl.dpk) - they appear to be part of the OpenCLX project, I wonder if they are actually required for Win32 applications?
OK, I've found a useful post by Dave Nottage explaining how to get Delphi to re-create the packages; I reckon I only need to create vcl.dcp and rtl.dcp as the SynopseRTL doesn't make any DB changes.
So I've been able to create vcl.dpk and rtl.dpk (which I had to edit manually because Delphi incorrectly put %sys32% as the path to the Synopse-modified units:
contains
ZLib,
ZLibConst,
SysUtils in 'C:\WINDOWS\system32\SysUtils.pas',
Windows,
Types,
SysConst,
Classes in 'C:\WINDOWS\system32\Classes.pas',
)
But I've hit a snag: rtl.dpk contains a reference to "VarHlpr", and that doesn't exist at all in my Delphi installation. Any ideas?
I never did that, but I guess you can open the package sources - .bpk I guess.
I think they'd be .dpk for the .pas source files, but I don't have any vcl.dpk or vcl.bpk in my Delphi installation. Do you?
At least they provide the source code for the installer, I think I'll try changing it to insert my Enhanced RTL directory at the start.
That didn't work either. After much messing around I eventually thought of using ProcMon to find out why the Jedi JVCL packages were being built with the original grids.dcu - the reason is simple: they're directly accessing the original **packages**: vcl.dcp, rtl.dcp, vcldb.dcp and dbrtl.dcp!
So I guess I just need to rebuild those packages in my own lib directory. Does anyone here know how to do that?
Perhaps replace the Grids.dcu and other units in Delphi/... sub folder with the Enhanced RTL version.
Yes, that's probably the simplest solution, although I was hoping to avoid touching the "official" files.
Or change the dcc32.cfg path in Delphi/bin to also first point at the enhanced RTL directory, just like the IDE.
I suspect the JVCL installer does not use the IDE path, but use the default dcc32.cfg file.
I tried that already, it doesn't work. I've looked at the JVCL installer source code and discovered it builds a dcc32.cfg file on the fly and puts the standard Delphi directories first in the search path.
At least they provide the source code for the installer, I think I'll try changing it to insert my Enhanced RTL directory at the start.
Thanks for replying Arnaud!
make sure that the new directory (e.g. D:\Dev\Lib) is the FIRST in all paths
This recommended way of installing these units causes a problem with the Jedi JVCL installer (http://wiki.delphi-jedi.org/wiki/JEDI_V … nt_Library): it appears to be designed to always find the original Delphi units first, so when one tries to build an application the following error occurs:
Unit JvJVCLUtils was compiled with a different version of Grids.TCustomDrawGrid
Can anyone suggest a simple solution?
Pages: 1