function TYxCySms.SendEx(MobileNO: OleVariant; const SerialNum, Info,
  UserID, PhoneNO: WideString): WideString;
var
  I: Integer;
  sPhone: array of PChar;
  vRes : PChar;
begin
try
  Result:='';
  SetLength(sPhone,1);
  for I:=0 to StrToInt(PhoneNO) do
  begin
    sPhone[0] := PChar(VarToStr(MobileNO[I]));
    vRes := SendSMS(PChar(VarToStr(SN)),sPhone[0],PChar(VarToStr(Info)));
    if vRes<>'1' then
    begin
      Result := Result+'<'+sPhone[0]+'>'+'Error:'+strpas(vRes);
    end
    else
    begin
      with ASP_Exec,Parameters do
      begin
        Close;
        ProcedureName := 'YxCySms.BP_SmsSend;1';
        Refresh;
        ParamByName('@iOperator').Value := UserID;
        ParamByName('@vcSendMobile').Value := VarToStr(MobileNO[I]);
        ParamByName('@vcInfo').Value := Info;
        ExecProc;
      end;
    end;
  end;
  SetComplete;
except
  ON E:Exception do
  begin
    SetAbort;
    raise ERangeError.Create(E.Message);
  end;
end;
end;这段代码出会出一个非常怪的问题
当:StrToInt(PhoneNO)>=1时没有任何问题!
当:StrToInt(PhoneNO)=0是就出会错误!而且用异常也不能茯得错误,用高度模式可得到错误如下:
access violation at 0x01013494:read of address 0xffffffff
在系统的“事情查看器(本地)”出现的错误如下:事件类型: 错误
事件来源: Application Error
事件种类: 无
事件 ID: 1000
日期: 2005-04-01
事件: 15:55:48
用户: N/A
计算机: YXCY_RANDOMREN
描述:
错误应用程序 dllhost.exe,版本 5.1.2600.0,错误模块 yxcysmsserver.dll,版本 1.0.0.0,错误地址 0x00003494。有关更多信息,请参阅在 http://go.microsoft.com/fwlink/events.asp 的帮助和支持中心。
数据:
0000: 41 70 70 6c 69 63 61 74   Applicat
0008: 69 6f 6e 20 46 61 69 6c   ion Fail
0010: 75 72 65 20 20 64 6c 6c   ure  dll
0018: 68 6f 73 74 2e 65 78 65   host.exe
0020: 20 35 2e 31 2e 32 36 30    5.1.260
0028: 30 2e 30 20 69 6e 20 79   0.0 in y
0030: 78 63 79 73 6d 73 73 65   xcysmsse
0038: 72 76 65 72 2e 64 6c 6c   rver.dll
0040: 20 31 2e 30 2e 30 2e 30    1.0.0.0
0048: 20 61 74 20 6f 66 66 73    at offs
0050: 65 74 20 30 30 30 30 33   et 00003
0058: 34 39 34 0d 0a            494..   特求高人指点,谢谢!

