下面的函数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;

解决方案 »

  1.   

    我以前写的,看对你是否有帮助:
    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;
      

  2.   

    procedure TlxcDebugger.Trace(args:array of const);
                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;
      

  3.   


                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.
      

  4.   

    用QuotedStr这个函数看看。QuotedStr function
    ==================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.
      

  5.   

    TO Eastunfail(浴血雏龙)==(恶鱼杀手) :
       你贴的东西很不错,不过你贴的代码里也只是读取了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函数中有问题,编译是通过,但肯定是哪里搞错了……
      

  6.   

    修正版本:传入ShortString, AnsiString(string),WideString,Variant,OleVariant等类型运行结果正确了,就是PChar类型不知道如何处理以前的内容的内存哪位高手分析分析,是否会有内存泄漏发生啊?function FormatSql(const SqlFormat: String; const Args: array of const): String;
    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;
      

  7.   

    不用这个了,用SQL支持的参数标记 "?"处理更好多谢各位……