在Delphi中如何获取Windows上的完全限定域名

16

我需要在Delphi中获取域中Windows机器的完全限定域名。

我尝试使用LookupAccountSid,但它仅提供NetBIOS域名,在我的情况下是"intranet",但我需要完整的"intranet.companyname.com"。

有什么想法吗?


公司名.com的域服务器是否在运行,否则即使您使用正确的功能也会是空白。 - Joseph Le Brech
1
这是一个Active Directory域吗? - Marcus Adams
2
你的问题不是很清楚。所有这些信息都与机器有关,而不是用户 - OnTheFly
我删除了“当前登录用户”的引用,因为它是无关紧要的,并且只会导致用户混淆。 - Warren P
1
机器领域和用户领域之间有一个重要的区别。我可以使用本地帐户、DomainA 帐户或 DomainB 帐户登录到计算机上。当您使用 GetUserNameEx 时,您将获得用户所在域的名称(如果有的话),这可能与计算机加入的域不同。您可以调用 NetGetJoinInformation 来获取计算机加入的域/工作组/无的名称,但它返回 NetBIOS 域名。 - Ian Boyd
4个回答

12

尝试使用Windows API函数GetUserNameEx

const
  NameUnknown            = 0;
  NameFullyQualifiedDN   = 1;
  NameSamCompatible      = 2;
  NameDisplay            = 3;
  NameUniqueId           = 6;
  NameCanonical          = 7;
  NameUserPrincipal      = 8;
  NameCanonicalEx        = 9;
  NameServicePrincipal   = 10;
  NameDnsDomain          = 12;

function GetUserNameExString(ANameFormat: DWORD): string;
var
  Buf: array[0..256] of Char;
  BufSize: DWORD;
  GetUserNameEx: function (NameFormat: DWORD; lpNameBuffer: LPSTR;
    var nSize: ULONG): BOOL; stdcall;
begin
  Result := '';
  BufSize := SizeOf(Buf) div SizeOf(Buf[0]);
  GetUserNameEx := GetProcAddress(GetModuleHandle('secur32.dll'), 'GetUserNameExA');
  if Assigned(GetUserNameEx) then
    if GetUserNameEx(ANameFormat, Buf, BufSize) then
      Result := Buf;
end;

例如使用NameDnsDomain格式,如果您已登录到"www.mydomain.com"域,将会得到www.mydomain.com\user_name


由于我现在已经根据自己的需要在我们的应用程序中实现了这一点,@iPath的评论是正确的。最好使用GetComputerNameEx,并为自己的需求指定一个COMPUTER_NAME_FORMAT

Delphi实现代码如下(Unicode版本):

interface
...
type
  COMPUTER_NAME_FORMAT = (
    ComputerNameNetBIOS,
    ComputerNameDnsHostname,
    ComputerNameDnsDomain,
    ComputerNameDnsFullyQualified,
    ComputerNamePhysicalNetBIOS,
    ComputerNamePhysicalDnsHostname,
    ComputerNamePhysicalDnsDomain,
    ComputerNamePhysicalDnsFullyQualified,
    ComputerNameMax);

function GetComputerNameExString(ANameFormat: COMPUTER_NAME_FORMAT): WideString;

implementation
...
function GetComputerNameExW(NameType: COMPUTER_NAME_FORMAT; lpBuffer: LPWSTR;
  var nSize: DWORD): BOOL; stdcall; external kernel32 name 'GetComputerNameExW';

function GetComputerNameExString(ANameFormat: COMPUTER_NAME_FORMAT): WideString;
var
  nSize: DWORD;
begin
  nSize := 1024;
  SetLength(Result, nSize);
  if GetComputerNameExW(ANameFormat, PWideChar(Result), nSize) then
    SetLength(Result, nSize)
  else
    Result := '';
end;

请问需要传递哪些参数到这个API? - David Heffernan
我相信用户实际上想要的是机器名称(包括domain.com),而不是\ACTIVEDIRECTORYDOMAIN\username字符串。 - Warren P
2
这种方法完全是错误的:如果计算机加入了FOO.com,但您的程序是在user3@BAR.com下启动的,会怎样?如果BAR.com和FOO.com是受信任的Active Directory域,则可能会发生这种情况(而且确实会发生)。最好使用GetComputerNameEx并指定COMPUTER_NAME_FORMAT:http://msdn.microsoft.com/en-us/library/windows/desktop/ms724301(v=vs.85).aspx - iPath ツ
COMPUTER_NAME_FORMAT和GetComputerNameExW()已经在Winapi.Windows中定义。 - dominikkv
2
@dominikkv,这取决于Delphi版本。旧版本没有定义此API。 - kobik
小心使用 GetComputerNameEx。根据文档,如果计算机没有主 DNS 后缀,即使它们实际上属于域,您也无法获取域名。 - SiBrit