解决方案 »

  1.   

    >>for I:=0 to StrToInt(PhoneNO) do
    不知道为什么会产生异常,但是,像你这样写,不是多循环了一次吗?
      

  2.   

    是不是先这样好一点:
    var
    j :integer;
    begin
    .
    .
    try
     j=StrToInt(PhoneNO);
    except
      j=0;
    end;for i=0  to j do
    begin
    end;
    ...end;
      

  3.   

    哎!为什么不用strtointdef这个函数啊?晕哦!
      

  4.   

    谢谢大家的关注,我又进行了深度的调试。发现他的执行过程是这样的!
    当StrToInt(PhoneNO)=1时
    Unit 调用的过程或函数
    MtsRdm TMtsDataModule.Deactivate (1)
    Classes TComponent._Release (2)
    VCLCom TVCLAutoObject.ObjQueryInterface (3)
    ComObj TComObject.ObjRelease (4)
    Classes TComponent._Release (5)
    ComObj TComObject.ObjRelease (6)
    然后程序就停在这里!
    当StrToInt(PhoneNO)=0时
    Unit 调用的过程或函数
    MtsRdm TMtsDataModule.Deactivate (1)
    Classes TComponent._Release (2)
    VCLCom TVCLAutoObject.ObjQueryInterface (3)
    ComObj TComObject.ObjRelease (4)
    Classes TComponent._Release (5)
    ComObj TComObject.ObjRelease (6)
    System TObject.Free "在这里发生错误" (7)
    各位大哥再帮忙看一下!
    谢谢了!
      

  5.   

    >>for I:=0 to StrToInt(PhoneNO) do
    不知道为什么会产生异常,但是,像你这样写,不是多循环了一次吗?
    不会多循环的啦
    其实PhoneNO是数组MobileNO: OleVariant的成员个数!
      

  6.   

    function TYxCySms.SendEx(MobileNO: OleVariant; const SerialNum, Info,
      UserID, PhoneNO: WideString): WideString;
    var
      I: Integer;
      sPhone: array of PChar;
      vRes : PChar;
    begin
    try
      Result:='';
      SetLength(sPhone,1);
      for I:=0 to StrToInt(PhoneNO) do //应该是这行的问题, PhoneNO的长度跟MobileNo的长度一致?
      begin
        sPhone[0] := PChar(VarToStr(MobileNO[I])); //这边可能会引起下标越界问题
        vRes := SendSMS(PChar(VarToStr(SN)),sPhone[0],PChar(VarToStr(Info)));
        if vRes<>'1' then
        begin
          Result := Result+'<'+sPhone[0]+'>'+'Error:'+strpas(vRes);
        end
        else
        begin
          with ASP_Exec,Parameters do
          begin
            Close;
            ProcedureName := 'YxCySms.BP_SmsSend;1';
            Refresh;
            ParamByName('@iOperator').Value := UserID;
            ParamByName('@vcSendMobile').Value := VarToStr(MobileNO[I]);
            ParamByName('@vcInfo').Value := Info;
            ExecProc;
          end;
        end;
      end;
      SetComplete;
    except
      ON E:Exception do
      begin
        SetAbort;
        raise ERangeError.Create(E.Message);
      end;
    end;
    end;//另外肯定不会是TObject.Free的问题, 别再调进去了。
      

  7.   

    >>不会多循环的啦 其实PhoneNO是数组MobileNO: OleVariant的成员个数!
    如果MobileNO: OleVariant的成员个数是0,那么sPhone[0] := PChar(VarToStr(MobileNO[I]));你又去访问MobileNO[0],这不是访问一个并不存在的对象吗?怎么会不出问题呢?另外,for I:=0 to StrToInt(PhoneNO) do...确实会多循环一次,应该改成:
    for I:=0 to StrToInt(PhoneNO)-1 do...
    这样保证不会再出现你的所谓的错误了!
      

  8.   

    数组应该是从0开始的吧??
    MobileNO[0] 这样访问没有问题啊
    能取出其中的值来啊!!
    还有我要说明的是
    无论StrToInt(PhoneNO)的值是多少,我的函数都是完整的按我想要的方式在执行!
    比如StrToInt(PhoneNO)>=0 则这段
    sPhone[0] := PChar(VarToStr(MobileNO[I]));
        vRes := SendSMS(PChar(VarToStr(SN)),sPhone[0],PChar(VarToStr(Info)));
        if vRes<>'1' then
        begin
          Result := Result+'<'+sPhone[0]+'>'+'Error:'+strpas(vRes);
        end
        else
        begin
          with ASP_Exec,Parameters do
          begin
            Close;
            ProcedureName := 'YxCySms.BP_SmsSend;1';
            Refresh;
            ParamByName('@iOperator').Value := UserID;
            ParamByName('@vcSendMobile').Value := VarToStr(MobileNO[I]);
            ParamByName('@vcInfo').Value := Info;
            ExecProc;
          end;
        end;
    代码执行1次
    比如StrToInt(PhoneNO)>=N 则这段
    sPhone[0] := PChar(VarToStr(MobileNO[I]));
        vRes := SendSMS(PChar(VarToStr(SN)),sPhone[0],PChar(VarToStr(Info)));
        if vRes<>'1' then
        begin
          Result := Result+'<'+sPhone[0]+'>'+'Error:'+strpas(vRes);
        end
        else
        begin
          with ASP_Exec,Parameters do
          begin
            Close;
            ProcedureName := 'YxCySms.BP_SmsSend;1';
            Refresh;
            ParamByName('@iOperator').Value := UserID;
            ParamByName('@vcSendMobile').Value := VarToStr(MobileNO[I]);
            ParamByName('@vcInfo').Value := Info;
            ExecProc;
          end;
        end;
    代码执行N+1次
    然后再执行以下代码
      SetComplete;
    except
      ON E:Exception do
      begin
        SetAbort;
        raise ERangeError.Create(E.Message);
      end;
    end;
    end;
    并且都能成功执行到最的一个end;
    (以上我是用断点测试了的,是这样执行的,绝对没问题!!)然后怪事说出来了!StrToInt(PhoneNO)=0时要出错!
    我又设置断点进行了深度的调试。发现他的执行过程是这样的!
    (执行到最后一个End,再按F8,他们的步骤执行如下!)
    当StrToInt(PhoneNO)=1时
    Unit单元 调用的过程或函数
    MtsRdm TMtsDataModule.Deactivate (1)
    Classes TComponent._Release (2)
    VCLCom TVCLAutoObject.ObjQueryInterface (3)
    ComObj TComObject.ObjRelease (4)
    Classes TComponent._Release (5)
    ComObj TComObject.ObjRelease (6)
    然后程序就停在这里!
    当StrToInt(PhoneNO)=0时
    Unit 调用的过程或函数
    MtsRdm TMtsDataModule.Deactivate (1)
    Classes TComponent._Release (2)
    VCLCom TVCLAutoObject.ObjQueryInterface (3)
    ComObj TComObject.ObjRelease (4)
    Classes TComponent._Release (5)
    ComObj TComObject.ObjRelease (6)
    System TObject.Free "在这里发生错误" (7)
    各位大哥再帮忙看一下!
    谢谢了!
      

  9.   

    >>不会多循环的啦 其实PhoneNO是数组MobileNO: OleVariant的成员个数!
    如果MobileNO: OleVariant的成员个数是0,那么sPhone[0] := PChar(VarToStr(MobileNO[I]));你又去访问MobileNO[0],这不是访问一个并不存在的对象吗?怎么会不出问题呢?回:
    PhoneNO是我在前台传上来的值,是这样取的 PhoneNO:=IntToStr(high(MobileNO)),这个应该不是成员个数,但我忘记怎么表达了,^_^ <MobileNO在前台是一个数组>
    所以MobileNO[0],是没有问题的吧??我测试了,有值!并且是正确的!
      

  10.   

    我有做了如下的测试!
    function TYxCySms.SendEx(MobileNO: OleVariant; const SerialNum, Info,
      UserID, PhoneNO: WideString): WideString;
    var
      vRes : PChar;
    begin
      try
        Result:='';
        vRes := SendSMS(PChar(VarToStr(SN)),PChar(1399054****),PChar(VarToStr(Info)));
        if vRes<>'1' then
          Result := Result+'<'+sPhone[0]+'>'+'Error:'+strpas(vRes);
        SetComplete;
      except
        ON E:Exception do
        begin
          SetAbort;
          raise ERangeError.Create(E.Message);
        end;
      end;
    end;
    这样的话,也是要出同样的错误!就和当StrToInt(PhoneNO)=0我错误一样
    但我一直想不明白的是为什么当StrToInt(PhoneNO)>=1的时候又没有任何问题呢?
    谢谢大家
    如果问题解决,我决定再加100分!!
      

  11.   

    >>PhoneNO:=IntToStr(high(MobileNO)),
    high是计算数组的边界的上届,如果数组下界为0,像你这样做是正确的~~~
    但是,问题在于high使用在动态数组上有时会出现问题,例如,当数组成员数为0时,high可能返回1
    感觉使用high不好,使用Length好一些你给出的调试数据感觉是在减少一个对象(应该是MobileNO)的引用计数,当PhoneNO为0的时候这个对象的引用计数减少到了0,结果要被销毁~~~销毁这个对象的时候出了问题,应该还是入口参数(MobileNO)有问题~~~前台先用Length测试一下 if length(MobileNO) =0 ,就不用再PhoneNO:=IntToStr(high(MobileNO))直接退出算了~~
      

  12.   

    我觉得应该不是我的代码的问题,你再看看三楼的代码,一样的要出问题!
    我有减少了一个参数,但还是要出问题呢!
    function TYxCySms.SendOne(const MobileNO, SerialNum, Info,
      UserID: WideString): WideString;
    var
      vRes : PChar;
    begin
      try
        Result:='';
        vRes := SendSMS(PChar(VarToStr(SN)),PChar(VarToStr(MobileNO)),PChar(VarToStr(Info)));
        if vRes<>'1' then
          Result := Result+'<'+MobileNO+'>'+'Error:'+strpas(vRes);
        SetComplete;
      except
        SetAbort;
        Raise;
      end;
    end;
    注:SendSMS是一个DLL中的函数,会不会是这个引起的呢?
    谢谢!
      

  13.   

    有的什么数据库?MS OR Sybase OR Mysql OR Oracl
      

  14.   

    兄弟,虽然你减少了一个参数,但是vRes := SendSMS(PChar(VarToStr(SN)),PChar(VarToStr(MobileNO)),PChar(VarToStr(Info)));---PChar(VarToStr(MobileNO))同样增加了MobileNO的引用计数~~~至于是不是DLL中的函数引起的,不清楚~~~~~~~~~~`
      

  15.   

    我又作了如下有变动,但还是有错,哎!
      try
        Result:='';
        vRes := SendSMS(PChar(VarToStr(SN)),PChar('1399054****'),PChar('测试单独发送'));
        if vRes<>'1' then
          Result := Result+'<1399054****>Error:'+strpas(vRes);
        SetComplete;
      except
        ON E:Exception do
        begin
          SetAbort;
          Raise ERangeError.Create(E.Message);
        end;
      end;
      

  16.   

    SetComplete;可以把它的实现贴出来吗?
      

  17.   

    你可以这样试一下:
      将[I]改为[LOW()+I]
      

  18.   

    选择 Project->Options 打开对话框中选 Linker 页,在 Map file 组合框中选 Detailed,现在从新编译会得到一个 .map 文件,它是纯文本的,用记事本可以打开。
    现在运行你的程序,记下出现异常时崩溃地址,将这个地址减去 40100 结果比如说是 1234 ,在 .map 文件中搜索这个地址,没有的话就去掉末尾数字比如 123 ,再搜一下。看结果里最接近的,恩,就是这里引起崩溃的。