Solved

NetShareAdd: Error handling

Posted on 2010-08-30
38
1,175 Views
Last Modified: 2012-05-10
Hi,

Running to code below gives me error = 8.
Can anybody tell me what this error means and how it might be solved?
In fact other errors should be handled as well, so at least an informative message can be presented to the user.

I already found some information but it doesn't mention any errorcode.
http://msdn.microsoft.com/en-us/library/bb525384(VS.85).aspx
0
Comment
Question by:Delphiwizard
  • 16
  • 11
  • 7
  • +1
38 Comments
 

Author Comment

by:Delphiwizard
ID: 33556534
And the code of course:
function ShareFolder(vFolder : String) : Boolean;

var Buffer        : TShareInfo;

    Err           : Integer;

    NetName, Path : WideString;

Begin

  NetName                  := 'MyApp';

  Buffer.shi2_NetName      := PWideChar(NetName);

  Buffer.shi2_Type         := STYPE_DISKTREE;

  Buffer.shi2_Remark       := nil;

  Buffer.shi2_Permissions  := ACCESS_ALL; // Alle gebruikers

  Buffer.shi2_MaxUsers     := DWORD(-1);

  Buffer.shi2_Current_Uses := DWORD(-1);

  Path                     := vFolder;

  Buffer.shi2_Path         := PWideChar(Path);

  Buffer.shi2_PassWord     := nil;

    if NetShareAdd(nil, 2, @Buffer, Err) <> 0 then

    begin

      Result := False;

      ShowMessage( 'Error ' + IntToStr(Err) );

    end else

      Result := False;

end;

Open in new window

0
 
LVL 13

Expert Comment

by:aflarin
ID: 33556578
here is improved function. run it and let me know about error codes:

function ShareFolder(vFolder : String) : Boolean;
var
  Buffer : TShareInfo;
  Err, ErrField : Integer;
  NetName, Path: WideString;
Begin

  NetName:= 'NetName';
  Buffer.shi2_NetName := PWideChar(NetName);
  Buffer.shi2_Type:= STYPE_DISKTREE;
  Buffer.shi2_Remark:= nil;
  Buffer.shi2_Permissions:= ACCESS_ALL;
  Buffer.shi2_MaxUsers:= DWORD(-1);
  Buffer.shi2_Current_Uses:= DWORD(-1);
  Path:= vFolder;
  Buffer.shi2_Path:= PWideChar(Path);
  Buffer.shi2_PassWord:= nil;

  Err:= NetShareAdd(nil,2,@Buffer, ErrField);
  Result:= Err = 0;
  if not Result then
    ShowMessage( Format('Error %d %d', [Err, ErrField]) );
end;
0
 
LVL 25

Expert Comment

by:epasquier
ID: 33556634
Error Code 8
System error code 8 means "Not enough storage is available to process this command."
This error code may also display as "ERROR_NOT_ENOUGH_MEMORY" or as the value 0x8.
0
 
LVL 25

Expert Comment

by:epasquier
ID: 33556655
oh, but when you say you get an error = 8 , you might be talking about the last parameter, not the function result (as Aflarin has modified the code to display it).

If that is the case, you are mistaken about the signification of this last parameter :


parm_err [out] :
Pointer to a value that receives the index of the first member of the share information structure that causes the ERROR_INVALID_PARAMETER error. If this parameter is NULL, the index is not returned on error. For more information, see the NetShareSetInfo function.

=> I am not sure about the index thing, but it might be the password that is not correct. Have you tried with and empty string instead of nil ?

Buffer.shi2_PassWord:= '';
0
 
LVL 13

Expert Comment

by:aflarin
ID: 33556657
> Error Code 8

No, it isn't the error code.
In the initial function the error code indicates the field of structure where the error happens.

It seems the error code is ERROR_INVALID_PARAMETER and the problem parameter is shi2_PassWord
0
 

Author Comment

