Solved

Listing thin client drives in a Windows Terminal 2003

Posted on 2004-09-14
7
179 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

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…

743 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

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now