1

我尝试了以上所有方法,但都没有成功。最终,我只好获取环境变量来解决问题。

uses jclSysInfo;

function GetDomain:string;
begin
     result:=GetEnvironmentVariable('USERDNSDOMAIN');
end;

在 Server 2008 R2 上测试成功,返回 "server.home.lan"。在未连接域的 Windows 7 电脑上返回空字符串。

需要检查InternetGetConnectedState,因为如果您失去连接,USERDNSDOMAIN不会被清除。您可以通过拔掉网络电缆来验证有线网络。 - Paul McCarthy

1

NetGetJoinInformation 应该可以正常工作。

MSDN:

http://msdn.microsoft.com/en-us/library/windows/desktop/aa370423(v=vs.85).aspx

例子:

type
  PWKSTA_INFO_100 = ^WKSTA_INFO_100;

  WKSTA_INFO_100 = packed record
    wki100_platform_id: DWord;
    wki100_computername: PWChar;
    wki100_langroup: PWChar;
    wki100_ver_major: DWord;
    wki100_ver_minor: DWord;
  end;

  TNetSetupJoinStatus =
  (
    NetSetupUnknownStatus,
    NetSetupUnjoined,
    NetSetupWorkgroupName,
    NetSetupDomainName
  );

  TNetApiBufferFreeFunction = function(ABuffer: Pointer): DWORD; stdcall;
  TNetWkstaGetInfoFunction  = function(const AServername: PWChar; const ALevel: DWord; const ABufptr: Pointer): DWORD; stdcall;
  TNetGetJoinInformationFunction = function(const AServerName: PWChar; out ANameBuffer: PWChar; out ABufferType: TNetSetupJoinStatus): DWORD; stdcall;

const
  NERR_SUCCESS = 0;

function GetLocalComputerDomainName: string;
var
  NetApiBuffer: Pointer;
  NetApi: THandle;
  NetApiBufferFree: TNetApiBufferFreeFunction;
  NetWkstaGetInfo: TNetWkstaGetInfoFunction;
  NetGetJoinInformation: TNetGetJoinInformationFunction;
  NetSetupJoinStatus: TNetSetupJoinStatus;
  NameBuffer: PWideChar;
begin
  Result := '';
  NetApi := LoadLibrary('netapi32.dll');
  if NetApi <> 0 then
  begin
    NetApiBufferFree      := TNetApiBufferFreeFunction(     GetProcAddress(NetApi, 'NetApiBufferFree'));
    NetGetJoinInformation := TNetGetJoinInformationFunction(GetProcAddress(NetApi, 'NetGetJoinInformation'));
    NetWkstaGetInfo       := TNetWkstaGetInfoFunction(      GetProcAddress(NetApi, 'NetWkstaGetInfo'));
    if @NetApiBufferFree <> nil then
    begin
      if @NetSetupJoinStatus <> nil then
      begin
        if NetGetJoinInformation(nil, NameBuffer, NetSetupJoinStatus) = NERR_SUCCESS then
        begin
          if NetSetupJoinStatus = NetSetupDomainName then
          begin
            Result := NameBuffer;
          end;
          NetApiBufferFree(NameBuffer);
        end;
      end;
    end;
    FreeLibrary(NetApi);
  end;
end;

它返回的结果可能取决于域网络的设置方式。抱歉,我不知道具体细节,但在工作中我只使用NetGetJoinInformation获取一个简单的域名。 - Ondrej Kelle
如果域名不以.companyname.com结尾,那么这是正确的。在这种情况下,对IP地址进行反向DNS查找可能会得到FQDN,这也可能是OP想要的。 - Jens Mühlenhoff
2
很遗憾,你的代码只返回了我的域名中的“内网”部分。至少在我的域名中是这样的。 - Gilmor
MSDN称:lpNameBuffer [out] - 指向缓冲区的指针,该缓冲区接收计算机加入的域或工作组的NetBIOS名称。因此NetGetJoinInformation不返回FQDN,而是域的NETBIOS名称。 - iPath ツ

0
唯一正确的API是DsGetDcName。 因为NetGetJoinInformation仍然来自“lanmanager时代”,所以域是LM兼容的。
这里的代码是C,但你足够聪明,在Delphi中也可以做到同样的事情 :)
PDOMAIN_CONTROLLER_INFOW pdomInfo ;
auto result1 = ::DsGetDcNameW(nullptr, nullptr, nullptr, nullptr, DS_DIRECTORY_SERVICE_PREFERRED | DS_RETURN_DNS_NAME, &pdomInfo);
if (result1 == ERROR_SUCCESS) {
auto retVal = SysAllocString(pdomInfo->DomainName);
                ::NetApiBufferFree(pdomInfo);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接