Solved

Listing thin client drives in a Windows Terminal 2003

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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Mydac connection data base issue 3 135
delphi exception 7 61
Mobile Keyboard covers the display of the TMemo 3 78
Controlled Assessment GCSE - desperate help needed 4 75
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…
Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
A short film showing how OnPage and Connectwise integration works.
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …

939 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

1 Experts available now in Live!

Get 1:1 Help Now