Solved

NetShareAdd: Error handling

Posted on 2010-08-30
38
1,198 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
Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
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
 
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

Active Directory Webinar

We all know we need to protect and secure our privileges, but where to start? Join Experts Exchange and ManageEngine on Tuesday, April 11, 2017 10:00 AM PDT to learn how to track and secure privileged users in Active Directory.

Question has a verified solution.

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

Suggested Solutions

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…
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…
Microsoft Active Directory, the widely used IT infrastructure, is known for its high risk of credential theft. The best way to test your Active Directory’s vulnerabilities to pass-the-ticket, pass-the-hash, privilege escalation, and malware attacks …
In an interesting question (https://www.experts-exchange.com/questions/29008360/) here at Experts Exchange, a member asked how to split a single image into multiple images. The primary usage for this is to place many photographs on a flatbed scanner…

821 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