我在delphi中调用excel,用来打印一些东西,代码如下:
function TTAppBasicForm.ShowExcelWindow(sCaption, sFileName: string;
  Cmd: array of string): boolean;
var
  i,j,iNum: integer;
  S: string;
begin
  with OleExcel do begin
    try
      //CreateObjectfromfile(sFileName,false);
      CreateObject('Excel.Application',False);
      OleObject.Application.WorkBooks.Open(sFileName);      OleObject.Application.ActiveWindow.Caption := sCaption;
      OleObject.Application.Caption := Application.MainForm.Caption;
      OleObject.Application.Application.WindowState := 3;
      OleObject.Application.ActiveWindow.WindowState := 2;
      Screen.Cursor := crHourGlass;
      for i:=1 to 52 do begin
        for j:=1 to 26 do begin
          S := OleObject.Application.Cells[i,j].Value;
          if System.Copy(S,1,2)='##' then begin
            iNum := StrToInt(System.Copy(S,3,Length(S)));
            if (iNum<0) or (iNum>Length(Cmd)-1) then
              OleObject.Application.Cells(i,j) := ''
            else
              OleObject.Application.Cells(i,j) := Cmd[iNum];
          end;
        end;
      end;
      Screen.Cursor := crDefault;
      OleObject.Application.Visible := true;
    except
      on e:exception do begin
        ShowErrMessage('Open excel error!'+#13+#10+e.Message,'E');
        result := false; exit;
      end;
    end
  end;
  result := True;
end;procedure TTAppBasicForm.CreateOleExcel;
begin
  OleExcel := TOleContainer.Create(self);
  with OleExcel do begin
    Visible := false;
    AllowInPlace := false;
    Parent := self;
    Align := alClient;
    OldStreamFormat := false;
  end;
end;可以运行,可是我发现程序中打开的excel进程好像在死循环,cpu占用99%,而且时间一直在涨.
请问是什么原因,怎么解决?我很少用ole,不是恨懂,望指教.

解决方案 »

  1.   

    你的单元中是否加入了comobj 或activex单元?你能确定你正确的初始化了OLE运行环境吗?(是否在建立OLE对象之前运行了OleInitilize 或CoInitilize).
    你的代码中此句:
      iNum := StrToInt(System.Copy(S,3,Length(S)));
      存在内存访问漏洞,copy函数将从S字符串的第3个字符开始拷贝Length(S)长度的子串,而此长度正好超过S字符串实际长度3个字节。strtoint函数有可能在对不规则文本转换时出错。
      

  2.   

    上面的大哥能说的详细一点吗?不大懂.
    copy的问题,delphi的帮助这样讲
    If Count specifies more characters or array elements than are available, only the characters or elements from S[Index] to the end of S are returned.
    那个地方如果不是数字会异常,但不会内存访问越界的.
      

  3.   

    你应该优化一下你的循环,你可以把循环次数修改小一点看看CPU占用率有多高?
      

  4.   

    var
      ExcelApp: OLEVariant;
    begin
      ExcelApp := CreateOleObject('Excel.Application');
      ExcelApp.Visible := false;
      ExcelApp.WorkBooks.Open('MyExcelFile.xls');  try
        ExcelApp.Cells[j,i+1].Value := '...';
        {...}
      finally
        if not VarIsEmpty(ExcelApp) then
        begin
          ExcelApp.Quit;
          ExcelApp := Unassigned;
        end;
      end;
    end;  説明:増加一個変量「ExcelApp: OLEVariant;」
       操作完、最後释放該変量。
      

  5.   

    你说对copy函数的解释是对的,delphi在线帮助说明如果索引超界将只返回由INDEX至变量未尾的数据。copy 这一句代码应该不是引起问题的原因。
      初始化ole执行环境是每一个使用ole对象的程序员都必须要做的事,只是当你将comobj或comsvr两个单元显示加入到你的引用单元列表中后,delphi会执行comobj单元的初始化代码如下:
    procedure InitComObj;
    begin
      if SaveInitProc <> nil then TProcedure(SaveInitProc);
      if (CoInitFlags <> -1) and Assigned(ComObj.CoInitializeEx) then
      begin
        NeedToUninitialize := Succeeded(ComObj.CoInitializeEx(nil, CoInitFlags));
        IsMultiThread := IsMultiThread or
          ((CoInitFlags and COINIT_APARTMENTTHREADED) <> 0) or
          (CoInitFlags = COINIT_MULTITHREADED);  // this flag has value zero
      end
      else
        NeedToUninitialize := Succeeded(CoInitialize(nil));
    end;
    其中,就有我所说的初始化com执行环境的关键代码CoInitializeEx/CoInitialize,对于这个函数的作用,windows sdk解释如下:
    The CoInitialize function initializes the Component Object Model(COM) library. You must initialize the library before you can call its functions. Applications must call CoInitialize before they make any other COM library calls with two exceptions: the 
    CoGetMalloc function, and memory allocation calls.
    其大意是你在使用com执行环境的任何api之间,你必须运行CoInitialize来初始化com库。而OleInitialize在内部也会调用CoInitialize来初始化ole执行环境。从你的代码来看,你并没有将delphi自带的Excel包装对象TExcelOLEObject,因此也就没有引用excel2000.pas这一单元文件。而excel2000.pas本身引用comobj单元。
      

  6.   

    谢谢各位,我原来是copy别人的代码,用的是oleContainer实现的,后来用OleVariant变量来实现就没问题.估计是我对OleContainer的用法有问题.感谢liangma(昆仑踏月) ,cronuz(cronus)和所有关注这个问题的人
      

  7.   

    最后,贴上源代码共享
    function TTAppBasicForm.ShowExcelWindow(sCaption, sFileName: string;
      Cmd: array of string): boolean;
    var
      OleExcel: Variant;
      i,j,iNum: integer;
      S: string;
      TmpFile: string;
    begin
      try
        OleExcel := CreateOleObject('Excel.Application');
      except
        ShowErrMessage('Open excel error!','E');
        result := false; exit;
      end;  try
        OleExcel.Application.WorkBooks.Open(sFileName);
        OleExcel.Application.ActiveWindow.Caption := sCaption;
        OleExcel.Application.Caption := Application.MainForm.Caption+'-'+sCaption;
        OleExcel.Application.WindowState := 3;
        OleExcel.Application.ActiveWindow.WindowState := 2;    Screen.Cursor := crHourGlass;
        for i:=1 to 52 do for j:=1 to 26 do begin
          S := OleExcel.Application.Cells[i,j].Value;
          if System.Copy(S,1,2)='##' then begin
            iNum := StrToInt(System.Copy(S,3,Length(S)));
            if (iNum<0) or (iNum>Length(Cmd)-1) then
              OleExcel.Application.Cells(i,j) := ''
            else
              OleExcel.Application.Cells(i,j) := Cmd[iNum];
          end;
        end;
        Screen.Cursor := crDefault;    TmpFile := RunPath+'Temp\Invoice_'+FormatDateTime('yymmdd-hhnnss',now)+'.xls';
        OleExcel.Application.ActiveWorkBook.SaveAs(TmpFile);
        OleExcel.Application.Visible := true;
      except
        on e:exception do begin
          OleExcel.Applicaton.DisplayAlerts := false;
          OleExcel.Applicaton.Quit;
          ShowErrMessage('Open excel error!'+#13+#10+e.Message,'E');
          result := false; exit;
        end;
      end;
      result := True;
    end;