Home > Delphi > Ye old network snippets revisited

Ye old network snippets revisited

November 20, 2013 Leave a comment Go to comments
Networking

Networking

Lately I have been looking at some code for ordinary, average networking tasks. Simple stuff like “how do you get the workgroup name” or “how do you get the computer name”. Functions that should be fairly commonplace in our day and age. But there is a world of pain on the internet when it comes to snippets like this. Everyone makes mistakes so I’m not pointing any fingers, but a quick visit to MSDN unveils a horror of memory leaks, incompatible datatypes and code that will make your citrix administrator permanently ban you.

Here are some routines I updated (most of them collected here and there). Tested on Windows 8 and Windows 7 under Citrix.

  class function TNetUtils.getUserName:String;
  var
    BufferSize: DWORD;
    pUser: PChar;
  begin
    // Extract default system-buffer size
    BufferSize := 0;
    winapi.Windows.GetUserName(nil, BufferSize);

    // Allocate string to match system buffer
    pUser := StrAlloc(BufferSize);
    try
      if winapi.Windows.GetUserName(pUser, BufferSize) then
      result := pUser;
    finally
      StrDispose(pUser);
    end;
  end;

  class function TNetUtils.getDomainController:String;
  var
    BufPtr:   PChar;
  begin
    BufPtr:=NIL;
    (* API reference material:
      msdn.microsoft.com/en-us/library/windows/desktop/aa370420(v=vs.85).aspx *)
    if netGetDCName(nil,nil,BufPtr)=NERR_SUCCESS then
    Begin
      try
        Result := BufPtr;
      finally
        NetApiBufferFree(BufPtr);
      end;
    end;
  end;

  class function TNetUtils.getDomainController(Const aDomain:String):String;
  var
    BufPtr: PChar;
  begin
    if length(aDomain)>0 then
    Begin
    (* API reference material:
      msdn.microsoft.com/en-us/library/windows/desktop/aa370420(v=vs.85).aspx *)
      if NetGetDCName(nil,PChar(aDomain),BufPtr)=NERR_SUCCESS then
      Begin
        try
          Result := BufPtr;
        finally
          NetApiBufferFree(BufPtr);
        end;
      end;
    end else
    result:=getDomainController;
  end;

  class function TNetUtils.getComputerName:String;
  var
    mSize: DWord;
    mBuffer: PChar;
  begin
    (* API reference material:
    msdn.microsoft.com/en-us/library/windows/desktop/ms724295(v=vs.85).aspx *)
    mSize:=(MAX_COMPUTERNAME_LENGTH + 1) * SizeOf(WideChar);

    (* Allocate buffer *)
    mBuffer:=allocmem(mSize);
    try
      (* Get the computer name *)
      if winapi.Windows.GetComputerName(mBuffer, mSize) then
      result:=mBuffer;
    finally
      freeMem(mBuffer);
    end;
  end;

  class function TNetUtils.getWorkGroupName:String;
  var
    Info: P_WKSTA_INFO_100;
  begin
    setLength(result,0);
    (* API reference material:
    msdn.microsoft.com/en-us/library/windows/desktop/aa370663(v=vs.85).aspx *)
    if NetWkstaGetInfo(NIL,100,info)=NERR_SUCCESS then
    Begin
      try
        result:=info.wki100_langroup;
      finally
        NetApiBufferFree(info);
      end;
    end;
  end;

  class function TNetUtils.getUserDomain:string;
  begin
    result:=getUserDomain(getUserName);
  end;

  class function TNetUtils.getUserDomain(aUserName:String):String;
  const
    DNLEN = 255;
  var
    sid               : PSID;
    sidSize           : DWORD;
    sidNameUse        : DWORD;
    domainNameSize    : DWORD;
    domainName        : array[0..DNLEN] of char;
    vlSize : ^DWORD;
  begin
    aUsername:=Trim(aUserName);
    if length(aUserName)<1 then
    raise Exception.Create
    ('Unable to extract domain, username was empty');

    domainNameSize := DNLEN + 1;
    sidNameUse := SidTypeUser;

    (* try the "proper" way *)
    sidSize := 65536;
    sid:=AllocMem(sidSize);
    try
      if LookupAccountName(nil, PChar(aUserName), sid, sidSize,
      domainName, domainNameSize, sidNameUse) then
      Result:=StrPas(domainName);
    finally
      FreeMem(sid);
    end;

    (* Fallback mechanism, check environment variables *)
    if length(result)<1 then
    Begin
      New(vlSize);
      try
        vlSize^ := 1024;
        ExpandEnvironmentStrings(PChar('%USERDOMAIN%'), domainName, vlSize^);
        Result := domainName;
      finally
        Dispose(vlSize);
      end;
    end;
  end;

And some updated declarations which doesnt mix ansi and widestring into a nest of pigs:


  type

  P_WKSTA_INFO_100 = ^T_WKSTA_INFO_100;
  _WKSTA_INFO_100 = record
    wki100_platform_id: DWORD;
    wki100_computername: PChar;
    wki100_langroup: PChar;
    wki100_ver_major: DWORD;
    wki100_ver_minor: DWORD;
  end;
  T_WKSTA_INFO_100 = _WKSTA_INFO_100;

  function  NetApiBufferAllocate
            (ByteCount: DWORD;
            var Buffer:Pointer):DWORD;
            stdcall; external 'netapi32.dll';

  function  NetApiBufferFree
            (Buffer: Pointer): DWORD;
            stdcall;external 'netapi32.dll';

  function  NetGetDCName
            (servername:PChar;
            domainname:PChar;
            var bufptr):DWORD;
            stdcall; external 'netapi32.dll';

  Function  NetWkstaGetInfo
            (ServerName : PChar;
            Level      : DWORD;
            var BufPtr) : DWord;
            Stdcall; external 'netapi32.dll';

Advertisements
  1. November 21, 2013 at 3:38 pm

    No need for this part on the URLs: (v=vs.85)
    You can even leave out the .aspx part (But I think that is more tricky).

  1. No trackbacks yet.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: