Текущий архив: 2007.09.23;
Скачать: CL | DM;
ВнизSafeArray Найти похожие ветки
← →
alex_s (2006-01-11 10:01) [0]Помогите плиз разобраться со структурой SafeArray.
Мне нужно получить данные c OPC-сервера. Имеем процедуру:
SyncRead(Source:integer; NumItems:integer; var ServerHandles:PSafeArray; out Values:PSafeArray; out Errors:PSafeArray; out Qualities:oleVariant; out TimeStamps:oleVariant);
где Source - источник данных
NumItems - кол-во считываемых значений
Подскажите, что я делаю не так:
procedure TForm1.Button1Click(Sender: TObject);
var Qual,TimeS:oleVariant;
A1,A2,A3:oleVariant;
SH,Val,Err:PSafeArray;
begin
A1:=VarArrayCreate([0,1],varVariant);
A1[0]:=My_OPCItem.ServerHandle;
A2:=VarArrayCreate([0,1],varVariant);
A3:=VarArrayCreate([0,1],varVariant);
SH:=PSafeArray(TVarData(A1).VArray);
Val:=PSafeArray(TVarData(A2).VArray);
Err:=PSafeArray(TVarData(A3).VArray);
My_OPCGroup.SyncRead(2,1,SH,Val,Err,Qual,TimeS);
end;
На My_OPCGroup.SyncRead(2,1,SH,Val,Err,Qual,TimeS) выскакивает ошибка.
← →
AbrosimovA (2006-01-11 11:32) [1]Для получения внятного ответа по-существу требуется указывать текст ошибки.
← →
alex_s (2006-01-11 11:56) [2]Текст ошибки такой:
Access violation at address 1F506C31 in module "OCSDAAuto.dll".
Read of address 00000058.
← →
Набережных С. © (2006-01-11 13:02) [3]А точно элементы массивов должны быть вариантами?
И откуда взята декларация SyncRead? Есть некоторые сомнения в правильности приведенного описания, вот это:
> var ServerHandles:PSafeArray; out Values:PSafeArray; out Errors:PSafeArray
как-то подозрительно выглядит.
А если декларация соответствует, то вызывается неправильно - Values и Errors должны вернуть указатель на SafeArray, передавать при вызове в них ничего не надо.
← →
AbrosimovA (2006-01-11 13:52) [4]Скорее всего нужно так:
function ReadOPCItemProperties(Group: IUnknown; ItemServerHandle: OPCHANDLE;
var ItemTimeStamp: TFileTime; var ItemValue: OleVariant;
var ItemQuality: Word): HResult;
var
SyncIOIf: IOPCSyncIO;
Errors: PResultList;
ItemValues: POPCITEMSTATEARRAY;
begin
Result := E_FAIL;
Errors:=nil;
ItemValues:=nil;
if Group = nil then Exit;
try
SyncIOIf := Group as IOPCSyncIO;
except
SyncIOIf := nil;
Exit;
end;
Result := SyncIOIf.Read(OPC_DS_CACHE, 1, @ItemServerHandle, ItemValues,
Errors);
if Succeeded(Result) then
begin
Result := Errors[0];
CoTaskMemFree(Errors);
Errors:=nil;
ItemValue := ItemValues[0].vDataValue;
ItemQuality := ItemValues[0].wQuality;
ItemTimeStamp := ItemValues[0].ftTimeStamp;
VariantClear(ItemValues[0].vDataValue);
CoTaskMemFree(ItemValues);
ItemValues:=nil;
end;
end;
← →
alex_s (2006-01-11 15:02) [5]
> И откуда взята декларация SyncRead?
Путем импорта библиотеки типов (OCSDAAuto.dll) получен модуль OPCAutomation_TLB.pas.
Вот выдержки описание:
unit OPCAutomation_TLB;
...
// *********************************************************************//
// Interface: IOPCGroup
// Flags: (4416) Dual OleAutomation Dispatchable
// GUID: {49C687D9-2A18-11D3-A5BC-0050043EC1B2}
// *********************************************************************//
IOPCGroup = interface(IDispatch)
["{49C687D9-2A18-11D3-A5BC-0050043EC1B2}"]
...
procedure SyncRead(Source: Smallint; NumItems: Integer;
var ServerHandles: PSafeArray; out Values: PSafeArray;
out Errors: PSafeArray; out Qualities: OleVariant;
out TimeStamps: OleVariant); safecall;
...
end;
// *********************************************************************//
// DispIntf: IOPCGroupDisp
// Flags: (4416) Dual OleAutomation Dispatchable
// GUID: {49C687D9-2A18-11D3-A5BC-0050043EC1B2}
// *********************************************************************//
IOPCGroupDisp = dispinterface
["{49C687D9-2A18-11D3-A5BC-0050043EC1B2}"]
...
procedure SyncRead(Source: Smallint; NumItems: Integer;
var ServerHandles: {??PSafeArray}OleVariant;
out Values: {??PSafeArray}OleVariant;
out Errors: {??PSafeArray}OleVariant;
out Qualities: OleVariant;
out TimeStamps: OleVariant); dispid 1610743828;
...
end;
// *********************************************************************//
// OLE Server Proxy class declaration
// Server Object : TOPCGroup
// Help String : OPC Automation Group
// Default Interface: IOPCGroup
// Def. Intf. DISP? : No
// Event Interface: DIOPCGroupEvent
// TypeFlags : (2) CanCreate
// *********************************************************************//
{$IFDEF LIVE_SERVER_AT_DESIGN_TIME}
TOPCGroupProperties= class;
{$ENDIF}
TOPCGroup = class(TOleServer)
private
...
protected
...
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
...
procedure SyncRead(Source: Smallint; NumItems: Integer;
var ServerHandles: PSafeArray;
out Values: PSafeArray;
out Errors: PSafeArray); overload;
procedure SyncRead(Source: Smallint; NumItems: Integer;
var ServerHandles: PSafeArray;
out Values: PSafeArray;
out Errors:PSafeArray;
out Qualities: OleVariant); overload;
procedure SyncRead(Source: Smallint; NumItems: Integer;
var ServerHandles: PSafeArray;
out Values: PSafeArray;
out Errors: PSafeArray;
out Qualities: OleVariant;
out TimeStamps: OleVariant); overload;
published
...
end;
procedure TOPCGroup.SyncRead(Source: Smallint; NumItems: Integer; var ServerHandles: PSafeArray;
out Values: PSafeArray; out Errors: PSafeArray);
begin
DefaultInterface.SyncRead(Source, NumItems, ServerHandles, Values, Errors, EmptyParam, EmptyParam);
end;
procedure TOPCGroup.SyncRead(Source: Smallint; NumItems: Integer; var ServerHandles: PSafeArray;
out Values: PSafeArray; out Errors: PSafeArray;
out Qualities: OleVariant);
begin
DefaultInterface.SyncRead(Source, NumItems, ServerHandles, Values, Errors, Qualities, EmptyParam);
end;
procedure TOPCGroup.SyncRead(Source: Smallint; NumItems: Integer; var ServerHandles: PSafeArray;
out Values: PSafeArray; out Errors: PSafeArray;
out Qualities: OleVariant; out TimeStamps: OleVariant);
begin
DefaultInterface.SyncRead(Source, NumItems, ServerHandles, Values, Errors, Qualities, TimeStamps);
end;
> А если декларация соответствует, то вызывается неправильно
> - Values и Errors должны вернуть указатель на SafeArray,
> передавать при вызове в них ничего не надо.
A2:=VarArrayCreate([0,1],varVariant);
A3:=VarArrayCreate([0,1],varVariant);
Val:=PSafeArray(TVarData(A2).VArray);
Err:=PSafeArray(TVarData(A3).VArray);
это лишнее. Вы правы.
Ошибка скорее всего в передаче ServerHandles.
Может я его не так передаю.
Значение одной переменной читается:
procedure TForm1.Button2Click(Sender: TObject);
var v,q,ts:oleVariant;
begin
My_OPCItem:=My_OPCGroup.OPCItems.Item(Memo1.ItemIndex+1);
My_OPCItem.Read(2,v,q,ts);
Edit16.Text:=IntToStr(v);
Edit17.Text:=IntToStr(q);
Edit18.Text:=TimeToStr(ts);
end;
Read(Source:integer; out Value:oleVariant; out Qualities:oleVariant;
out TimeStamps:oleVariant);
> AbrosimovA (11.01.06 13:52) [4]
Предлагаете использовать OPC Data Access Custom Interface Specification?
Но через OPC Data Access Automation Specification тоже ведь должно работать?
← →
Набережных С. © (2006-01-11 18:30) [6]
> alex_s (11.01.06 15:02) [5]
Я бы предпочел увидеть описание интерфейса на IDL, но да ладно, вряд-ли здесь есть ошибка.
> Ошибка скорее всего в передаче ServerHandles.
Скорее всего. Думаю, нужно разбираться с типом и, возможно, количеством элементов массива, которые ожидает метод. И, конечно, учитывать наличие модификатора VAR при этом параметре.
← →
AbrosimovA (2006-01-12 11:03) [7]Вообще-то в opcda20_auto.doc процедура описана следующим образом:
SyncRead(Source As Integer, NumItems As Long, ServerHandles() As Long, ByRef Values() As Variant, ByRef Errors() As Long, Optional ByRef Qualities As Variant, Optional ByRef TimeStamps As Variant)
Страницы: 1 вся ветка
Текущий архив: 2007.09.23;
Скачать: CL | DM;
Память: 0.48 MB
Время: 0.04 c