dll的一段代码,程序调用第一次会出现地址错误,以后就不会有,经过多方测试发现 hisitemno,samplelist 两个tstringlist不能同时释放,只释放其中的一个就没有错误产生,不明是什么问题,请各位专家不吝赐教,谢谢!谢谢!代码如下:
function f_tubecount(jyxmh: pchar): pchar;stdcall;
var
  hisitemno, samplelist: TStrings;
  bloodtype: array[0..3] of integer; 
  jyxmhstr, btstr: string;
  tempquery: tadoquery;
  resultstr: string;
  i, n: integer;
begin
  result := '';
  for i := 0 to 3 do
    bloodtype[i] := 0;
  tempquery := tadoquery.Create(nil);
  tempquery.Connection := dmmain.ADOConMain;
    hisitemno := tstringlist.Create;
  samplelist := tstringlist.Create;
  try
    jyxmhstr := string(jyxmh); //pchar to string
    i := pos('|', jyxmhstr);
    n := 0;
    while i > 0 do
    begin
      hisitemno.Add(copy(jyxmhstr, 1, i - 1));
      delete(jyxmhstr, 1, i);
      i := pos('|', jyxmhstr);
      n := n + 1;
    end;
    for i := 0 to hisitemno.Count - 1 do
    begin
      OpenQuery(TempQuery, 'select * from testitem where orderno=''' + hisitemno.Strings[i] + '''');
      if not tempquery.IsEmpty then
      begin
        hisitemno.Strings[i] := tempquery.fieldbyname('itemno').asstring;
        SaveToLog('lis代码:'+hisitemno.Strings[i]);
      end
      else
        application.MessageBox(PCHAR('!' + hisitemno.Strings[i]), '警告', MB_OK + MB_ICONINFORMATION);
    end;
    for i := 0 to hisitemno.Count - 1 do
    begin
      OpenQuery(TempQuery, 'select * from Samplingitem where itemno=' + hisitemno.Strings[i]);
      if not tempquery.IsEmpty then
      begin
        if samplelist.IndexOf(tempquery.fieldbyname('SamplingGroupNo').AsString) < 0 then
          samplelist.Add(tempquery.fieldbyname('SamplingGroupNo').AsString);
      end;
    end;
    for i := 0 to samplelist.Count - 1 do
    begin
      OpenQuery(TempQuery, 'select * from Samplinggroup where samplinggroupno=' + samplelist.Strings[i]);
      if not tempquery.IsEmpty then
        btstr := tempquery.fieldbyname('bloodtype').asstring;
      if trim(btstr) = '常规血液' then
        bloodtype[0] := bloodtype[0] + 1;
      if trim(btstr) = '生化血液' then
        bloodtype[1] := bloodtype[1] + 1;
      if trim(btstr) = '血凝血液' then
        bloodtype[2] := bloodtype[2] + 1;
      if trim(btstr) = '血沉血液' then
        bloodtype[3] := bloodtype[3] + 1;
   end;
    tempquery.Close;
    resultstr := inttostr(bloodtype[0]) + '|' + inttostr(bloodtype[1]) + '|' + inttostr(bloodtype[2]) + '|' + inttostr(bloodtype[3]);
       result :=pchar(resultstr+CHAR(0));
  finally
    HISITEMNO.FREE;
    SAMPLELIST.FREE;
   tempquery.FREE;
  end;
end;

解决方案 »

  1.   


    function f_tubecount(jyxmh: pchar): pchar;stdcall; 
    var 
      hisitemno, samplelist: TStrings; 
      bloodtype: array[0..3] of integer; 
      jyxmhstr, btstr: string; 
      tempquery: tadoquery; 
      resultstr: string; 
      i, n: integer; 
    begin 
      result := ''; 
      for i := 0 to 3 do 
        bloodtype[i] := 0; 
      tempquery := tadoquery.Create(nil); 
      tempquery.Connection := dmmain.ADOConMain; 
        hisitemno := tstringlist.Create; 
      samplelist := tstringlist.Create; 
      try 
        jyxmhstr := string(jyxmh); //pchar to string 
        i := pos(' ¦', jyxmhstr); 
        n := 0; 
        while i > 0 do 
        begin 
          hisitemno.Add(copy(jyxmhstr, 1, i - 1)); 
          delete(jyxmhstr, 1, i); 
          i := pos(' ¦', jyxmhstr); 
          n := n + 1; 
        end; 
        for i := 0 to hisitemno.Count - 1 do 
        begin 
          OpenQuery(TempQuery, 'select * from testitem where orderno=''' + hisitemno.Strings[i] + ''''); 
          if not tempquery.IsEmpty then 
          begin 
            hisitemno.Strings[i] := tempquery.fieldbyname('itemno').asstring; 
            SaveToLog('lis代码:'+hisitemno.Strings[i]); 
          end 
          else 
            application.MessageBox(PCHAR('!' + hisitemno.Strings[i]), '警告', MB_OK + MB_ICONINFORMATION); 
        end; 
        for i := 0 to hisitemno.Count - 1 do 
        begin 
          OpenQuery(TempQuery, 'select * from Samplingitem where itemno=' + hisitemno.Strings[i]); 
          if not tempquery.IsEmpty then 
          begin 
            if samplelist.IndexOf(tempquery.fieldbyname('SamplingGroupNo').AsString) < 0 then 
              samplelist.Add(tempquery.fieldbyname('SamplingGroupNo').AsString); 
          end; 
        end; 
        for i := 0 to samplelist.Count - 1 do 
        begin 
          OpenQuery(TempQuery, 'select * from Samplinggroup where samplinggroupno=' + samplelist.Strings[i]); 
          if not tempquery.IsEmpty then 
            btstr := tempquery.fieldbyname('bloodtype').asstring; 
          if trim(btstr) = '常规血液' then 
            bloodtype[0] := bloodtype[0] + 1; 
          if trim(btstr) = '生化血液' then 
            bloodtype[1] := bloodtype[1] + 1; 
          if trim(btstr) = '血凝血液' then 
            bloodtype[2] := bloodtype[2] + 1; 
          if trim(btstr) = '血沉血液' then 
            bloodtype[3] := bloodtype[3] + 1; 
      end; 
        tempquery.Close; 
        resultstr := inttostr(bloodtype[0]) + ' ¦' + inttostr(bloodtype[1]) + ' ¦' + inttostr(bloodtype[2]) + ' ¦' + inttostr(bloodtype[3]); 
          result :=pchar(resultstr+CHAR(0)); 
      finally 
        HISITEMNO.FREE; 
        SAMPLELIST.FREE; 
      tempquery.FREE; 
      end; 
    end;
      

  2.   

    返回值不能用pchar,在函数返回之前PChar指向的那块数据区会被清理掉,因为它是局部变量,并且已经没有了string类型的引用尝试使用PWideChar,uses ActiveX,并写
    result := SysAllocString(resultstr+CHAR(0));
    exe中使用f_tubecount用完字符串后也要用SysFreeString来释放
      

  3.   

    我没看出阿九的代码跟楼主的有啥区别,能否标明一下。另外楼上的说法不敢苟同, 函数返回 PChar 的时候,系统会 write-copy。这不同于作为参数使用pchar。
    我看了下代码,去掉了 ado 相关的部分,代码执行没问题,所以我怀疑问题出在 ado 的操作上。楼主再耐心点跟一下看看。 有实际数据可能调试起来会相对简单些。
      

  4.   

    经过多次测试hisitemno,samplelist 两个tstringlist 任意一个释放都有可能会触发错误,两个同时释放肯定在第一次调用时出现地址异常,让后在反复调用就没有问题,我也怀疑是ado的部分因为数据连接被开始初始化后常驻内存,可能有处理不到位的情况,但为什么和stringlist有关的,另外我目前没有释放这两个stringlist,请教各位有什么后果?只是多占内存吗?谢谢各位!