下面的函数FormatSql主要用来处理SQL语句的,功能是自动替换Args参数中的可能有的单引号,自动替换为两个单引号。但是在调试运行时发现了错误,当Args有多个参数,并且有好几个WideString类型的参数时,出现不规则的错误,我遇到的是第一个参数变成了第四个参数的值,其他没变。肯定是哪里理解错误出了问题,内存混乱了,哪位兄弟指教指教……function StrForSql(const S: String): String;
begin
Result := StringReplace(S, '''', '''''', [rfReplaceAll]);
end;function FormatSql(const SqlFormat: String; const Args: array of const): String;
var
I: Integer;
V: Variant;
begin
for I := 0 to High(Args) do
begin
with Args[I] do
case VType of
vtString:
VString^ := StrForSql(VString^);
vtPChar:
VPChar := PChar(StrForSql(VPChar));
vtAnsiString:
VAnsiString := Pointer(StrForSql(String(VAnsiString)));
vtWideString:
VWideString := Pointer(WideString(StrForSql(WideString(VWideString))));
vtVariant:
begin
V := VVariant^;
case VarType(V) of
varOleStr, varString:
begin
V := StrForSql(V);
VVariant^ := V;
end;
end;
end;
end;
end;
Result := Format(SqlFormat, Args);
end;
begin
Result := StringReplace(S, '''', '''''', [rfReplaceAll]);
end;function FormatSql(const SqlFormat: String; const Args: array of const): String;
var
I: Integer;
V: Variant;
begin
for I := 0 to High(Args) do
begin
with Args[I] do
case VType of
vtString:
VString^ := StrForSql(VString^);
vtPChar:
VPChar := PChar(StrForSql(VPChar));
vtAnsiString:
VAnsiString := Pointer(StrForSql(String(VAnsiString)));
vtWideString:
VWideString := Pointer(WideString(StrForSql(WideString(VWideString))));
vtVariant:
begin
V := VVariant^;
case VarType(V) of
varOleStr, varString:
begin
V := StrForSql(V);
VVariant^ := V;
end;
end;
end;
end;
end;
Result := Format(SqlFormat, Args);
end;
unit lxcDebug;interface
uses Windows,Classes,sysUtils;
type
{Debug type
dtFile: the debug information is sotred in file which is existing in the same directory with current process with a extension .debug
dtMessageBox: the debug information displayed in a message box
}
TDebugType=(dtFile,dtMessageBox);
TDebugFormat=(dfDefault,dfInteger,dfFloat,dfIndex,dfLeftJusti,dfWidth,dfPrecision,dfObject);
TlxcFormat=class
private
_Format:TDebugFormat;
_Value:Cardinal; constructor Create;
end;
TlxcDebugger=class
private
FEnabled:Boolean;
IntType:UINT;
FloatType:UINT;
FIndex:UINT;
FPrecision:UINT;
FLeftJusti:UINT;
FWidth:UINT;
FObjShowPtr:Boolean;
FDebugType:TDebugType;
FDebugFile:TStringList;
FDebugFileName:string;
{Used by format}
function GetIntFmt:string;
function GetFloatFmt:string;
function GetPtrFmt:String;
function GetClsFmt:string;
function GetMnFmt:string;
procedure WriteLog(s:string;Caption:string);
procedure SetDefault2;
public
constructor Create(ClearLog:boolean=false);
property DebugType:TDebugType read FDebugType write FDebugType;
property Enabled:Boolean read FEnabled write FEnabled default true;
property DebugFileName:string read FDebugFileName;
procedure ClearDebugLog;
procedure Trace(args:array of const);
function TraceString(args:array of const):string;
function SetHex:TlxcFormat;
function SetDec:TlxcFormat;
function SetScientific:TlxcFormat;
function SetFixed:TlxcFormat;
function SetGeneral:TlxcFormat;
function SetNumber:TlxcFormat;
function SetDefault:TlxcFormat;
function SetIndex(n:Integer):TlxcFormat;
function SetLeftJusti(n:integer):TlxcFormat;
function SetWidth(n:integer):TlxcFormat;
function SetPrecision(n:integer):TlxcFormat;
function ObjShowPtr:TlxcFormat;
function ObjShowClass:TlxcFormat;
function InIDE:boolean;
{If condition is true, then make a breakpoint in debug environment. in non-debug environment, it will not make a breakpoint}
procedure Assert(Condition:Boolean=true);overload;
procedure Assert(Condition:Boolean;args:array of const);overload;
end;
{Single-ton pattern implemented by function}
function lxcDebugger:TlxcDebugger;
const
LXC_HEX=1;
LXC_DEC=2;
LXC_SCIENTIFIC=3;
LXC_FIXED=4;
LXC_GENERAL=5;
LXC_NUMBER=6;implementation
var _IsInIDE:Boolean;
_lxcDebugger:TlxcDebugger;
function lxcDebugger:TlxcDebugger;
begin
if _lxcDebugger=nil then _lxcDebugger:=TlxcDebugger.Create ;
Result:=_lxcDebugger;
end;
function TlxcDebugger.TraceString(args:array of const):string;
var s:string;i:integer;dbg:TlxcDebugger;
begin
if Not Assigned(self) then
begin
if Not Assigned(_lxcDebugger) then _lxcDebugger:=TlxcDebugger.Create ;
dbg:=_lxcDebugger;
end
else
dbg:=self;
s:='';
for i:=Low(args) to High(args) do
case args[i].VType of
System.vtInteger ,System.vtInt64:
s:=s+Format(dbg.GetIntFmt ,[args[i].VInteger]);
System.vtBoolean :
s:=s+BoolToStr(args[i].VBoolean ,true);
System.vtChar :
s:=s+args[i].VChar ;
System.vtExtended :
s:=s+Format(dbg.GetFloatFmt ,[args[i].VExtended^]);
System.vtString :
s:=s+String(args[i].VString );
System.vtPointer :
s:=s+Format(dbg.GetPtrFmt ,[args[i].VPointer ]);
System.vtPWideChar :
s:=s+String(args[i].VWideString);
System.vtObject :
if args[i].VObject is TlxcFormat then//adjust formats
begin
case (args[i].VObject as TlxcFormat)._Format of //
dfInteger:self.IntType :=(args[i].VObject as TlxcFormat)._Value ;
dfFloat:self.FloatType :=(args[i].VObject as TlxcFormat)._Value ;
dfIndex:self.FIndex :=(args[i].VObject as TlxcFormat)._Value ;
dfLeftJusti:self.FLeftJusti :=(args[i].VObject as TlxcFormat)._Value ;
dfWidth:self.FWidth :=(args[i].VObject as TlxcFormat)._Value ;
dfPrecision:self.FPrecision :=(args[i].VObject as TlxcFormat)._Value ;
dfObject:self.FObjShowPtr :=Boolean((args[i].VObject as TlxcFormat)._Value );
dfDefault:;//
end; // case
args[i].VObject.Free ;//free!
continue// only ignore TlxcFormat type
end
else
if FObjShowPtr then
s:=s+Format(dbg.GetPtrFmt,[Pointer(args[i].VObject)])
else
s:=s+Format(dbg.GetClsFmt,[args[i].VObject.ClassName]);
System.vtInterface :
s:=s+Format(dbg.GetPtrFmt ,[args[i].VInterface ]);
System.vtClass :
s:=s+Format(dbg.GetClsFmt ,[args[i].VClass.ClassName ]);
System.vtPChar:
s:=s+String(args[i].VPChar );
System.vtAnsiString:
s:=s+String(args[i].VAnsiString);
System.vtCurrency :
s:=s+Format(dbg.GetMnFmt ,[args[i].VCurrency]);
end;
Result:=s;
end;
begin
if not FEnabled then exit;
WriteLog(TraceString(args),'TRACE')
end;
{Implementation for class Trace Format}
constructor TlxcDebugger.Create(ClearLog:boolean=false);
var Buffer:array[1..1024] of char;
begin
if assigned(_lxcDebugger) then abort;//strictly only one instance exists
SetDefault2;//Set to default settings
FDebugType:=dtMessageBox; FDebugFile:=TStringList.Create ;
GetModuleFileName(0,@Buffer[1],1024);
FDebugFileName:=ChangeFileExt(StrPas(@Buffer[1]),'.debug');
if not FileExists(FDebugFileName) or ClearLog then//file not exists will automatic create a new debug log file
FDebugFile.SaveToFile(FDebugFileName)
else//otherwise load the exists file
FDebugFile.LoadFromFile(FDebugFileName);
if FDebugFile.Count =0 then//new file need adds some empty lines
FDebugFile.Add('');
FDebugFile.Add(' Debugger Launched in '+FormatDateTime('mm/dd/yyyy - hh/nn/ss.zzz AM/PM',now));
FDebugFile.saveToFile(FDebugFileName);
end;
function TlxcDebugger.SetHex:TlxcFormat;
begin
Result:=TlxcFormat.Create ;
Result._Format :=dfInteger;
Result._Value :=LXC_HEX;
end;
function TlxcDebugger.SetDec:TlxcFormat;
begin
Result:=TlxcFormat.Create ;
Result._Format :=dfInteger;
Result._Value :=LXC_DEC;
end; function TlxcDebugger.SetScientific:TlxcFormat;
begin
Result:=TlxcFormat.Create ;
Result._Format :=dfFloat;
Result._Value :=LXC_SCIENTIFIC;
end;
function TlxcDebugger.SetFixed:TlxcFormat;
begin
Result:=TlxcFormat.Create ;
Result._Format :=dfFloat;
Result._Value :=LXC_FIXED;
end;
function TlxcDebugger.SetGeneral:TlxcFormat;
begin
Result:=TlxcFormat.Create ;
Result._Format :=dfFloat;
Result._Value :=LXC_GENERAL;
end;
function TlxcDebugger.SetNumber:TlxcFormat;
begin
Result:=TlxcFormat.Create ;
Result._Format :=dfFloat;
Result._Value :=LXC_NUMBER;
end;
procedure TlxcDebugger.SetDefault2;
begin
IntType:=LXC_DEC;
FloatType:=LXC_FIXED;
FIndex:=0;
FLeftJusti:=0;
FWidth:=0;
FPrecision:=0;
FObjShowPtr:=True;
FEnabled:=true;
end;
function TlxcDebugger.SetDefault:TlxcFormat;
begin
Result:=TlxcFormat.Create ;
Result._Format :=dfDefault;
end;
function TlxcDebugger.SetIndex(n:Integer):TlxcFormat;
begin
Result:=TlxcFormat.Create ;
Result._Format :=dfIndex;
Result._Value :=n;
end;
function TlxcDebugger.SetLeftJusti(n:integer):TlxcFormat;
begin
Result:=TlxcFormat.Create ;
Result._Format :=dfleftJusti;
Result._Value :=n;
end;
function TlxcDebugger.SetWidth(n:integer):TlxcFormat;
begin
Result:=TlxcFormat.Create ;
Result._Format :=dfWidth;
Result._Value :=n;
end;
function TlxcDebugger.SetPrecision(n:integer):TlxcFormat;
begin Result:=TlxcFormat.Create ;
Result._Format :=dfPrecision;
Result._Value :=n;
end;
function TlxcDebugger.ObjShowPtr:TlxcFormat;
begin
Result:=TlxcFormat.Create ;
Result._Format :=dfObject;
Result._Value :=Cardinal(True);
end;
function TlxcDebugger.ObjShowClass:TlxcFormat;
begin
Result:=TlxcFormat.Create ;
Result._Format :=dfObject;
Result._Value :=Cardinal(False);
end;
function TlxcDebugger.GetIntFmt:string;
var s:string;
begin
s:='%';
if FIndex<>0 then s:=s+Format('%d:',[FIndex]);
if FLeftJusti<>0 then s:=s+Format('%d-',[FLeftJusti]);
if FWidth<>0 then s:=s+Format('%d',[FWidth]);
if FPrecision<>0 then s:=s+Format('.%d',[FPrecision]);
case IntType of
LXC_HEX:s:=s+'x';
LXC_DEC:s:=s+'d'; end;
Result:=s;
end;
function TlxcDebugger.GetMnFmt:string;
var s:string;
begin
s:='%';
if FIndex<>0 then s:=s+Format('%d:',[FIndex]);
if FLeftJusti<>0 then s:=s+Format('%d-',[FLeftJusti]);
if FWidth<>0 then s:=s+Format('%d',[FWidth]);
if FPrecision<>0 then s:=s+Format('.%d',[FPrecision]);
Result:=s+'m';
end;
function TlxcDebugger.GetFloatFmt:string;
var s:string;
begin
s:='%';
if FIndex<>0 then s:=s+Format('%d:',[FIndex]);
if FLeftJusti<>0 then s:=s+Format('%d-',[FLeftJusti]);
if FWidth<>0 then s:=s+Format('%d',[FWidth]);
if FPrecision<>0 then s:=s+Format('.%d',[FPrecision]);
case FloatType of
LXC_FIXED:s:=s+'f';
LXC_GENERAL:s:=s+'g';
LXC_SCIENTIFIC:s:=s+'e';
LXC_NUMBER:s:=s+'n';
end;
Result:=s;
end;
function TlxcDebugger.GetPtrFmt:String;
var s:string;
begin
s:='%';
if FIndex<>0 then s:=s+Format('%d:',[FIndex]);
if FLeftJusti<>0 then s:=s+Format('%d-',[FLeftJusti]);
if FWidth<>0 then s:=s+Format('%d',[FWidth]);
if FPrecision<>0 then s:=s+Format('.%d',[FPrecision]);
Result:='<'+s+'p>';
end;
function TlxcDebugger.GetClsFmt:string;
var s:string;
begin
s:='%';
if FIndex<>0 then s:=s+Format('%d:',[FIndex]);
if FLeftJusti<>0 then s:=s+Format('%d-',[FLeftJusti]);
if FWidth<>0 then s:=s+Format('%d',[FWidth]);
if FPrecision<>0 then s:=s+Format('.%d',[FPrecision]);
Result:='['+s+'s]';
end;
procedure TlxcDebugger.Assert(Condition:Boolean;args:array of const);
begin
if condition then exit;
WriteLog('lxcDebugger.Assert failed! breakpoint created!'#13#10'Details: '+self.TraceString(args),'Assert failed');
if _IsInIDE then
asm int 3;end;
end; procedure TlxcDebugger.Assert(Condition:Boolean=true);
begin
if Condition then exit;
WriteLog('lxcDebugger.Assert failed! breakpoint created!','Assert failed');
if _IsInIDE then
asm int 3;end;
end;
procedure TlxcDebugger.WriteLog(s:string;Caption:string);
begin
if (self.FDebugType =dtMessageBox)And(_IsInIDE) then
begin
MessageBox(GetActiveWindow,PChar(s),PChar(Caption),MB_ICONERROR);
exit;
end;
//Log to file
FDebugFile.Add(FormatDateTime('mmmm. dddd. yyyy - hh/nn/ss.zzz AM/PM ',now)+s);
FDebugFile.saveToFile(FDebugFileName);
end;
procedure TlxcDebugger.ClearDebugLog ;
begin
FDebugFile.Clear ;
FDebugFile.SaveToFile(FDebugFileName);
end;
function TlxcDebugger.InIDE:boolean;assembler
asm
movsx eax,_IsInIDE
end; constructor TlxcFormat.Create ;//
begin
end;
procedure _lxcInitDebug;assembler;
const ___Entry:string='IsDebuggerPresent';___kernel32:string='kernel32.dll';
var __isInIDE:cardinal;
asm
push ___kernel32
call GetModuleHandle
push ___Entry
push eax
call GetProcAddress
call eax
mov _IsInIDE,al
end;
initialization
_lxcInitDebug;
_lxcDebugger:=TlxcDebugger.Create ;
end.
==================Returns the quoted version of a string.UnitSysUtilsCategoryString handling routinesfunction QuotedStr(const S: string): string;DescriptionUse QuotedStr to convert the string S to a quoted string. A single quote character (') is inserted at the beginning and end of S, and each single quote character in the string is repeated.Note: When working with multi-byte character systems (MBCS), use AnsiQuotedStr instead.
你贴的东西很不错,不过你贴的代码里也只是读取了Args里面的值,偶是想改变值再接着整个Args传给Format,而不是读取一个值来传。TO jacky_shen(jacky) :
QuotedStr不太合适吧,不过AnsiQuotedStr的代码可以拿来用用,但也只是实现了我的单引号变成两个单引号的功能,我的问题主要是在于FormatSql函数处理Args的时候赋值有问题。
我写这个FormatSql函数的想法是这样的:比如有个SQL语句
const
SqlFormat = 'UPDATE Table SET F1=%d, F2=''%s'', F3=''%s'',F4=''%s'' WHERE F5=%d';因为F2,F3,F4是字符串,原始信息中可能包含了单引号,需要替换成双引号,这个我想大家都知道了原来的写法是这样的:(StrForSql函数是完成替换单引号功能)var
Sql: String;
F1, F5: Integer;
F2, F3, F4: String;
begin
Sql := Format(SqlFormst, [F1, StrForSql(F2), StrForSql(F3), StrForSql(F4), F5]);
.....
end;上面的写法肯定是可以的,但如果参数多了不仅麻烦,而且有时候变量多了代码长了之后,
都很难看清楚哪个变量是替换过的,哪个是原始信息的如果由一个FormatSql函数来处理的话,在FormatSql函数外就不需要再去考虑这个单引号问题了,写代码也干净多了:Sql := FormatSql(SqlFormat, [F1, F2, F3, F4, F5]);但是现在我的FormatSql函数中有问题,编译是通过,但肯定是哪里搞错了……
var
I: Integer;
V: Variant;
S: String;
begin
for I := 0 to High(Args) do
begin
with Args[I] do
case VType of
vtString:
VString^ := StrForSql(VString^);
vtPChar:
begin
S := StrForSql(String(VPChar));
//FreeMem(VPChar, StrLen(VPChar));
GetMem(VPChar, Length(S) + 1);
StrPCopy(VPChar, S);
end;
vtAnsiString:
String(VAnsiString) := StrForSql(AnsiString(VAnsiString));
vtWideString:
WideString(VWideString) := WideString(StrForSql(WideString(VWideString)));
vtVariant:
begin
V := VVariant^;
if VarIsStr(V) then
begin
V := StrForSql(V);
VVariant^ := V;
end;
end;
end;
end;
Result := Format(SqlFormat, Args);
end;