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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8446940/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 18:37:22  来源:igfitidea点击:

How to get fully qualified domain name on Windows in Delphi

windowsdelphidomain-name

提问by Gilmor

I need to get a fully qualified domain name for a Windows machine on a domain in Delphi.

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

I've tried to use LookupAccountSidbut it gives me only the netbios domain name, in my case it is "intranet" but I need the full "intranet.companyname.com"

我尝试使用LookupAccountSid但它只给了我 netbios 域名,在我的情况下它是“intranet”但我需要完整的“intranet.companyname.com”

Any Ideas?

有任何想法吗?

采纳答案by kobik

Try the GetUserNameExWindows API function.

尝试GetUserNameExWindows 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;

using the NameDnsDomainformat for example, will result www.mydomain.com\user_nameif you are logged into "www.mydomain.com" domain.

NameDnsDomain例如,www.mydomain.com\user_name如果您登录到“www.mydomain.com”域,将使用该格式。



Since I now implemented this for my own needs in our application, @iPath's comment was quit right. better use GetComputerNameEx, and specify one of the COMPUTER_NAME_FORMATfor your own needs.

由于我现在在我们的应用程序中根据自己的需要实现了这一点,@iPath 的评论是正确的。更好地使用GetComputerNameEx,并COMPUTER_NAME_FORMAT根据您自己的需要指定其中之一。

A Delphi implementation would look like this (Unicode version):

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;

回答by Steve Rymer

I tried all of the above, but without success. In the end, I settled for simply grabbing the environment variable.

我尝试了上述所有方法,但没有成功。最后,我决定简单地获取环境变量。

uses jclSysInfo;

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

Tested on Server 2008 R2 - works fine. Returns "server.home.lan". Results in an empty string on a Windows 7 non-domain connected PC.

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

回答by Jens Mühlenhoff

NetGetJoinInformationshould work fine.

NetGetJoinInformation应该工作正常。

MSDN:

微软:

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

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

Example:

例子:

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;

回答by Egbert Nierop

The only correct api to use is DsGetDcName. Because NetGetJoinInformation is still from the 'lanmanager age' so, the domain is LM compliant.

唯一正确使用的 api 是 DsGetDcName。因为 NetGetJoinInformation 仍然来自“lanmanager 时代”,所以该域是 LM 兼容的。

The code here is C, but you are smart enough to do the same in Delphi :)

这里的代码是 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);
}