这个问题与this问题有关,我之前已经问过这个问题。 @RRUZ提供的代码正在运行,但似乎不太正确或 我做错了。
执行GetSharedFiles
后TMyObject
实例发生了奇怪的事情。 ({应该})字段FMyEvent
指向一些随机数据。
我在5分钟前发现的是,如果我关闭编译器选项中的优化,它在重建后工作正常。那么也许这是一些编译器错误?
这是一个代码快照(Delphi 2009 Windows 7 64位):
unit Unit17;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm17 = class(TForm)
btnetst: TButton;
procedure btnTestClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
type
TMyEvent = procedure(Sender: TObject) of object;
type
TMyObject = class(TObject)
private
FMyEvent: TMyEvent;
function GetSharedFiles: TStringList;
public
property OnEvent: TMyEvent read FMyEvent write FMyEvent;
procedure DoSomething;
end;
var
Form17: TForm17;
implementation
uses
ActiveDs_TLB,
ActiveX;
function ADsGetObject(lpszPathName:WideString; const riid:TGUID; out ppObject):HRESULT; safecall; external 'activeds.dll';
{$R *.dfm}
procedure TForm17.btnTestClick(Sender: TObject);
var
MyObject: TMyObject;
begin
MyObject := TMyObject.Create;
try
MyObject.DoSomething;
finally
if Assigned(MyObject) then
MyObject.Free;
end;
end;
{ TMyObject }
procedure TMyObject.DoSomething;
var
TmpList: TStringList;
begin
try
TmpList := GetSharedFiles; //something is overwritting the memory in object and puts random data to FMyEvent?
if Assigned(FMyEvent) then
ShowMessage('WTF'); //this should not be called, and if you comment out GetSharedFiles it won't.
finally
if Assigned(TmpList) then
TmpList.Free;
end;
end;
function TMyObject.GetSharedFiles: TStringList;
var
FSO : IADsFileServiceOperations;
Resources : IADsCollection;
Resource : OleVariant;
pceltFetched : Cardinal;
oEnum : IEnumvariant;
begin
Result := TStringList.Create;
//establish the connection to ADSI
if ADsGetObject('WinNT://./lanmanserver', IADsFileServiceOperations, FSO) = S_OK then
begin
//get the resources interface
Resources := FSO.Resources;
//get the enumerator
oEnum:= IUnknown(Resources._NewEnum) as IEnumVariant;
while oEnum.Next(1, Resource, pceltFetched) = 0 do
begin
Result.Add(LowerCase(Format('%s%s%s',[Resource.Path,#9,Resource.User])));
Resource:=Unassigned;
end;
end;
end;
end.
任何想法出了什么问题? 谢谢你的时间。
答案 0 :(得分:2)
对此的调用约定应该是stdcall
,而不是safecall
:
function ADsGetObject(lpszPathName:WideString; const riid:TGUID; out ppObject):HRESULT; safecall; external 'activeds.dll';
典型的COM函数返回HRESULT
结果;如果一切正常,他们会用它来传递错误代码或S_OK
。使用这种类型的函数,通常会有这样的代码:
if CallComFunction(parameters) = S_OK then
begin
// Normal processing goes here
end
else
begin
// Error condition needs to be dealt with here.
end
由于通常无法处理错误条件,Delphi为我们提供了safecall
伪调用约定。这不是一个真正的调用约定,因为事实上它在幕后使用stdcall
。它的作用是自动生成S_OK
的测试,并在失败时引发错误。因此,典型的COM方法可以声明为以下任何一种:
function TypicalComFunction(Parameters): HRESULT; stdcall;
procedure TypicalComFunction(Parameters); safecall;
如果您不打算处理任何潜在错误,请使用第二种形式(使用safecall
)并忽略潜在的异常。如果确实发生错误,Delphi将引发异常,并且该异常将冒泡,直到它到达应用程序中可以处理错误的点。或者它会到达应用程序的异常处理程序,然后用于显示用户的错误。
使用safecall
,上面的典型代码如下所示:
TypicalComFunction(Parameters); // raises exception on error
// Normal processing goes here
另一方面,如果您 需要HRESUL
,即使它与S_OK
不同,请使用stdcall
变体。
答案 1 :(得分:0)
不,这并不意味着编译器错误本身。更改编译器(Delphi< - > FPC),编译器版本或优化选项可以影响代码生成,并优化远离引用计数的临时值或更早地释放它们,或者改变使用的寄存器和寄存器分配。
这反过来可以使真正隐藏的错误弹出。
此类问题的一个示例是您调用外部函数。如果由于某种原因,他们的原型(相关单元中的声明)是错误的,寄存器可能会被删除,并且再次改变编译器选项会导致heisenbug行为。
同时重新计算自动类型的问题,或修改通过CONST传递的全局变量可能会导致此类问题。关于主要FPC maillist atm的后一个问题有一个巨大的线索。
记住:已经工作了很长时间的代码不一定正确。
答案 2 :(得分:0)
这不会是编译器错误。在字段上设置数据断点,您将找到覆盖该字段的代码。
答案 3 :(得分:0)
我过去曾遇到过类似的错误。它只在编译器优化开启时出现。否则,代码工作了大约2年没有问题。这是因为使用优化ON编译的代码与使用优化OFF编译的代码非常不同!!!!!!!由于这些机会,这个bug可以显示(或不显示)。
提示:
这两个技巧帮助我找到了这个错误。