Link to home
Start Free TrialLog in
Avatar of NeoEvoMan
NeoEvoManFlag for Mexico

asked on

Listing thin client drives in a Windows Terminal 2003

How can I get a list of available disks/drives/files from a RDP session (Thin Client). like the list you see in Windows Explorer:
A in LapTop
C in LapTop
C in ThinClient1
C in ThinClient2
C in ThinClient3

NOTE. All those drives are listed as network drives but none API function I tried gives me that results.
Avatar of Wim ten Brink
Wim ten Brink
Flag of Netherlands image

I think you need to enumerate the network resources, checking which resource is a disk resource. Take this piece of code, for example:

program GetNetShares;

{$APPTYPE CONSOLE}

uses
  Windows, SysUtils;

const
  NERR_Success = 0; // Success

type
  NET_API_STATUS = DWORD;
  PShare_Info_0 = ^TShare_Info_0;
  TShare_Info_0 = record
    shi0_netname: PWideChar;
  end;
  PShare_Info_0_Arr = ^TShare_Info_0_Arr;
  TShare_Info_0_Arr = array[0..MaxInt div SizeOf(TShare_Info_0) - 1] of TShare_Info_0;
  PShare_Info_1 = ^TShare_Info_1;
  TShare_Info_1 = record
    shi1_netname: PWideChar;
    shi1_type: DWORD;
    shi1_remark: PWideChar;
  end;
  PShare_Info_1_Arr = ^TShare_Info_1_Arr;
  TShare_Info_1_Arr = array[0..MaxInt div SizeOf(TShare_Info_1) - 1] of TShare_Info_1;
  PShare_Info_2 = ^TShare_Info_2;
  TShare_Info_2 = record
    shi2_netname: PWideChar;
    shi2_type: DWORD;
    shi2_remark: PWideChar;
    shi2_permissions: DWORD;
    shi2_max_uses: DWORD;
    shi2_current_uses: DWORD;
    shi2_path: PWideChar;
    shi2_passwd: PWideChar;
  end;
  PShare_Info_2_Arr = ^TShare_Info_2_Arr;
  TShare_Info_2_Arr = array[0..MaxInt div SizeOf(TShare_Info_2) - 1] of TShare_Info_2;
  PShare_Info_502 = ^TShare_Info_502;
  TShare_Info_502 = record
    shi502_netname: PWideChar;
    shi502_type: DWORD;
    shi502_remark: PWideChar;
    shi502_permissions: DWORD;
    shi502_max_uses: DWORD;
    shi502_current_uses: DWORD;
    shi502_path: PWideChar;
    shi502_passwd: PWideChar;
    shi502_reserved: DWORD;
    shi502_security_descriptor: PSECURITY_DESCRIPTOR;
  end;
  PShare_Info_1004 = ^TShare_Info_1004;
  TShare_Info_1004 = record
    shi1004_remark: PWideChar;
  end;
  PShare_Info_1006 = ^TShare_Info_1006;
  TShare_Info_1006 = record
    shi1006_max_uses: DWORD;
  end;
  PShare_Info_1501 = ^TShare_Info_1501;
  TShare_Info_1501 = record
    shi1501_reserved: DWORD;
    shi1501_security_descriptor: PSECURITY_DESCRIPTOR;
  end;

function NetShareEnum(servername: PWideChar; level: DWORD; var buf: Pointer; prefmaxlen: DWORD; var entriesread: DWORD; var totalentries: DWORD; var resume_handle: DWORD): NET_API_STATUS; stdcall; external 'netapi32.dll';

function NetShareGetInfo(servername: PWideChar; netname: PWideChar; level: DWORD; var buf: Pointer): NET_API_STATUS; stdcall; external 'netapi32.dll';

function NetApiBufferFree(P: Pointer): NET_API_STATUS; stdcall; external 'netapi32.dll';

var
  Server: PWideChar;
  Buffer, Loop: PShare_Info_0;
  Buf502: PShare_Info_502;
  NetResult: DWORD;
  entriesread: DWORD;
  totalentries: DWORD;
  resume_handle: DWORD;
  I: Integer;
