令人惊讶的Delphi程序错误

时间:2010-02-05 14:59:58

标签: delphi delphi-2010

我在Delphi 2010应用程序中使用this unit来告诉我用户所属的Active Directory组。

我创建了一个全新的测试vcl表单应用程序,从该链接添加了单元,并创建了一个带有用户名编辑框的小表单,另一个用于保存CSV分隔的组列表的编辑框,以及一个列表框以列式格式保存组列表。

我的代码如下所示:

procedure TfrmMain.btnShowGroupsClick(Sender: TObject);
var
  ad: TADSI;
  adrec: TADSIUserInfo;
  csvGroups: string;
  slGroups: TStringList;
begin
  //take username from an edit box, tell me what AD groups they are a member of
  ad := TADSI.Create(Self);
  try
    ad.GetUser(edtDomain.Text,edtUser.Text,adrec);
    csvGroups := adrec.Groups;
    edtADGroups.Text := csvGroups;  //ACCESS VIOLATION!!
  finally
    FreeAndNil(ad);
  end;

  {
  //If I UN-comment this code, and make NO OTHER CHANGES, then the
  //aforementioned access violation does NOT occur; there are no errors @ all,
  //and everything works just fine

  slGroups := TStringList.Create;
  try
    slGroups.CommaText := csvGroups;
    listBoxADGroups.Items := slGroups;
  finally
    FreeAndNil(slGroups);
  end;
  //}
end;

如果我按原样运行此代码,当我尝试将CS​​V列表分配到编辑框时,会出现访问冲突。

---------------------------
Debugger Fault Notification
---------------------------
Project C:\Users\my_username.mydomain\bin\ADSITest.exe faulted with message: 'access violation at 0x0048a321: read of address 0x458c0035'. Process Stopped. Use Step or Run to continue.
---------------------------
OK   
---------------------------

但是,如果我取消注释涉及TStringList的代码块,那么一切都很好。

要么这是一些非常奇怪的编译器错误,要么我错过了一些明显的东西。有人可以帮助我吗?

“adrec”结构是一个简单的记录,包含一些布尔值,字符串和另一个记录(TPassword)。

4 个答案:

答案 0 :(得分:1)

当你做listBoxADGroups.Items:= slGroups;你正在用一个指向slGroups的指针替换listBoxADGroups.Items,下面几行,你正在释放它。当程序结束你的btnShowGroupsClick方法时,ListBox会尝试使用这个指针,但它是nil !,因此,A.V。

解决方案就是:

  slGroups := TStringList.Create;
  try
    slGroups.CommaText := csvGroups;
    listBoxADGroups.Items.AddStrings(slGroups);
  finally
    FreeAndNil(slGroups);
  end;

AddStrings方法将slGroups的内容复制到listBoxAdGroups.Items属性(也是TStrings对象),而不是仅替换指针。这样,TListBox的Items属性是完整的,只是其内容被更改。

答案 1 :(得分:0)

我在你的代码中看到你也会得到一个AV:

edtADGroups.Text := csvGroups;  //ACCESS VIOLATION!!

在涉及TStringList的部分中,我打赌你会在行上获得例外:

listBoxADGroups.Items := slGroups;

我认为Self无论如何都是无效的,也许它在某个地方是免费的......

您是在外部调用该方法,还是单击按钮?

答案 2 :(得分:0)

我没有为此代码重现问题或检查编译器的输出,但我注意到当该代码块被注释掉时, csvGroups 变量被冗余地用于存储和将值从一个位置加载到另一个位置。

这让我想知道编译器是否可能过早地优化了围绕该字符串变量的一些关键管家。

注释掉的代码包含对 csvGroups 的进一步引用,从而延长了该变量的生命周期,可能会破坏编译器错误执行的优化。

为了测试这个理论,我将完全从代码的“原样”版本中消除该变量的使用,即更改:

csvGroups := adrec.Groups;
edtADGroups.Text := csvGroups;  //ACCESS VIOLATION!!

简单地说:

edtADGroups.Text := adrec.Groups;

答案 3 :(得分:0)

这是猜测,但在我看来,你使用的单位不是UNICODE兼容的。如果你没有得到任何组(你调试并查看返回?)cvsGroups可能没有正确终止。当您取消注释代码时,写入slGroups可能会覆盖您之前遇到的任何垃圾(或者至少编译器执行类似于初始化slGroups之类的事情,一旦明确它将被触及)。