invoke方法带回返回值的问题,大家帮我捉虫 ( 积分: 200 )

  • 主题发起人 主题发起人 crazycock
  • 开始时间 开始时间
C

crazycock

Unregistered / Unconfirmed
GUEST, unregistred user!
invoke方法带回返回值的问题

有多个参数传入,需要传出多个结果,所以考虑到使用传一个指针的方法来实现,当然是in proc的前提下。

type
ParamRecord=record
ParamValueArray:array[0..255] of String;
ParamTypeArray:array[0..255] of Integer;
ParamCount:Integer;
ResultValue:String;
ResultType:Integer;
end;
PParamRecord=^ParamRecord;

var
pr:ParamRecord; //前面有定义
//------
paramcls:TParamCls;//某个类
HR:HResult;
MyIntf:IDispatch;
MyDispParams: TDispParams;
MyParams: array[0..1] of TVariantArg;
di:TDispID;
begin
......

HR:=OleContainer1.OleObjectInterface.QueryInterface(myGUID,MyIntf);
OleCheck(HR);
// 参数压栈是反序,不过这里只有一个参数,无所谓了。
MyParams[0].vt := VT_UI4;
MyParams[0].ulVal := Cardinal(@pr); //我把指针转成Cardinal,然后在ocx中再用pPR:=Pointer(Value)的方法转回去
with MyDispParams do
begin
rgvarg := @MyParams;
rgdispidNamedArgs := nil;
cArgs := 1;
cNamedArgs := 0;
end;
HR:=MyIntf.GetIDsOfNames(GUID_NULL,@Names,1,0,@di);
OleCheck(HR);
HR:=MyIntf.Invoke(di,GUID_NULL,0,DISPATCH_METHOD,MyDispParams,nil, nil, nil); // (关键位置)
OleCheck(HR);
//更新内存变量的值
paramcls.ParamValue:=pr.ResultValue;

......
end;

============================
ocx中的方法的代码

procedure TafxBaseFunc.func_Add(Value: SYSUINT);
var
pPR:PParamRecord;
i:Integer;
fSUM:Double;
begin //exit; <----
pPR:=Pointer(Value);
try
fSUM:=0;
for i:=0 to pPR.ParamCount-1 do
begin
case pPR.ParamTypeArray of
VT_UINT,VT_INT,VT_I2,VT_I4,VT_R4,VT_R8:fSUM:=fSUM+StrToFloat(pPR.ParamValueArray);
end;
end;
pPR.ResultValue:=FloatToStr(fSUM);
pPR.ResultType:=VT_R8;
except
pPR.ResultValue:='0';
pPR.ResultType:=VT_R8;
end;
end;

经过多个方面的测试,有以下现象和结论:
1。代码能运行,可以得到所需结果,但是平均30秒到1分钟左右,会出现错误,有些错误可以捕捉,有些则直接导致程序关闭;
2。如果把ocx中func_Add的代码屏蔽,即不做运算,则不会有错误出现;

结论:指针访问出现错误。

问题:哪个地方的写法导致了这个错误呢?怎么解决?注:程序中有可能出现临界区的地方都使用了互斥,而且经过检测排除了那种可能。
 
invoke方法带回返回值的问题

有多个参数传入,需要传出多个结果,所以考虑到使用传一个指针的方法来实现,当然是in proc的前提下。

type
ParamRecord=record
ParamValueArray:array[0..255] of String;
ParamTypeArray:array[0..255] of Integer;
ParamCount:Integer;
ResultValue:String;
ResultType:Integer;
end;
PParamRecord=^ParamRecord;

var
pr:ParamRecord; //前面有定义
//------
paramcls:TParamCls;//某个类
HR:HResult;
MyIntf:IDispatch;
MyDispParams: TDispParams;
MyParams: array[0..1] of TVariantArg;
di:TDispID;
begin
......

HR:=OleContainer1.OleObjectInterface.QueryInterface(myGUID,MyIntf);
OleCheck(HR);
// 参数压栈是反序,不过这里只有一个参数,无所谓了。
MyParams[0].vt := VT_UI4;
MyParams[0].ulVal := Cardinal(@pr); //我把指针转成Cardinal,然后在ocx中再用pPR:=Pointer(Value)的方法转回去
with MyDispParams do
begin
rgvarg := @MyParams;
rgdispidNamedArgs := nil;
cArgs := 1;
cNamedArgs := 0;
end;
HR:=MyIntf.GetIDsOfNames(GUID_NULL,@Names,1,0,@di);
OleCheck(HR);
HR:=MyIntf.Invoke(di,GUID_NULL,0,DISPATCH_METHOD,MyDispParams,nil, nil, nil); // (关键位置)
OleCheck(HR);
//更新内存变量的值
paramcls.ParamValue:=pr.ResultValue;

......
end;

============================
ocx中的方法的代码

procedure TafxBaseFunc.func_Add(Value: SYSUINT);
var
pPR:PParamRecord;
i:Integer;
fSUM:Double;
begin //exit; <----
pPR:=Pointer(Value);
try
fSUM:=0;
for i:=0 to pPR.ParamCount-1 do
begin
case pPR.ParamTypeArray of
VT_UINT,VT_INT,VT_I2,VT_I4,VT_R4,VT_R8:fSUM:=fSUM+StrToFloat(pPR.ParamValueArray);
end;
end;
pPR.ResultValue:=FloatToStr(fSUM);
pPR.ResultType:=VT_R8;
except
pPR.ResultValue:='0';
pPR.ResultType:=VT_R8;
end;
end;

经过多个方面的测试,有以下现象和结论:
1。代码能运行,可以得到所需结果,但是平均30秒到1分钟左右,会出现错误,有些错误可以捕捉,有些则直接导致程序关闭;
2。如果把ocx中func_Add的代码屏蔽,即不做运算,则不会有错误出现;

结论:指针访问出现错误。

问题:哪个地方的写法导致了这个错误呢?怎么解决?注:程序中有可能出现临界区的地方都使用了互斥,而且经过检测排除了那种可能。
 
请将下面语句中的三个nil用具体的变量代替:
HR:=MyIntf.Invoke(di,GUID_NULL,0,DISPATCH_METHOD,MyDispParams,nil, nil, nil);
该函数原型是:
function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; override
当Invoke执行过程中,系统会试图将返回结果保存到VarResult中,异常信息保存到ExceptInfo中,参数错误信息保存到ArgErr中;
 
谢谢指点。你提到的问题,这些信息我原来也做了保存,不过这些信息对我来说用处不大,只是不知道这些错误不保存是否就会被抛出?
 
其他人都不能帮忙一下么????
 
没有人回答。唉,高手总是没空的。
 
关注中也,居然说我关税!
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
763
import
I
后退
顶部