尝试在德尔福构建Excel RTD服务器



我正在尝试在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"函数时,我确实设法将结果放入单元格中,该函数简单返回字符串而不是 PSafeArray(尽管对该函数的第一次调用无法产生结果 (N/A(。只有在更改 RTD(( 调用中的主题后,它才会显示结果(仅一次((

我的代码基于来自 https://blog.learningtree.com/excel-creating-rtd-server-c/的 C# 示例

谁能指出我正确的方向?

OleVariant拥有它所持有的数据,并在自身超出范围时释放该数据。 因此,您返回指向Excel的无效PSafeArray指针。 您需要:

  1. 在返回数组指针之前释放数组指针的所有权:

    function TRtdServer.RefreshData(var TopicCount: Integer): PSafeArray;
    var
    Data : OleVariant;
    begin
    ...
    Result := PSafeArray(TVarData(Data).VArray);
    TVarData(Data).VArray = nil; // <-- add this
    end;
    
  2. 使用SafeArrayCopy()创建数组的副本,然后返回副本

    uses
    ..., ActiveX;
    function TRtdServer.RefreshData(var TopicCount: Integer): PSafeArray;
    var
    Data : OleVariant;
    begin
    ...
    OleCheck(
    SafeArrayCopy(
    PSafeArray(TVarData(Data).VArray),
    Result
    )
    );
    end;
    

最新更新