Solved

Listing thin client drives in a Windows Terminal 2003

Posted on 2004-09-14
7
188 Views
Last Modified: 2010-04-05
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.
0
Comment
Question by:NeoEvoMan
  • 2
  • 2
7 Comments
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 12068681
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.
0
 

Author Comment

by:NeoEvoMan
ID: 12069550
     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

0
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 12103614
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.
0
 

Author Comment

by:NeoEvoMan
ID: 12129381

 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
0
 

Accepted Solution

by:
modulo earned 0 total points
ID: 13432801
PAQed with points refunded (250)

modulo
Community Support Moderator
0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
RESTRequest Parameter 4 42
Wincontrol not (correctly) drawn 15 40
Delphi: making a BW image transparent 10 59
DBCtrlGrid, Delphi, Scroll 7 26
This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Microsoft Active Directory, the widely used IT infrastructure, is known for its high risk of credential theft. The best way to test your Active Directory’s vulnerabilities to pass-the-ticket, pass-the-hash, privilege escalation, and malware attacks …

856 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question