by:Delphiwizard
ID: 33556666
Your improved version gives error: 123 8
Which is not much better... :-)
Getting this error seems a bit strange as there is more then plenty storage and memory on my computer.
Bye the way I try to share folder:
C:\Documents and Settings\All Users\Documenten\MyAppName

0
 
LVL 25

Expert Comment

by:epasquier
ID: 33556673
ok, no,  8 is this parameter :
#define SHARE_PATH_PARMNUM 8

your path is incorrect
0
 

Author Comment

by:Delphiwizard
ID: 33556679
When I try to share the same folder from within Windows Explorer, I get the message that there is already a share available with the same ShareName (NetName). In my case "MyApp"
So I need to remove the old share first.
0
 
LVL 25

Expert Comment

by:epasquier
ID: 33556687
that confirms it :
Windows Error Message 123: 'ERROR_INVALID_NAME'
0
 

Author Comment

by:Delphiwizard
ID: 33556706
So I need some function that will remove a share by it's name (if it exists).
My Application will then have one share assigned to it (to it's base-folder).
Moving the base-folder will delete the share of the old base-folder and create a new share for the newly assigned base-folder.
0
 
LVL 13

Expert Comment

by:aflarin
ID: 33556707
Epasquier is right, it means you already have a share with the same name
0
 
LVL 13

Accepted Solution

by:
aflarin earned 500 total points
ID: 33556764
I've improved the function:
  - it shows the text error message now
  - it takes ShareName as param
  - changed params to const to improve perfomance

function GetWin32ErrorString(ErrorCode: Integer): string;
var
  Len: Integer;
  Buffer: array[0..255] of Char;
begin
  Len := FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM or
    FORMAT_MESSAGE_ARGUMENT_ARRAY, nil, ErrorCode, 0, Buffer,
    SizeOf(Buffer), nil);
  while (Len > 0) and (Buffer[Len - 1] in [#0..#32, '.']) do Dec(Len);
  SetString(Result, Buffer, Len);
end;


function ShareFolder(const AFolder, AShareName: String) : Boolean;
var
  Buffer : TShareInfo;
  Err, ErrField : Integer;
  NetName, Path: WideString;
Begin
  NetName:= AShareName;
  Buffer.shi2_NetName := PWideChar(NetName);
  Buffer.shi2_Type:= STYPE_DISKTREE;
  Buffer.shi2_Remark:= nil;
  Buffer.shi2_Permissions:= ACCESS_ALL;
  Buffer.shi2_MaxUsers:= DWORD(-1);
  Buffer.shi2_Current_Uses:= DWORD(-1);
  Path:= AFolder;
  Buffer.shi2_Path:= PWideChar(Path);
  Buffer.shi2_PassWord:= nil;

  Err:= NetShareAdd(nil,2,@Buffer, ErrField);
  Result:= Err = 0;
  if not Result then
    ShowMessage( Format('Error %d: %s'#13#10'Param index - %d', [Err, GetWin32ErrorString(Err), ErrField]) );
end;

Using

procedure TForm1.Button1Click(Sender: TObject);
Begin
  ShareFolder( 'C:\Documents and Settings\All Users\Documents\Test', 'MyShareName' );
end;
0
 

Author Comment

by:Delphiwizard
ID: 33556803
Yes.
Asuming that my application generates some unique sharename, It should never be created twice. So if it already exists as a sharename, then the old share can be removed and the new share can be created/added.
Do you agree with this?

Then there is the issue about how to remove the old share?
If a sharename is already present and it's NOT covering the sharing of the new base-Folder, then it must be removed so a new share can be created with the same name.
This also elliminates the problem of having multiple shares that aren't used anymore, but still give full access to all users.
0
 
LVL 25

Expert Comment

by:epasquier
ID: 33556806
this code works for me.
I added a parameter for the Share Name, and the display of a text message corresponding to the error you get if it fails.
but otherwise it is quite the same.

If you still have errors, then you have a problem that is not from the code. I hope the clear message will help you.
Type

  TShareInfo = record

     shi2_netname: LPWSTR;

     shi2_type: DWORD;

     shi2_remark: LPWSTR;

     shi2_permissions: DWORD;

     shi2_MaxUsers: DWORD;

     shi2_current_uses: DWORD;

     shi2_path: LPWSTR;

     shi2_PassWord: LPWSTR;

  end;

  pShareInfo=^TShareInfo;



const

 STYPE_DISKTREE = 0;

 STYPE_PRINTQ = 1;

 STYPE_DEVICE = 2;

 STYPE_IPC = 3;

 STYPE_DFS = 100;

 STYPE_SPECIAL = $80000000;

 

 ACCESS_NONE = 0;

 ACCESS_READ  = 1;

 ACCESS_WRITE = 2;

 ACCESS_CREATE = 4;

 ACCESS_EXEC = 8;

 ACCESS_DELETE = 16;

 ACCESS_ATRIB = 32;

 ACCESS_PERM = 64;

 ACCESS_ALL = (ACCESS_READ+ACCESS_WRITE+ACCESS_CREATE+ACCESS_EXEC+ACCESS_DELETE+ACCESS_ATRIB+ACCESS_PERM);



function NetShareAdd(servername: LPWSTR;

    level: DWORD;

    buf: pShareInfo;

    parm_err: LPDWORD):LongWord; stdcall; external 'netapi32.dll';

 

function ShareFolder(vFolder : String; ShareName:String) : Boolean;

var Buffer        : TShareInfo;

    Err           : Integer;

    NetName, Path : WideString;

Begin

  NetName                  := ShareName;

  Buffer.shi2_NetName      := PWideChar(NetName);

  Buffer.shi2_Type         := STYPE_DISKTREE;

  Buffer.shi2_Remark       := nil;

  Buffer.shi2_Permissions  := ACCESS_ALL;

  Buffer.shi2_MaxUsers     := DWORD(-1);

  Buffer.shi2_Current_Uses := DWORD(-1);

  Path                     := vFolder;

  Buffer.shi2_Path         := PWideChar(Path);

  Buffer.shi2_PassWord     := nil;

  if NetShareAdd(nil, 2, @Buffer, @Err) <> 0 then

   begin

    Result := False;

    ShowMessage(SysErrorMessage(GetLastError));

   end else Result := True;

end;

Open in new window

0
 
LVL 25

Expert Comment

by:epasquier
ID: 33556820
If the path is already shared with a different name, the old one is replaced by the new one with this function, not even generating an error. At least in my system, Vista 64
0
 

Author Comment

by:Delphiwizard
ID: 33556913
I changed some code I got from aflarin in a previous post.
I just need to have some code to delete the old share.
function IsFolderShared(vServer, vFolder, vUniqueSharename : String) : Boolean;

var  p                      : PShareInfo502Array;

     res, er, tr, resume, i : DWORD;

     szServer, line         :      String;

     lpwszServer            : Array [0..255] of WideChar;

     pwszServer             : PWideChar;

begin

  Result := False;

  er:=0;

  tr:=0;

  resume:=0;

  szServer:= vServer;  // ComputerName

  // Check parameter

  if (Length(szServer) = 0) then

    pwszServer:=nil

  else

  begin

    // Make sure the server starts with a \\

    if (Pos('\\', szServer) <> 1) then

      szServer:='\\'+szServer;

    StringToWideChar(szServer, @lpwszServer, SizeOf(lpwszServer));

    pwszServer:=@lpwszServer;

  end;

  // Call the NetShareEnum function; specify level 502.

  repeat

    res := NetShareEnum(pwszServer, 502, @p, DWORD(-1), @er, @tr, @resume);

    // If the call succeeds

    if (res = ERROR_SUCCESS) or (res = ERROR_MORE_DATA) then

    begin

      // Loop through the entries;

      for i := 1 to Pred(er) do

      begin

        // Check is sharename is used already

        // and if so: Does is cover sharing of vFolder

        if (AnsiCompareText(WideCharToString(p^[i].shi502_netname), vUniqueSharename) = 0) then

        begin

          if NOT (AnsiPos(WideCharToString(p^[i].shi502_path), vFolder) > 0) then

          begin

            // Sharename exists and must be removed first

            showMessage('Sharename already exists');



            DeleteShareByName; // HOW TO DO THIS???



          end;

        end;

        if (AnsiPos(WideCharToString(p^[i].shi502_path), vFolder) > 0) AND

           NOT (AnsiPos('$', WideCharToString(p^[i].shi502_netname)) > 0)  then

        begin

          // Folder is shared already (by any available share)

          Result := True;

        end;

      end;

      // Free the allocated buffer.

      NetApiBufferFree(p);

    end;

  until (res <> ERROR_MORE_DATA); // Continue to call NetShareEnum while there are more entries.

end;

Open in new window

0
 
LVL 13

Expert Comment

by:aflarin
ID: 33556963
>> Do you agree with this?

You can just enumerate all shares (NetShareEnum function from your previous question) and find if the share with the same Local Path already exist

>> Then there is the issue about how to remove the old share?

It's NetShareDel, I already posted this link and you already checked it :)
http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_23470466.html
0
 

Author Comment

by:Delphiwizard
ID: 33557037
Removing the old share was already present indeed. I got too many lines of code in my project and sometimes forget what I have already.... :-)
0
 

Author Comment

by:Delphiwizard
ID: 33557159
The code works fine except when I try sharing the following folder (which I actually want to share): C:\Documents and Settings\All Users\Documenten\MyAppName

Here I get error:

using: ShowMessage(SysErrorMessage(GetLastError));
=> Overlapping I/O is executed
using: ShowMessage( Format('Error %d: %s'#13#10'Param index - %d', [Err, GetWin32ErrorString(Err), ErrField]) );
Error 123: Syntaxt of filename, foldername ot volumename is incorrect. Param index - 8
0
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.

 
LVL 13

Expert Comment

by:aflarin
ID: 33557261
>> using: ShowMessage(SysErrorMessage(GetLastError));
>> => Overlapping I/O is executed

It seems it's not a correct message. I think GetLastError returns error from other function, not NetShareAdd.

>> Error 123: Syntaxt of filename, foldername ot volumename is incorrect. Param index - 8

It's the same error as in your first post - 123 8
Try to create share in Explorer, it seems you already have the same share name
0
 
LVL 14

Expert Comment

by:systan
ID: 33557281
Why not do like this;
function ReShareFolder(const AFolder, AShareName: String) : Boolean;

var

  Buffer : TShareInfo;

  Err, ErrField : Integer;

  NetName, Path: WideString;

  NameNT : PWChar;

  Size : Integer;

Begin

  NetName:= AShareName;

  Buffer.shi2_NetName := PWideChar(NetName);

  Buffer.shi2_Type:= STYPE_DISKTREE;

  Buffer.shi2_Remark:= nil;

  Buffer.shi2_Permissions:= ACCESS_ALL;

  Buffer.shi2_MaxUsers:= DWORD(-1);

  Buffer.shi2_Current_Uses:= DWORD(-1);

  Path:= AFolder;

  Buffer.shi2_Path:= PWideChar(Path);

  Buffer.shi2_PassWord:= nil;



  Err:= NetShareAdd(nil,2,@Buffer, ErrField);

  Result:= Err = 0;

  if not Result then

    begin

    Size := SizeOf(WideChar)*256;

    GetMem(NameNT,Size);

    StringToWideChar(AShareName,NameNT,Size);

    NetShareDel(nil,NameNT,0);

    ReShareFolder(AFolder, AShareName);

  end;

end;



procedure TForm1.ButtonXClick(Sender: TObject);

begin

  ReShareFolder('C:\Documents and Settings\All Users\Documenten\MyAppName', 'TestX' );

end;

Open in new window

0
 
LVL 13

Expert Comment

by:aflarin
ID: 33557292
Hm. when I try to create share with existing share name, it returns
2118: The name has already been shared. Param index - 0
0
 
LVL 25

Expert Comment

by:epasquier
ID: 33557331
Really, that is not a problem with sharing a folder that is already shared, as in this case IT IS JUST REPLACED.

Are you sure you can share the folder you want using windows explorer ?
0
 

Author Comment

by:Delphiwizard
ID: 33557414
epasquier:
Yes I can share the folder in Windows Explorer.
The folder nor the drivepath are shared. Only the default admninistrative share "C$" is available. When I select the same folder in my aplication, then it gives the mentioned error (even with a completely unique sharename).
systan:
I believe your code could result in an endless loop. If for some other reason, than a duplicate sharename, the share can't be created.
0
 
LVL 13

Expert Comment

by:aflarin
ID: 33557555
are you still sharing a folder on a local machine?

My function from http:#33556764 creates a share fine. did you still use it?

If you modified it, please show the code. There may be a problem there.


0
 
LVL 14

Expert Comment

by:systan
ID: 33557630
>>I believe your code could result in an endless loop. If for some other reason, than a duplicate sharename, the share can't be created.

huh, I tested it many times.  Even I clicked the button for many times it wont error.
0
 

Author Comment

by:Delphiwizard
ID: 33557730
aflarin:
Yes I still use that function

systan:
I believe it won't error because the only error you trap is an existing share. But if in any case a different error occurs then it would loop (in my homble opinion)
0
 
LVL 13

Expert Comment

by:aflarin
ID: 33557870
Could you show how you are using it?

1. Delphi version. Don't think it may be cause, because I checked on D7 and D2009
2. OS version
3. ShareName and Folder params. Maybe there is a typo there



0
 

Author Comment

by:Delphiwizard
ID: 33557982
vFolder:
\\COMPUTERNAME\C$\Documents and Settings\All Users\Documenten\MyAppName
vSharename:
"MyApp"

function DelenMapStarten(vFolder, vShareName : String) : Boolean;

var Buffer        : TShareInfo;

    Err, ErrField : Integer;

    NetName, Path : WideString;

Begin

  NetName                  := vShareName;

  Buffer.shi2_NetName      := PWideChar(NetName);

  Buffer.shi2_Type         := STYPE_DISKTREE;

  Buffer.shi2_Remark       := nil;

  Buffer.shi2_Permissions  := ACCESS_ALL; // Alle gebruikers

  Buffer.shi2_MaxUsers     := DWORD(-1);

  Buffer.shi2_Current_Uses := DWORD(-1);

  Path                     := vFolder;

  Buffer.shi2_Path         := PWideChar(Path);

  Buffer.shi2_PassWord     := nil;

  Err:= NetShareAdd(nil, 2, @Buffer, ErrField);

  Result:= (Err = 0);

  if NOT Result then

  begin

    ShowMessage( Format('Error %d: %s'#13#10'Param index - %d', [Err, GetWin32ErrorString(Err), ErrField]) );

  end;

end;

Open in new window

0
 
LVL 13

Assisted Solution

by:aflarin
aflarin earned 500 total points
ID: 33558000
>> vFolder:
>> \\COMPUTERNAME\C$\Documents and Settings\All Users\Documenten\MyAppName

That's it. You have to use only local path!

C:\Documents and Settings\All Users\Documenten\MyAppName

If you are trying to create share on other PC, you have to use the first param of NetShareAdd
0
 

Author Comment

by:Delphiwizard
ID: 33558058
Can I use the first param of NetShareAdd even when I'm on a local computer?
That would make things a lot easier for me, as I store the UNC-path in the database (because an other user in the network needs to be pointed to the same folder on the server)..
0
 
LVL 13

Expert Comment

by:aflarin
ID: 33558222
>> Can I use the first param of NetShareAdd even when I'm on a local computer?

I think you can, but it isn't a good idea. Why?

1. At the first you have to extract Server name and Local Path from UNC in any event. (Because server name is the first param on NetShareAdd and the local path is the shi2_Path of structure.

2. At the second... I'm not sure how Windows handles if you are using server name param on local machine. It should be ok, but... I don't like a risk in such cases
0
 

Author Comment

by:Delphiwizard
ID: 33558419
In my database I store two paths:
  1. Base-folder
  2. Templates-folder
Both are always located on the server.
Currently these paths are stored as UNCpath.
So I need to translate the UNC-path back to a local path in order to check for shares.
Can this be done easily?
Or else I need to do a reset of these paths, so the user can select them again. And then store it as local filepaths in the database?
 
0
 

Author Comment

by:Delphiwizard
ID: 33558552
You can forget the last conversion question of the UNC-path.
Got that covered.
0
 

Author Closing Comment

by:Delphiwizard
ID: 33558647
Thank you all.
aflarin has posted the first solution that supplies a informative errormessage and also came up with the cause of the error while sharing a folder (=> don't use a UNCpath locally)
0
 
LVL 14

Expert Comment

by:systan
ID: 33558686
I know it is already closed, but this can help you.

Here's the code to correct the  <vFolder>  even if includes the UNC path and even if it is already shared AND even if you don't issue a  <vSharename>.

What do you think?
function ReShareFolder(AFolder:String) : Boolean;

var

  Buffer : TShareInfo;

  Err, ErrField : Integer;

  NetName, Path: WideString;

  NameNT : PWChar;

  Size : Integer;

  AShareName: String;

Begin

  AShareName := AFolder;

  size := pos('$',Afolder);

  if size>0 then

  begin

  AFolder := copy(AFolder,size-1, length(AFolder)-(size-2));

  AFolder := StringReplace(AFolder, '$', ':',[rfReplaceAll, rfIgnoreCase]);

  end;



  repeat

  size := pos('\',AShareName);

  AShareName := copy(AShareName,size+1,length(AShareName)-size);

  until size=0;



  NetName:= AShareName;

  Buffer.shi2_NetName := PWideChar(NetName);

  Buffer.shi2_Type:= STYPE_DISKTREE;

  Buffer.shi2_Remark:= nil;

  Buffer.shi2_Permissions:= ACCESS_ALL;

  Buffer.shi2_MaxUsers:= DWORD(-1);

  Buffer.shi2_Current_Uses:= DWORD(-1);

  Path:= AFolder;

  Buffer.shi2_Path:= PWideChar(Path);

  Buffer.shi2_PassWord:= nil;



  Err:= NetShareAdd(nil,2,@Buffer, ErrField);

  Result:= Err = 0;

  if not Result then

    begin

    Size := SizeOf(WideChar)*256;

    GetMem(NameNT,Size);

    StringToWideChar(AShareName,NameNT,Size);

    NetShareDel(nil,NameNT,0);

    ReShareFolder(AFolder);

  end;

end;

Open in new window

0
 
LVL 14

Expert Comment

by:systan
ID: 33559096
>>So I need to translate the UNC-path back to a local path in order to check for shares.
Thats the answer of your need, what do you think?
0
 

Author Comment

by:Delphiwizard
ID: 33561963
It's worth testing, but for now I got all the basics covered.
The thing you do with AFolder to get the local path is something I do, but then before I go into this functies.
For the rest your function look good.
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
Delphi 10 Seattle Dataset Actions 5 78
How to fill array with TArray.Create? 14 78
Magic Software info 18 124
Delphi inherited method 6 61
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…
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…
This tutorial demonstrates a quick way of adding group price to multiple Magento products.
You have products, that come in variants and want to set different prices for them? Watch this micro tutorial that describes how to configure prices for Magento super attributes. Assigning simple products to configurable: We assigned simple products…

919 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

13 Experts available now in Live!

Get 1:1 Help Now