尝试在 Delphi 中构建 Excel RTD 服务器
Trying to build Excel RTD server in Delphi
我正在尝试在 Delphi 中为 Excel 构建一个 RTD 服务器,但我无法使这部分代码工作:
function TRtdServer.RefreshData(var TopicCount: Integer): PSafeArray;
//Called when Excel is requesting a refresh on topics. RefreshData will be called
//after an UpdateNotify has been issued by the server. This event should:
//- supply a value for TopicCount (number of topics to update)
//- The data returned to Excel is an Object containing a two-dimensional array.
// The first dimension represents the list of topic IDs.
// The second dimension represents the values associated with the topic IDs.
var
Data : OleVariant;
begin
//Create an array to return the topics and their values
//note:The Bounds parameter must contain an even number of values, where each pair of values specifies the upper and lower bounds of one dimension of the array.
Data:=VarArrayCreate([0, 1, 0, 0], VT_VARIANT);
Data[0,0]:=MyTopicId;
Data[1,0]:=GetTime();
if Main.Form1.CheckBoxExtraInfo.Checked then Main.Form1.ListBoxInfo.Items.Add('Excel called RefreshData. Returning TopicId: '+IntToStr(Data[0,0])+' and Value: '+Data[1,0]);
TopicCount:=1;
// RefreshTimer.Enabled:=true;
//Result:=PSafeArray(VarArrayAsPSafeArray(Data));
Result:=PSafeArray(TVarData(Data).VArray);
end;
我不确定这部分:
Result:=PSafeArray(TVarData(Data).VArray);
但它可以是代码的任何部分。
Excel 只是在包含 rtd() 函数调用的单元格中不显示任何结果。我确实设法在第一次 Excel 调用我的 "ConnectData" 函数时将结果输入到单元格中,这个简单的 returns 字符串而不是 PSafeArray(尽管第一次调用该函数失败产生结果 (N/A)。只有在 RTD() 调用中更改主题后,它才会显示结果(仅一次))
我的代码基于 https://blog.learningtree.com/excel-creating-rtd-server-c/
中的 C# 示例
谁能指出我正确的方向?
OleVariant
拥有它持有的数据,当它超出范围时将释放该数据。因此,您 return 正在使用指向 Excel 的无效 PSafeArray
指针。您需要:
在 return 之前释放数组指针的所有权:
function TRtdServer.RefreshData(var TopicCount: Integer): PSafeArray;
var
Data : OleVariant;
begin
...
Result := PSafeArray(TVarData(Data).VArray);
TVarData(Data).VArray = nil; // <-- add this
end;
使用SafeArrayCopy()
对数组进行复制,然后return复制:
uses
..., ActiveX;
function TRtdServer.RefreshData(var TopicCount: Integer): PSafeArray;
var
Data : OleVariant;
begin
...
OleCheck(
SafeArrayCopy(
PSafeArray(TVarData(Data).VArray),
Result
)
);
end;
我正在尝试在 Delphi 中为 Excel 构建一个 RTD 服务器,但我无法使这部分代码工作:
function TRtdServer.RefreshData(var TopicCount: Integer): PSafeArray;
//Called when Excel is requesting a refresh on topics. RefreshData will be called
//after an UpdateNotify has been issued by the server. This event should:
//- supply a value for TopicCount (number of topics to update)
//- The data returned to Excel is an Object containing a two-dimensional array.
// The first dimension represents the list of topic IDs.
// The second dimension represents the values associated with the topic IDs.
var
Data : OleVariant;
begin
//Create an array to return the topics and their values
//note:The Bounds parameter must contain an even number of values, where each pair of values specifies the upper and lower bounds of one dimension of the array.
Data:=VarArrayCreate([0, 1, 0, 0], VT_VARIANT);
Data[0,0]:=MyTopicId;
Data[1,0]:=GetTime();
if Main.Form1.CheckBoxExtraInfo.Checked then Main.Form1.ListBoxInfo.Items.Add('Excel called RefreshData. Returning TopicId: '+IntToStr(Data[0,0])+' and Value: '+Data[1,0]);
TopicCount:=1;
// RefreshTimer.Enabled:=true;
//Result:=PSafeArray(VarArrayAsPSafeArray(Data));
Result:=PSafeArray(TVarData(Data).VArray);
end;
我不确定这部分:
Result:=PSafeArray(TVarData(Data).VArray);
但它可以是代码的任何部分。 Excel 只是在包含 rtd() 函数调用的单元格中不显示任何结果。我确实设法在第一次 Excel 调用我的 "ConnectData" 函数时将结果输入到单元格中,这个简单的 returns 字符串而不是 PSafeArray(尽管第一次调用该函数失败产生结果 (N/A)。只有在 RTD() 调用中更改主题后,它才会显示结果(仅一次))
我的代码基于 https://blog.learningtree.com/excel-creating-rtd-server-c/
中的 C# 示例谁能指出我正确的方向?
OleVariant
拥有它持有的数据,当它超出范围时将释放该数据。因此,您 return 正在使用指向 Excel 的无效 PSafeArray
指针。您需要:
在 return 之前释放数组指针的所有权:
function TRtdServer.RefreshData(var TopicCount: Integer): PSafeArray; var Data : OleVariant; begin ... Result := PSafeArray(TVarData(Data).VArray); TVarData(Data).VArray = nil; // <-- add this end;
使用
SafeArrayCopy()
对数组进行复制,然后return复制:uses ..., ActiveX; function TRtdServer.RefreshData(var TopicCount: Integer): PSafeArray; var Data : OleVariant; begin ... OleCheck( SafeArrayCopy( PSafeArray(TVarData(Data).VArray), Result ) ); end;