Solved

NetShareAdd: Error handling

Posted on 2010-08-30
38
1,167 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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
> 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
Comment Utility
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
Comment Utility
ok, no,  8 is this parameter :
#define SHARE_PATH_PARMNUM 8

your path is incorrect
0
 

Author Comment

by:Delphiwizard
Comment Utility
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
Comment Utility
that confirms it :
Windows Error Message 123: 'ERROR_INVALID_NAME'
0
 

Author Comment

by:Delphiwizard
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
>> 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
Comment Utility
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
Comment Utility
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
How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

 
LVL 13

Expert Comment

by:aflarin
Comment Utility
>> 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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
>>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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
>> 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
Comment Utility
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
Comment Utility
>> 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
Comment Utility
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
Comment Utility
You can forget the last conversion question of the UNC-path.
Got that covered.
0
 

Author Closing Comment

by:Delphiwizard
Comment Utility
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
Comment Utility
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
Comment Utility
>>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
Comment Utility
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

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
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

15 Experts available now in Live!

Get 1:1 Help Now