angerer
asked on
connect to a network drive (unc path)
i have to load a file from a network drive within a service. i know that the api function FindFirstFileW excepts an UNC-path. but before i have to connect to the other machine. simply as i mount a drive in the windows-explorer.
which api function(s) do i have to use ??
thanks very much
bernhard
Dipl. Ing. Bernhard Angerer
IFT / Vienna University of Technology
Karlsplatz 13/311
A-1040 Wien
Tel: +43 1 58801 31110
Fax: +43 1 58801 31199
angerer@mail.ift.tuwien.ac .at
which api function(s) do i have to use ??
thanks very much
bernhard
Dipl. Ing. Bernhard Angerer
IFT / Vienna University of Technology
Karlsplatz 13/311
A-1040 Wien
Tel: +43 1 58801 31110
Fax: +43 1 58801 31199
angerer@mail.ift.tuwien.ac
angerer, can you be more specific?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
ok - i will be more specific (you are right)
the thing is that my code is running as a nt-service. there are no drives mounted when no user is logged onto the system, so my service has to connect by its own to another machine. how can i connect to a unc-path ?
// START: this is from the unit SysUtils
function FileAge(const FileName: string): Integer;
var
Handle: THandle;
//FindData: TWin32FindData;
FindData: TWin32FindDataW;
LocalFileTime: TFileTime;
hStr: WideString;
begin
hStr := FileName;
Handle := FindFirstFileW(PWideChar(h Str), FindData);
//Handle := FindFirstFile(PChar(FileNa me), FindData);
if Handle <> INVALID_HANDLE_VALUE then
begin
Windows.FindClose(Handle);
if (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = 0 then
begin
FileTimeToLocalFileTime(Fi ndData.ftL astWriteTi me, LocalFileTime);
if FileTimeToDosDateTime(Loca lFileTime, LongRec(Result).Hi,
LongRec(Result).Lo) then Exit;
end;
end;
Result := -1;
end;
function FileExists(const FileName: string): Boolean;
begin
Result := FileAge(FileName) <> -1;
end;
// END: this is from the unit SysUtils
procedure TForm1.Button1Click(Sender : TObject);
begin
//\\ecipca.ift.tuwien.ac.a t\Terminal
if FileExists('\\ecipca.ift.t uwien.ac.a t\Terminal \TERMINAL. TXT') then
Edit1.Text := 'exists'
else
Edit1.Text := 'exists not';
end;
in this code i try to write my own 'FileExists' function that try to connect to the machine 'ecipca.ift.tuwien.ac.at'.
thanks
bernhard
the thing is that my code is running as a nt-service. there are no drives mounted when no user is logged onto the system, so my service has to connect by its own to another machine. how can i connect to a unc-path ?
// START: this is from the unit SysUtils
function FileAge(const FileName: string): Integer;
var
Handle: THandle;
//FindData: TWin32FindData;
FindData: TWin32FindDataW;
LocalFileTime: TFileTime;
hStr: WideString;
begin
hStr := FileName;
Handle := FindFirstFileW(PWideChar(h
//Handle := FindFirstFile(PChar(FileNa
if Handle <> INVALID_HANDLE_VALUE then
begin
Windows.FindClose(Handle);
if (FindData.dwFileAttributes
begin
FileTimeToLocalFileTime(Fi
if FileTimeToDosDateTime(Loca
LongRec(Result).Lo) then Exit;
end;
end;
Result := -1;
end;
function FileExists(const FileName: string): Boolean;
begin
Result := FileAge(FileName) <> -1;
end;
// END: this is from the unit SysUtils
procedure TForm1.Button1Click(Sender
begin
//\\ecipca.ift.tuwien.ac.a
if FileExists('\\ecipca.ift.t
Edit1.Text := 'exists'
else
Edit1.Text := 'exists not';
end;
in this code i try to write my own 'FileExists' function that try to connect to the machine 'ecipca.ift.tuwien.ac.at'.
thanks
bernhard
I think I understand that you want to control the network in a certain way, but you will of course need to enumerate the names.
I have an example, which will do the trick (BOTH in 95/98/NT). I have seen examples that don't.
The original sources is made by Brad Stowers, but here you will also be met by an option to setup all available drives as NetWork drives.
Simply make a new application, make an OnFormCreate event procedure and paste the following lines to unit1:
unit unit1;
// Original sources by Brad Stowers
//
// Brad Stowers bstowers@pobox.com 10/19/96
//
// Following added by Thomas Williams (c) 01/05/99
// -------------------------- ---------- -
// Automatic Network drive connection support.
// You can use ExpandUNCFileName(const FileName: string): string;
// but when accessing files on Network drives, it will behave as
// normal.
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ComCtrls, StdCtrls, ExtCtrls, Menus;
Const
STAY_IN_NETWORK_ON_REBOOT = False;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
Button1: TButton;
rgScope: TRadioGroup;
GroupBox1: TGroupBox;
GroupBox2: TGroupBox;
cbTypeAny: TCheckBox;
cbTypeDisk: TCheckBox;
cbTypePrint: TCheckBox;
cbUsageAll: TCheckBox;
cbUsageConnectable: TCheckBox;
cbUsageContainer: TCheckBox;
cbNetDrives: TCheckBox;
NetTree: TTreeView;
procedure Button1Click(Sender: TObject);
procedure BuildWindow;
Function GetFreeDriveLetter: Char;
public
procedure Open_Do_Close_Enum(const ParentNode: TTreeNode;
ResScope, ResType, ResUsage: DWORD;
const NetContainerToOpen: PNetResource);
function OpenEnum(const NetContainerToOpen: PNetResource;
ResScope, ResType, ResUsage: DWORD): THandle;
function EnumResources(const ParentNode: TTreeNode;
ResScope, ResType, ResUsage: DWORD;
hNetEnum: THandle): UINT;
procedure MapDrive(Res: TNetResource; StayInNetwork: Boolean);
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender : TObject);
var
ResScope,
ResType,
ResUsage: DWORD;
begin
NetTree.Items.Clear;
case rgScope.ItemIndex of
1: ResScope := RESOURCE_GLOBALNET;
2: ResScope := RESOURCE_REMEMBERED;
else
ResScope := RESOURCE_CONNECTED;
end;
ResType := 0;
if cbTypeAny.Checked then
ResType := ResType or RESOURCETYPE_ANY;
if cbTypeDisk.Checked then
ResType := ResType or RESOURCETYPE_DISK;
if cbTypePrint.Checked then
ResType := ResType or RESOURCETYPE_PRINT;
ResUsage := 0;
if cbUsageConnectable.Checked then
ResUsage := ResUsage or RESOURCEUSAGE_CONNECTABLE;
if cbUsageContainer.Checked then
ResUsage := ResUsage or RESOURCEUSAGE_CONTAINER;
Open_Do_Close_Enum(NetTree .Items.Add (NIL, 'Network Resources'),
ResScope, ResType, ResUsage, NIL);
end;
procedure TForm1.Open_Do_Close_Enum( const ParentNode: TTreeNode;
ResScope, ResType, ResUsage: DWORD;
const NetContainerToOpen: PNetResource);
var
hNetEnum: THandle;
begin
hNetEnum := OpenEnum(NetContainerToOpe n, ResScope, ResType, ResUsage);
if (hNetEnum = 0) then exit;
EnumResources(ParentNode, ResScope, ResType, ResUsage, hNetEnum);
if (NO_ERROR <> WNetCloseEnum(hNetEnum)) then
ShowMessage('WNetCloseEnum Error');
end;
function TForm1.OpenEnum(const NetContainerToOpen: PNetResource;
ResScope, ResType, ResUsage: DWORD): THandle;
var
hNetEnum: THandle;
begin
Result := 0;
if (NO_ERROR <> WNetOpenEnum(ResScope, ResType, ResUsage,
NetContainerToOpen, hNetEnum))
then
showmessage('WNetOpenEnum Error')
else
Result := hNetEnum;
end;
function TForm1.EnumResources(const ParentNode: TTreeNode;
ResScope, ResType, ResUsage: DWORD;
hNetEnum: THandle): UINT;
function ShowResource(const ParentNode: TTreeNode; Res: TNetResource): TTreeNode;
var
i: Integer;
begin
Result := NetTree.Items.AddChild(Par entNode, string(Res.lpRemoteName));
//** Modification - Begin **
//find //<Server>/<Resource>
i:= 3;
While (i<Length(Result.Text)) AND (Result.Text[i]<>'\') do inc(i);
If (Copy(Result.Text,1,2)='\\ ')
AND (i<Length(Result.Text))
AND (Res.dwType OR RESOURCETYPE_DISK>0) //make sure it's a diskdrive
AND cbNetDrives.Checked
then MapDrive(Res,STAY_IN_NETWO RK_ON_REBO OT);
//** Modification - End **
end;
const
RESOURCE_BUF_ENTRIES = 2000;
var
ResourceBuffer: array[1..RESOURCE_BUF_ENTR IES] of TNetResource;
i, ResourceBuf, EntriesToGet: DWORD;
NewNode: TTreeNode;
begin
Result := 0;
while TRUE do
begin
ResourceBuf := sizeof(ResourceBuffer);
EntriesToGet := RESOURCE_BUF_ENTRIES;
if (NO_ERROR <> WNetEnumResource(hNetEnum,
EntriesToGet,
@ResourceBuffer,
ResourceBuf)) then
begin
case GetLastError() of
NO_ERROR:
// Drop out of the switch, walk the buffer
break;
ERROR_NO_MORE_ITEMS:
// Return with 0 code because this only happens when we got
// RESOURCE_BUF_ENTRIES entries on the previous call to
// WNetEnumResource, and there were coincidentally exactly
// RESOURCE_BUF_ENTRIES entries total in the enum at the time of
// that previous call
exit;
else
ShowMessage('WNetEnumResou rce Error');
Result := 1;
exit;
end;
end;
for i := 1 to EntriesToGet do
begin
NewNode := ShowResource(ParentNode, ResourceBuffer[i]);
if (ResourceBuffer[i].dwUsage and RESOURCEUSAGE_CONTAINER) <> 0 then
Open_Do_Close_Enum(NewNode ,
ResScope,
ResType,
ResUsage,
@ResourceBuffer[i]);
end;
end;
end;
procedure TForm1.BuildWindow;
Begin
Width := 356;
Height := 420;
With TButton.Create(Self) do
begin
SetBounds(13,96,91,25);
Caption := 'Enum Resources';
Default := True;
TabOrder := 3;
OnClick := Button1Click;
parent := Self;
end;
rgScope:= TRadioGroup.Create(Self);
With rgScope do
Begin
SetBounds(8,8,105,73);
Caption := 'Scope';
Parent := Self;
Items.Add('Connected');
Items.Add('Global');
Items.Add('Remembered');
ItemIndex := 1;
TabOrder := 0;
TabStop := True;
end;
GroupBox1:= TGroupBox.Create(Self);
With GroupBox1 do
begin
SetBounds(232,8,113,73);
Caption := 'Resource Usage';
TabOrder := 2;
Parent := Self;
end;
cbUsageAll:= TCheckBox.Create(GroupBox1 );
With cbUsageAll do
Begin
SetBounds(8,16,97,17);
Caption := 'All';
TabOrder := 0;
Parent := GroupBox1;
end;
cbUsageConnectable:= TCheckBox.Create(GroupBox1 );
With cbUsageConnectable do
begin
SetBounds(8,32,97,17);
Caption := 'Connectable';
State := cbChecked;
TabOrder := 1;
Parent := GroupBox1;
end;
cbUsageContainer:= TCheckBox.Create(GroupBox1 );
With cbUsageContainer do
Begin
SetBounds(8,48,97,17);
Caption := 'Container';
State := cbChecked;
TabOrder := 2;
Parent := GroupBox1;
end;
GroupBox2:= TGroupBox.Create(Self);
With GroupBox2 do
Begin
SetBounds(128,8,97,73);
Caption := 'Resource Type';
TabOrder := 1;
Parent := Self;
End;
cbTypeAny:= TCheckBox.Create(GroupBox2 );
With cbTypeAny do
Begin
SetBounds(8,16,80,17);
Caption := 'Any';
TabOrder := 0;
Parent := GroupBox2;
end;
cbTypeDisk:= TCheckBox.Create(GroupBox2 );
With cbTypeDisk do
Begin
SetBounds(8,32,80,17);
Caption:= 'Disk';
State := cbChecked;
TabOrder := 1;
Parent := GroupBox2;
end;
cbTypePrint:= TCheckBox.Create(GroupBox2 );
With cbTypePrint do
begin
SetBounds(8,48,80,17);
Caption := 'Print';
TabOrder := 2;
Parent := GroupBox2;
end;
NetTree:= TTreeView.Create(Self);
With NetTree do
Begin
SetBounds(8,128,327,249);
Parent:= Self;
Indent := 19;
TabOrder := 4;
end;
cbNetDrives:= TCheckBox.Create(Self);
With cbNetDrives do
Begin
SetBounds(125,96,191,25);
Checked := True;
Caption := 'Find and add Network drives';
Parent := Self;
End;
End;
Function TForm1.GetFreeDriveLetter: Char;
var
S: String;
drives : set of 0..25;
drive : integer;
Begin
S:= '';
DWORD( drives ) := GetLogicalDrives;
for drive := 0 to 25 do
if not(drive in drives) then
S:= S + Chr( drive + Ord( 'A' ));
If S<>'' then
Result:= S[1]
else
Result:= #0;
End;
procedure TForm1.MapDrive(Res: TNetResource; StayInNetwork: Boolean);
Var
Error: DWORD;
NetStay: WORD;
S: String;
Drive: Array[0..1] of Char;
Begin
Drive[0]:= GetFreeDriveLetter;
If Drive[0]<>#0 then
Begin
Drive[1]:= ':';
Res.lpLocalName:= Drive;
If StayInNetwork then
NetStay:= CONNECT_UPDATE_PROFILE
else
NetStay:= 0;
Error:= WNetAddConnection2(
Res, // points to structure that specifies connection details
nil, // points to password string
nil, // points to user name string
NetStay // set of bit flags that specify connection options
);
Case Error of
ERROR_ACCESS_DENIED:
S:= 'Access to the network resource was denied.';
ERROR_ALREADY_ASSIGNED:
S:= 'The local device specified by lpLocalName is already connected to a network resource.';
ERROR_BAD_DEV_TYPE:
S:= 'The type of local device and the type of network resource do not match.';
ERROR_BAD_DEVICE:
S:= 'The value specified by lpLocalName is invalid.';
ERROR_BAD_NET_NAME:
S:= 'The value specified by lpRemoteName is not acceptable to any network resource provider. The resource name is invalid, or the named resource cannot be located.';
ERROR_BAD_PROFILE:
S:= 'The user profile is in an incorrect format.';
ERROR_BAD_PROVIDER:
S:= 'The value specified by lpProvider does not match any provider.';
ERROR_BUSY:
S:= 'The router or provider is busy, possibly initializing. The caller should retry.';
ERROR_CANCELLED:
S:= 'The attempt to make the connection was cancelled by the user through a dialog box from one of the network resource providers, or by a called resource.';
ERROR_CANNOT_OPEN_PROFILE:
S:= 'The system is unable to open the user profile to process persistent connections.';
ERROR_DEVICE_ALREADY_REMEM BERED:
S:= 'An entry for the device specified in lpLocalName is already in the user profile.';
ERROR_EXTENDED_ERROR:
S:= 'A network-specific error occured. Call the WNetGetLastError function to get a description of the error.';
ERROR_INVALID_PASSWORD:
S:= 'The specified password is invalid.';
ERROR_NO_NET_OR_BAD_PATH:
S:= 'A network component has not started, or the specified name could not be handled.';
ERROR_NO_NETWORK:
S:= 'There is no network present.';
end;
end else
Begin
Error:= 1;
S:= 'There is no free drives left';
End;
If Error<>0 then messageDlg(S,mtError,[mbOk ],0);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
BuildWindow;
end;
end.
Regards,
Williams
I have an example, which will do the trick (BOTH in 95/98/NT). I have seen examples that don't.
The original sources is made by Brad Stowers, but here you will also be met by an option to setup all available drives as NetWork drives.
Simply make a new application, make an OnFormCreate event procedure and paste the following lines to unit1:
unit unit1;
// Original sources by Brad Stowers
//
// Brad Stowers bstowers@pobox.com 10/19/96
//
// Following added by Thomas Williams (c) 01/05/99
// --------------------------
// Automatic Network drive connection support.
// You can use ExpandUNCFileName(const FileName: string): string;
// but when accessing files on Network drives, it will behave as
// normal.
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ComCtrls, StdCtrls, ExtCtrls, Menus;
Const
STAY_IN_NETWORK_ON_REBOOT = False;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
Button1: TButton;
rgScope: TRadioGroup;
GroupBox1: TGroupBox;
GroupBox2: TGroupBox;
cbTypeAny: TCheckBox;
cbTypeDisk: TCheckBox;
cbTypePrint: TCheckBox;
cbUsageAll: TCheckBox;
cbUsageConnectable: TCheckBox;
cbUsageContainer: TCheckBox;
cbNetDrives: TCheckBox;
NetTree: TTreeView;
procedure Button1Click(Sender: TObject);
procedure BuildWindow;
Function GetFreeDriveLetter: Char;
public
procedure Open_Do_Close_Enum(const ParentNode: TTreeNode;
ResScope, ResType, ResUsage: DWORD;
const NetContainerToOpen: PNetResource);
function OpenEnum(const NetContainerToOpen: PNetResource;
ResScope, ResType, ResUsage: DWORD): THandle;
function EnumResources(const ParentNode: TTreeNode;
ResScope, ResType, ResUsage: DWORD;
hNetEnum: THandle): UINT;
procedure MapDrive(Res: TNetResource; StayInNetwork: Boolean);
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender
var
ResScope,
ResType,
ResUsage: DWORD;
begin
NetTree.Items.Clear;
case rgScope.ItemIndex of
1: ResScope := RESOURCE_GLOBALNET;
2: ResScope := RESOURCE_REMEMBERED;
else
ResScope := RESOURCE_CONNECTED;
end;
ResType := 0;
if cbTypeAny.Checked then
ResType := ResType or RESOURCETYPE_ANY;
if cbTypeDisk.Checked then
ResType := ResType or RESOURCETYPE_DISK;
if cbTypePrint.Checked then
ResType := ResType or RESOURCETYPE_PRINT;
ResUsage := 0;
if cbUsageConnectable.Checked
ResUsage := ResUsage or RESOURCEUSAGE_CONNECTABLE;
if cbUsageContainer.Checked then
ResUsage := ResUsage or RESOURCEUSAGE_CONTAINER;
Open_Do_Close_Enum(NetTree
ResScope, ResType, ResUsage, NIL);
end;
procedure TForm1.Open_Do_Close_Enum(
ResScope, ResType, ResUsage: DWORD;
const NetContainerToOpen: PNetResource);
var
hNetEnum: THandle;
begin
hNetEnum := OpenEnum(NetContainerToOpe
if (hNetEnum = 0) then exit;
EnumResources(ParentNode, ResScope, ResType, ResUsage, hNetEnum);
if (NO_ERROR <> WNetCloseEnum(hNetEnum)) then
ShowMessage('WNetCloseEnum
end;
function TForm1.OpenEnum(const NetContainerToOpen: PNetResource;
ResScope, ResType, ResUsage: DWORD): THandle;
var
hNetEnum: THandle;
begin
Result := 0;
if (NO_ERROR <> WNetOpenEnum(ResScope, ResType, ResUsage,
NetContainerToOpen, hNetEnum))
then
showmessage('WNetOpenEnum Error')
else
Result := hNetEnum;
end;
function TForm1.EnumResources(const
ResScope, ResType, ResUsage: DWORD;
hNetEnum: THandle): UINT;
function ShowResource(const ParentNode: TTreeNode; Res: TNetResource): TTreeNode;
var
i: Integer;
begin
Result := NetTree.Items.AddChild(Par
//** Modification - Begin **
//find //<Server>/<Resource>
i:= 3;
While (i<Length(Result.Text)) AND (Result.Text[i]<>'\') do inc(i);
If (Copy(Result.Text,1,2)='\\
AND (i<Length(Result.Text))
AND (Res.dwType OR RESOURCETYPE_DISK>0) //make sure it's a diskdrive
AND cbNetDrives.Checked
then MapDrive(Res,STAY_IN_NETWO
//** Modification - End **
end;
const
RESOURCE_BUF_ENTRIES = 2000;
var
ResourceBuffer: array[1..RESOURCE_BUF_ENTR
i, ResourceBuf, EntriesToGet: DWORD;
NewNode: TTreeNode;
begin
Result := 0;
while TRUE do
begin
ResourceBuf := sizeof(ResourceBuffer);
EntriesToGet := RESOURCE_BUF_ENTRIES;
if (NO_ERROR <> WNetEnumResource(hNetEnum,
EntriesToGet,
@ResourceBuffer,
ResourceBuf)) then
begin
case GetLastError() of
NO_ERROR:
// Drop out of the switch, walk the buffer
break;
ERROR_NO_MORE_ITEMS:
// Return with 0 code because this only happens when we got
// RESOURCE_BUF_ENTRIES entries on the previous call to
// WNetEnumResource, and there were coincidentally exactly
// RESOURCE_BUF_ENTRIES entries total in the enum at the time of
// that previous call
exit;
else
ShowMessage('WNetEnumResou
Result := 1;
exit;
end;
end;
for i := 1 to EntriesToGet do
begin
NewNode := ShowResource(ParentNode, ResourceBuffer[i]);
if (ResourceBuffer[i].dwUsage
Open_Do_Close_Enum(NewNode
ResScope,
ResType,
ResUsage,
@ResourceBuffer[i]);
end;
end;
end;
procedure TForm1.BuildWindow;
Begin
Width := 356;
Height := 420;
With TButton.Create(Self) do
begin
SetBounds(13,96,91,25);
Caption := 'Enum Resources';
Default := True;
TabOrder := 3;
OnClick := Button1Click;
parent := Self;
end;
rgScope:= TRadioGroup.Create(Self);
With rgScope do
Begin
SetBounds(8,8,105,73);
Caption := 'Scope';
Parent := Self;
Items.Add('Connected');
Items.Add('Global');
Items.Add('Remembered');
ItemIndex := 1;
TabOrder := 0;
TabStop := True;
end;
GroupBox1:= TGroupBox.Create(Self);
With GroupBox1 do
begin
SetBounds(232,8,113,73);
Caption := 'Resource Usage';
TabOrder := 2;
Parent := Self;
end;
cbUsageAll:= TCheckBox.Create(GroupBox1
With cbUsageAll do
Begin
SetBounds(8,16,97,17);
Caption := 'All';
TabOrder := 0;
Parent := GroupBox1;
end;
cbUsageConnectable:= TCheckBox.Create(GroupBox1
With cbUsageConnectable do
begin
SetBounds(8,32,97,17);
Caption := 'Connectable';
State := cbChecked;
TabOrder := 1;
Parent := GroupBox1;
end;
cbUsageContainer:= TCheckBox.Create(GroupBox1
With cbUsageContainer do
Begin
SetBounds(8,48,97,17);
Caption := 'Container';
State := cbChecked;
TabOrder := 2;
Parent := GroupBox1;
end;
GroupBox2:= TGroupBox.Create(Self);
With GroupBox2 do
Begin
SetBounds(128,8,97,73);
Caption := 'Resource Type';
TabOrder := 1;
Parent := Self;
End;
cbTypeAny:= TCheckBox.Create(GroupBox2
With cbTypeAny do
Begin
SetBounds(8,16,80,17);
Caption := 'Any';
TabOrder := 0;
Parent := GroupBox2;
end;
cbTypeDisk:= TCheckBox.Create(GroupBox2
With cbTypeDisk do
Begin
SetBounds(8,32,80,17);
Caption:= 'Disk';
State := cbChecked;
TabOrder := 1;
Parent := GroupBox2;
end;
cbTypePrint:= TCheckBox.Create(GroupBox2
With cbTypePrint do
begin
SetBounds(8,48,80,17);
Caption := 'Print';
TabOrder := 2;
Parent := GroupBox2;
end;
NetTree:= TTreeView.Create(Self);
With NetTree do
Begin
SetBounds(8,128,327,249);
Parent:= Self;
Indent := 19;
TabOrder := 4;
end;
cbNetDrives:= TCheckBox.Create(Self);
With cbNetDrives do
Begin
SetBounds(125,96,191,25);
Checked := True;
Caption := 'Find and add Network drives';
Parent := Self;
End;
End;
Function TForm1.GetFreeDriveLetter:
var
S: String;
drives : set of 0..25;
drive : integer;
Begin
S:= '';
DWORD( drives ) := GetLogicalDrives;
for drive := 0 to 25 do
if not(drive in drives) then
S:= S + Chr( drive + Ord( 'A' ));
If S<>'' then
Result:= S[1]
else
Result:= #0;
End;
procedure TForm1.MapDrive(Res: TNetResource; StayInNetwork: Boolean);
Var
Error: DWORD;
NetStay: WORD;
S: String;
Drive: Array[0..1] of Char;
Begin
Drive[0]:= GetFreeDriveLetter;
If Drive[0]<>#0 then
Begin
Drive[1]:= ':';
Res.lpLocalName:= Drive;
If StayInNetwork then
NetStay:= CONNECT_UPDATE_PROFILE
else
NetStay:= 0;
Error:= WNetAddConnection2(
Res, // points to structure that specifies connection details
nil, // points to password string
nil, // points to user name string
NetStay // set of bit flags that specify connection options
);
Case Error of
ERROR_ACCESS_DENIED:
S:= 'Access to the network resource was denied.';
ERROR_ALREADY_ASSIGNED:
S:= 'The local device specified by lpLocalName is already connected to a network resource.';
ERROR_BAD_DEV_TYPE:
S:= 'The type of local device and the type of network resource do not match.';
ERROR_BAD_DEVICE:
S:= 'The value specified by lpLocalName is invalid.';
ERROR_BAD_NET_NAME:
S:= 'The value specified by lpRemoteName is not acceptable to any network resource provider. The resource name is invalid, or the named resource cannot be located.';
ERROR_BAD_PROFILE:
S:= 'The user profile is in an incorrect format.';
ERROR_BAD_PROVIDER:
S:= 'The value specified by lpProvider does not match any provider.';
ERROR_BUSY:
S:= 'The router or provider is busy, possibly initializing. The caller should retry.';
ERROR_CANCELLED:
S:= 'The attempt to make the connection was cancelled by the user through a dialog box from one of the network resource providers, or by a called resource.';
ERROR_CANNOT_OPEN_PROFILE:
S:= 'The system is unable to open the user profile to process persistent connections.';
ERROR_DEVICE_ALREADY_REMEM
S:= 'An entry for the device specified in lpLocalName is already in the user profile.';
ERROR_EXTENDED_ERROR:
S:= 'A network-specific error occured. Call the WNetGetLastError function to get a description of the error.';
ERROR_INVALID_PASSWORD:
S:= 'The specified password is invalid.';
ERROR_NO_NET_OR_BAD_PATH:
S:= 'A network component has not started, or the specified name could not be handled.';
ERROR_NO_NETWORK:
S:= 'There is no network present.';
end;
end else
Begin
Error:= 1;
S:= 'There is no free drives left';
End;
If Error<>0 then messageDlg(S,mtError,[mbOk
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
BuildWindow;
end;
end.
Regards,
Williams
ASKER
i am sorry,
i dont need to enumerate something.
the only thing what i have to do is to load a ascii-file from another machine from a windows-nt service.
i have found the following:
function AddConnection:boolean;
var ANetResource:TNetResource;
PW, UN:array[0..200] of char;
begin
with ANetResource do begin
dwType:=RESOURCETYPE_DISK;
lpLocalName:='K:';
lpRemoteName:='\\MyNetwork Path\MyLW' ;
lpProvider:=nil;
end;
StrCopy(PW,'mypasswordonse rver');
StrCopy(UN,'myusernameonse rver');
AddConnection:=(WNetAddCon nection2(A NetResourc e, @PW, @UN, 0)=0);
end;
the function 'AddConnection' works perfect in a normal delphi application. but within a TServiceApplication it returns the errorcode 1312 ??? (i did not find the error-constant with this value.)
maybe you know some hints ? it should be really possible to do this also from a service.
thanks
bernhard
i dont need to enumerate something.
the only thing what i have to do is to load a ascii-file from another machine from a windows-nt service.
i have found the following:
function AddConnection:boolean;
var ANetResource:TNetResource;
PW, UN:array[0..200] of char;
begin
with ANetResource do begin
dwType:=RESOURCETYPE_DISK;
lpLocalName:='K:';
lpRemoteName:='\\MyNetwork
lpProvider:=nil;
end;
StrCopy(PW,'mypasswordonse
StrCopy(UN,'myusernameonse
AddConnection:=(WNetAddCon
end;
the function 'AddConnection' works perfect in a normal delphi application. but within a TServiceApplication it returns the errorcode 1312 ??? (i did not find the error-constant with this value.)
maybe you know some hints ? it should be really possible to do this also from a service.
thanks
bernhard
Hi Bernhard,
I don't think that this is a Delphi problem (so you might as well reject the proposed answer :-), it more like a NT issue. When you install a service it is by default installed to run under the System account. This account doesn't have access to the network! So what you have to do, is to open Control Panel / Services, find you service in the list, click Startup and specify a privilegde user (f.ex. Adminstrator) to run the service..
My guess is it will be working now...
I don't think that this is a Delphi problem (so you might as well reject the proposed answer :-), it more like a NT issue. When you install a service it is by default installed to run under the System account. This account doesn't have access to the network! So what you have to do, is to open Control Panel / Services, find you service in the list, click Startup and specify a privilegde user (f.ex. Adminstrator) to run the service..
My guess is it will be working now...
I'm not sure about this, but I traced the error to be
ERROR_NO_SUCH_LOGON_SESSIO N
(A specified logon session does not exist. It may already have been terminated)
BUT first of all: WNetAddConnection2 does return a DWORD containing an error code, where zero is a correct response.
Have you tried to trace it?
Though I think Blackman is right about this, but if his example doesn't work you could also try:
DWORD WNetAddConnection
LPTSTR lpszRemoteName, // address of network device name
LPTSTR lpszPassword, // address of password
LPTSTR lpszLocalName // address of local device name
);
Like..
Name:= '\\<Server>\<Drive>'; //Type an example
Password:= '<Password>';
Drive:= '<Driveletter>:';
ErrorCode := WNetAddConnection(pChar(Na me),pChar( Password), pChar(Driv e));
This command has been built for backwards-combatiblity with elder OS's.
Regards,
Williams
ERROR_NO_SUCH_LOGON_SESSIO
(A specified logon session does not exist. It may already have been terminated)
BUT first of all: WNetAddConnection2 does return a DWORD containing an error code, where zero is a correct response.
Have you tried to trace it?
Though I think Blackman is right about this, but if his example doesn't work you could also try:
DWORD WNetAddConnection
LPTSTR lpszRemoteName, // address of network device name
LPTSTR lpszPassword, // address of password
LPTSTR lpszLocalName // address of local device name
);
Like..
Name:= '\\<Server>\<Drive>'; //Type an example
Password:= '<Password>';
Drive:= '<Driveletter>:';
ErrorCode := WNetAddConnection(pChar(Na
This command has been built for backwards-combatiblity with elder OS's.
Regards,
Williams
ASKER
Dear BlackMan !
you are very right.
i could manage to connect when the service was assigned with a user that had enough rights.
but my solution still has a problem with different users than the service that are logged on the system and are using the explorer.
the explorer recognizes the new drive letter - but if the user that is logged in does not have the rights that the service has ... thats a problem. (but it should be possible that a user can work on this machine :-) )
if you know a way how to suppress that a drive-letter is mounted when using the function 'WNetAddConnection2' than please tell me. would be perfect if i could access the file just with the unc-path !?
thanks
bernhard
you are very right.
i could manage to connect when the service was assigned with a user that had enough rights.
but my solution still has a problem with different users than the service that are logged on the system and are using the explorer.
the explorer recognizes the new drive letter - but if the user that is logged in does not have the rights that the service has ... thats a problem. (but it should be possible that a user can work on this machine :-) )
if you know a way how to suppress that a drive-letter is mounted when using the function 'WNetAddConnection2' than please tell me. would be perfect if i could access the file just with the unc-path !?
thanks
bernhard