begin
  if (ParamCount = 0) then begin
    Server := nil;
  end
  else begin
    Server := PWideChar(WideString(ParamStr(1)));
  end;
  entriesread := 0;
  totalentries := 0;
  resume_handle := 0;
  NetResult := NetShareEnum(Server, 0, Pointer(Buffer), DWORD(-1), entriesread, totalentries, resume_handle);
  if (NetResult = NERR_Success) then begin
    Loop := Buffer;
    WriteLn('Entries read: ', entriesread);
    for I := 1 to entriesread do begin
      WriteLn('Name: ', string(Loop.shi0_netname));
      try
        NetResult := NetShareGetInfo(Server, Loop.shi0_netname, 502, Pointer(Buf502));
        if (NetResult = NERR_Success) then begin
          WriteLn('* Net name: ', string(Buf502.shi502_netname));
          WriteLn('* Type: ', Buf502.shi502_type);
          WriteLn('* Remark: ', string(Buf502.shi502_remark));
          WriteLn('* Permissions: ', Buf502.shi502_permissions);
          WriteLn('* Max uses: ', Buf502.shi502_max_uses);
          WriteLn('* Current uses: ', Buf502.shi502_current_uses);
          WriteLn('* Path: ', string(Buf502.shi502_path));
          WriteLn('* Password: ', string(Buf502.shi502_passwd));
          WriteLn('* Reserved: ', Buf502.shi502_reserved);
        end
        else begin
          WriteLn('* Error: ', SysErrorMessage(NetResult));
        end;
        NetApiBufferFree(Buf502);
      except on E: Exception do WriteLn('* Error: ', E.Message);
      end;
      WriteLn;
      Inc(Loop);
    end;
    NetApiBufferFree(Buffer);
  end;
end.

Basically, the only thing you need to know is the Path for all disk resources. It should work, technicakky speaking.
Avatar of NeoEvoMan

ASKER

     Thanks for your code , but it does not work in Terminal Server 2003 (RDP session). This is the kind of problem I have experimented with some API functions that "only see" mapped network drives but not those shared in a Terminal Server session.

      When a RDP session is  stablished and its local resources are exposed, all the entire drives appear with next format in Windows Explorer: Drive + 'ON ' + Machine_Name, example:
                    A On LapTop.
                    C On LapTop.

Thanks

Another option could be the use of WMI. I'll include some example that I used in a console application:

program GetShares;

{$APPTYPE CONSOLE}

uses
  Windows, SysUtils, ActiveX, WbemScripting_TLB;

function NextItem(var Enum: IEnumVARIANT; const riid: TGUID; out ppObject): Boolean;
var
  OleProperty: OleVariant;
  NumProp: LongWord;
begin
  try
    Result := Succeeded(Enum.Next(1, OleProperty, NumProp)) and (NumProp > 0) and Succeeded(IDispatch(OleProperty).QueryInterface(riid, ppObject));
  except
    Result := False;
    IUnknown(ppObject) := nil;
  end;
end;

function Prop(Obj: ISWbemObject; Name: string): string;
begin
  try
    Result := VarToStr(obj.Properties_.Item(Name, 0).Get_Value);
  except on E: Exception do Result := E.Message;
  end;
end;

var
  AFile: TextFile;
  Enum: IEnumVARIANT;
  Obj: ISWbemObject;
begin
  if Succeeded(CoInitializeEx(nil, COINIT_MULTITHREADED or COINIT_DISABLE_OLE1DDE or COINIT_SPEED_OVER_MEMORY)) then begin
    AssignFile(AFile, ChangeFileExt(ParamStr(0), '.txt'));
    Rewrite(AFile);
    try
      Enum := CoSWbemLocator.Create.ConnectServer(ParamStr(1), 'root\cimv2', '', '', '', '', 0, nil).ExecQuery('Select * from Win32_Share', 'WQL', wbemFlagBidirectional, nil)._NewEnum as IEnumVariant;
      while NextItem(Enum, SWBemObject, Obj) do begin
        WriteLn('Name: ', Prop(Obj, 'Name'));
        WriteLn(AFile, 'Name: ', Prop(Obj, 'Name'));
        WriteLn(AFile, 'Path: ', Prop(Obj, 'Path'));
        WriteLn(AFile, 'Status: ', Prop(Obj, 'Status'));
        WriteLn(AFile, 'Caption: ', Prop(Obj, 'Caption'));
        WriteLn(AFile, 'Description: ', Prop(Obj, 'Description'));
        WriteLn(AFile, 'AllowMaximum: ', Prop(Obj, 'AllowMaximum'));
        WriteLn(AFile);
        obj := nil;
      end;
    except
      on E: Exception do begin
        WriteLn(E.Message);
        WriteLn(AFile, E.Message);
      end;
    end;
    Enum := nil;
    CoUninitialize;
    CloseFile(AFile);
  end;
end.

To get the unit WbemScripting_TLB all you have to do is "Project/Import type library" and add the file "C:\WINNT\system32\wbem\wbemdisp.tlb" to Delphi. If possible, don't let it create a component wrapper since it's not much use anyway. Like the other application, this is just a simple console application. Let me know if you need the WbemScripting_TLB too, or grab it from http://workshop-alex.org/Sources/WbemScripting_TLB.pas if you use Delphi 7.
I would assume that of all system environment thingies, WMI would always provide the required information. If it doesn't then I assume there's no way to retrieve the information.

 Workshop_Alex,

  Thanks for taking a time to try to help me with this question and I would like to tell you that it works because your effort but unfortunately again it didn't work.  

Regards
ASKER CERTIFIED SOLUTION
Avatar of modulo
modulo

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial