Hen*_*run -1 delphi autocomplete delphi-10.1-berlin
在@KenWhite的自动完成示例中,Next函数在TPointerList()[]调用时具有访问冲突(通过Windows自动完成界面).
D10.1u2,Win10.64
function TEnumString.Next(celt: Integer; out elt;
pceltFetched: PLongint): HResult;
var
I: Integer;
wStr: WideString;
begin
I := 0;
while (I < celt) and (FCurrIndex < FStrings.Count) do
begin
wStr := FStrings[FCurrIndex];
TPointerList(elt)[1] := PWideChar('abcd'); //access violation
TPointerList(elt)[1] := CoTaskMemAlloc(8); //access violation
TPointerList(elt)[I] := CoTaskMemAlloc(2 * (Length(wStr) + 1)); //access violation
StringToWideChar(wStr, TPointerList(elt)[I], 2 * (Length(wStr) + 1));
Inc(I);
Inc(FCurrIndex);
end;
if pceltFetched <> nil then
pceltFetched^ := I;
if I = celt then
Result := S_OK
else
Result := S_FALSE;
end;
Run Code Online (Sandbox Code Playgroud)
在较新的版本(IIRC XE2及更高版本)中,你可以做Remy所说的,但你不应该做IMO.
在XE2之前的版本(或任何版本)中,定义TPointerList为:
type
...
TPointerList = array[0..MaxListSize] of Pointer;
Run Code Online (Sandbox Code Playgroud)
在较新的版本中,它是:
type
TPointerList = array of Pointer;
Run Code Online (Sandbox Code Playgroud)
换句话说,现在它已成为动态数组类型(引用类型),而不是静态数组类型(值类型).将无类型输出参数的地址强制转换为此类数组可能会变得棘手.
中定义的不同解释了为什么在新版本中,代码不能正常工作:有一个间接的额外水平.
现在,如果将以下声明添加到uAutoComplete.pas文件中:
type
TPointerList = array[0..65535] of Pointer; // assuming 65536 (2^16) entries are enough
Run Code Online (Sandbox Code Playgroud)
那么文件的其余部分可以保持原来的样子.然后:
TPointerList(elt)[I] := ...
Run Code Online (Sandbox Code Playgroud)
可以工作,并且不要求你在一些实际上没有的东西上使用稍微棘手的,间接的,强制转换为Delphi动态数组.请注意,这也适用于旧版本.