【问题标题】:How to get fully qualified domain name on Windows in Delphi如何在Delphi的Windows上获得完全合格的域名
【发布时间】:2011-12-09 14:29:29
【问题描述】:

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

我尝试使用LookupAccountSid,但它只给了我 netbios 域名, 就我而言,它是“intranet”,但我需要完整的“intranet.companyname.com”

有什么想法吗?

【问题讨论】:

  • 是companyname.com上运行的域服务器,否则即使你使用正确的功能它也会是空白的。
  • 它是 Active Directory 域吗?
  • 你的问题不是很清楚。所有这些信息都与机器有关,而不是用户
  • 我删除了对“当前登录用户”的引用,因为它是虚假的,并且只显示用户混淆。
  • 机器的域和用户的域有一个重要的区别。我可以使用本地帐户、DomainA 帐户或DomainB 帐户登录机器。当您使用GetUserNameEx 时,您将获得用户 的域名称(如果有的话),它可能与机器加入的域不同。您可以调用 NetGetJoinInformation 来获取机器加入的域/工作组/none 的名称,但它会返回 NetBIOS 域名。

标签: windows delphi domain-name


【解决方案1】:

试试GetUserNameEx Windows API 函数。

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?
  • 我相信用户实际上想要一个机器名(包括 domain.com),而不是 \\ACTIVEDIRECTORYDOMAIN\username 字符串。
  • 这是完全错误的做法:如果计算机加入了 FOO.com,但你的程序是在 user3@BAR.com 下启动的怎么办?如果 BAR.com 和 FOO.com 是受信任的 Active Directory 域,这可能会发生(并且会发生)。最好使用 GetComputerNameEx 并指定 COMPUTER_NAME_FORMAT:msdn.microsoft.com/en-us/library/windows/desktop/…
  • COMPUTER_NAME_FORMAT 和 GetComputerNameExW() 已在 Winapi.WIndows 中定义。
  • @dominikkv,这取决于 Delphi 版本。旧版本未定义此 API。
【解决方案2】:

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获得了一个简单的域名。
  • 如果域名不以.companyname.com 结尾,则为真。在这种情况下,对 IP 地址的反向 DNS 查找可能会得到 FQDN,这也可能是 OP 想要的。
  • 不幸的是,您的代码仅返回我域名的“内部网”部分。至少在我的领域。
  • MSDN 说:lpNameBuffer [out] - 指向缓冲区的指针,该缓冲区接收计算机加入的域或工作组的 NetBIOS 名称。所以 NetGetJoinInformation 不返回 FQDN,而是返回域的 NETBIOS 名称
【解决方案3】:

我尝试了以上所有方法,但没有成功。最后,我只好简单地抓取环境变量。

uses jclSysInfo;

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

在 Server 2008 R2 上测试 - 工作正常。返回“server.home.lan”。 在 Windows 7 未连接域的 PC 上产生一个空字符串。

【讨论】:

  • 还需要检查 InternetGetConnectedState,因为如果您失去连接,则不会清除 USERDNSDOMAIN。您可以通过拔下网线在有线网络上进行验证。
【解决方案4】:

唯一正确使用的 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);
}

【讨论】:

    最近更新 更多