windows-nt/Source/XPSP1/NT/shell/osshell/lmui/shrspec.txt
2020-09-26 16:20:57 +08:00

432 lines
20 KiB
Plaintext

This is a minimal description of this code, ntshrui.dll.
What it is
----------
This is a port/rewrite of the Win95 msshrui.dll (Win95 SLM source found in
\\flipper\chinet\src\wnet\msshrui, Win96+ on \\trango\slm\...). It provides a
"Sharing" property page for directories to allow local LanMan (SMB) shares
to be created for the selected directory. It provides a "Sharing..."
context menu to provide quick access to the "Sharing" property page.
It also provides a "Sharing" copy hook to handle directory renames and
move/deletes properly by warning the user about the shares that may
be need to be deleted in the process (shares aren't recreated based
on the directory's new name). Finally, there are a few API entrypoints
for programs to perform Share operations.
All of this functionality is dependent on being able to execute a NetShareEnum
at level 502, which requires Administrators local group or comm, print,
or server operator group membership. The APIs will fail and there will be no
Sharing UI in the explorer if this is not true.
One goal of the Win95 shell, carried forward to the NT shell, is to
be completely independent of network-specific code. The shell will
call WNet apis, which are network-independent. However, there are
no network-independent share creation APIs. Thus, the shell consults
the HKEY_CLASSES_ROOT\Network\SharingHandler key to determine the
network-specific sharing handler DLL. Note that under Windows 95,
only one server at a time was allowed to run. Under NT, multiple
servers may run (SFM -- Macintosh, FPNW -- NetWare, SMB -- Windows
Networking). However, the shell hasn't been expanded to handle this.
The exported APIs are:
DllGetClassObject
DllCanUnloadNow
IsPathSharedA
IsPathSharedW
IsPathShared = IsPathSharedA
SharingDialogA
SharingDialogW
SharingDialog = SharingDialogA
GetNetResourceFromLocalPathA
GetNetResourceFromLocalPathW
GetNetResourceFromLocalPath = GetNetResourceFromLocalPathA
GetLocalPathFromNetResourceA
GetLocalPathFromNetResourceW
GetLocalPathFromNetResource = GetLocalPathFromNetResourceA
There are A and W versions for all of these, even though there aren't
clients for all versions of the API. Namely, the shell uses the W
versions. However, the SharingDialog API is used only in its A version
by the FAX group (they are the only known client). However, to avoid
problems later, both A and W versions are implemented.
There are two Windows 95 APIs not implmented:
PrintShareProperties
ShareShutdownNotify
The implemented, exported APIs do the following:
DllGetClassObject, DllCanUnloadNow -- standard OLE entrypoints. Used
for the shell extensions (context-menu, property sheet, copy hook).
IsPathShared -- returns TRUE if a path is shared. Used by the shell to
determine when to put a "sharing" hand on a folder. Must be fast, as
the shell calls it for every folder it displays.
SharingDialog -- Displays the same dialog as the property sheet page, but
in a modal dialog form. used by the FAX group.
GetNetResourceFromLocalPath -- Given a local path on a machine, returns
a UNC form of that path, if the path is shared. This is used to store
a network-aware form of the path in a shortcut for use if the shortcut
is copied to another machine, such that the local path stored in the
shortcut isn't available.
GetLocalPathFromNetResource -- The opposite of the above, it determines
the local path of an object given a UNC path.
The Sharing page
----------------
The Sharing property page and context-menu shortcut should appear when the
user right-clicks on anything that corresponds to a file system directory.
This is basically a folder or a disk icon. The drive can be either a hard
drive, a floppy, or a CD-ROM. We only support the page when the folder or
drive is local: the page is not available when looking at remote folders
either via a UNC path in the network neighborhood or via a mapped drive
letter path.
The Sharing page behaves as follows. If there are no shares, the "Not Shared"
radio button is checked and everything inside the "Shared As" radio button box
is grayed. Clicking "Shared As" ungrays the controls within its box.
There are two "modes" when the "Shared As" button is checked: initial mode and
already-shared mode. Initial mode is when the folder has not yet been shared.
In this case, the "Share name" control is a single-line edit control. All the
controls can be used to enter information for one new share. In
"already-shared" mode, the folder already is shared with one or more names.
In this case, the "Share name" control is a drop-down list box with a list of
shares for this directory. The other controls are filled with the data
associated with the share currently selected in the drop-down control. Changing
the comment, user limit, or permissions at this point causes the selected
share to be modified accordingly, but does not add a new share.
Note that standard property sheet semantics hold with all the changes made to
the sharing characteristics of the selected folder, namely, that no changes
are actually made to the machine state until "OK" or "Apply" is chosen.
In initial mode, only a single share can be created (unless you hit "apply"
and subsequently change to "already-shared" mode). In already-shared mode,
there are one or two additional buttons to control creating/deleting shares.
The "New Share..." button will always be visible in this mode. Pressing it
pops up a "New Share" modal dialog that allows you to create another share
name for the same directory. This other share might have a different comment,
different user limit, and most importantly, different permissions. The
operation of the controls in this dialog are identical to the operation of
the controls on the property sheet in "initial" mode. If there are two or
more shares for the directory, then the "Remove Share" button is visible.
Pressing this removes the currently selected share (pending "OK" or
"Apply" of course).
To delete the final share, or to delete all the shares at once, you must
choose the "Not shared" radio button. If there is currently more than one
share for the directory, this confirmation message is displayed:
This folder is shared more than once. Are you sure you wish
to remove all these shares?
yes/no
Hitting "no" causes the "Shared As" button to be clicked again. Hitting "yes"
causes all shares to be marked for removal. However, the shares are still
left in the property sheet, but grayed. If the "Shared As" button is pressed
again, then it will be as if the "Not Shared" button was never pressed: all
share properties are retained, and hitting "Apply" or "OK" will make all
previously requested changes.
A default share name is put in the "Share Name" SLE in "initial" mode, as
follows. If the directory is not the root of the volume, for example,
C:\foo\bar, then the default share name is the last component of the path,
in this case, bar. If the directory is a root, then the default is the drive
letter, in the previous example, C. However, if the default name is already
used as a share name on the system, then there is no default given.
The user limit controls work as follows. The "Allow" text box allows
the user to enter a specific number of users. Only numbers are allowed to
be typed: no letters or other characters. If the number is out of range,
the number reverts to the default user limit (10) when the edit control loses
focus. Note that no error message is given: we do this silently. Up and down
arrows increase and decrease the number. Since we are using the Win95
up/down control, the range for the number is 1 to 32767. The number doesn't
wrap. If the user chooses "Maximum allowed" after having typed a number in
the "allow" edit box, the edit box is cleared but the number is remembered.
If the user subsequently clicks the "allow" radio button, the remembered
number is reinserted into the edit control as the default.
The Permissions button brings up the standard security (ACL) editor with
the permissions of the share. The default permissions for a share are World
access, Full control. As with everything else, the permissions aren't
committed until the property page "OK" or "Apply" button is pressed.
Note that hitting the escape key should cancel the property page no matter
what the current keyboard focus is. I mention this because I've had problems
getting this to work with the focus on the (subclassed) "Allow" edit control.
If the user types a share name that is the same as another share for this same
directory (in the "New Share" dialog), then the following warning message
is displayed:
The share name %1 already exists for this resource. Please
choose another share name.
If the user types a share name in the "New Share" dialog or on the property
sheet (initial mode, and then hits "Apply" or "OK"), and that name is the same
as another share on the machine for another path, then this message is
displayed:
You are already sharing %1 using the name %2. Do you want
to share %3 using the name %2 instead?
If the user hits "yes", then we use the new name as a new share, and put the
other share on a list of "shares of the same name but different directories"
to delete when the user hits "OK" or "Apply".
The share names are validated as follows. If no share name is typed in you
get this error:
You must type a share name for this resource.
If you use illegal characters in the share name (particularly *, but there may
be others), you get this error:
The share name contains invalid characters.
If the name is not accessible from DOS, because it isn't 8.3 or for some other
reason, you get this warning:
The share name %1 is not accessible from some MS-DOS
workstations. Are you sure you want to use the share name?
Note that there is special handling code to allow users to create and delete
the default disk shares, namely <drive>$ for each hard drive, and admin$. Only
configuration of IPC$ is not supported, as it has no associated storage.
These are handled specially as follows. Selecting one of them, getting the
sharing property page, and pressing "Permissions" will pop up the message:
This has been shared for administrative purposes.
The permissions cannot be set.
When the share name is being validated in the property page or "New Share"
dialog, a check is made against "IPC$". If it matches, this message is
displayed:
The share names ADMIN$ and IPC$ are reserved and may not be used.
Note that we mention ADMIN$ as a restricted share name, even though we allow
its creation in one particular case. If they use the name "ADMIN$", we
disallow it for all cases except if the selected directory is the Windows
directory, since that is the only place ADMIN$ can share.
We do allow the creation of <drive>$ shares at places besides the proper
drive. I.e., we allow you to share D:\ as C$. If, however, you share C:\ as
C$, it gains special "default" status, any permissions you may have edited are
discarded (silently) and the default permissions are instantiated.
Applying changes
----------------
When the user hits "OK" or "Apply" the following things occur. First, the
list of shares with the same name as new shares but with different directories
is deleted. Second, all share changes for the current directory are applied:
either added, deleted, or modified. The following error messages may occur
if we get a network error. For add:
An error occurred while trying to share %1. %2
The shared resource was not created at this time.
For delete:
An error occurred while trying to delete share %1. %2
For modify:
An error occurred while trying to modify share %1. %2
After the changes are applied, the page is refreshed. This is unnecessary
if the user hit "OK", but essential if they pressed "Apply". The Apply button
is grayed out, indicating there are no pending changes. Note that the act of
applying changes might convert the page from "already-shared" mode to initial
mode or vice-versa.
When a share to be deleted that is currently being accessed by a user, one of
the following error messages will be displayed (the same error messages are
used in the copy hook handler):
There are %1!d! user(s) connected to %2. If you stop sharing %2,
they will be disconnected. Do you want to continue?
There are %1!d! file(s) open by %2!d! user(s) connected to %3.
If you stop sharing %3, the files will close, which may cause
these users to lose data. Do you want to continue?
One bug to beware of: when adding a second or greater share, or when deleting
shares but leaving at least one, the combo box of shares should be re-filled
correctly with the new set of shares for the directory.
Copy hook
---------
A copy hook in the tool monitors shell rename/move/delete operations on
directories. If the directory or a subdirectory is shared, then an appropriate
error message is displayed and the user is forced to verify the operation.
In particular, one of the following messages will be displayed:
There are %1!d! user(s) connected to %2. If you stop sharing %2,
they will be disconnected. Do you want to continue?
There are %1!d! file(s) open by %2!d! user(s) connected to %3.
If you stop sharing %3, the files will close, which may cause
these users to lose data. Do you want to continue?
You are sharing %1 as %2. Others may be using files in this
folder. If you delete the folder, it will no longer be shared.
Are you sure you want to delete it?
Security editor
---------------
If the security editor DLL (acledit.dll) can't be loaded, this message is
reported:
Error invoking the security editor.
Initialization
--------------
All of the above discussion assumes that the LanMan server service is
running. This section describes how we determine the server is running,
how we initialize our cache of shares (subsequently used by the Explorer
to use for annotating folders with "hand" icons), what we do if the server
is started manually after boot time, and what we do if the server is stopped
sometime after boot time.
Windows 95 initializes during DLL initialization by doing a NetServerGetInfo
to determine if the server is running. We can't do this because it is bad
to do net operations in DLL initialization code, for reasons having to do
with the process mutant. In addition, because the server is a service
controlled by the service controller that can be started manually and stopped
at will, we would like to update the display of visible shares in the
Explorer whenever the server starts or stops. For instance, if the server
stops, we would like to remove all the "hand" icons from visible shared
folders.
Ideally, we would receive a notification from either the service controller
or the server service whenever the server starts or stops. Since there is no
support for this in the system, and none is likely to appear soon, we do two
things. One, during initialization we wait as appropriate for the server to
start. Note that the server starts asynchronously from the shell at boot time,
so it is more than conceivable that the shell will start before the server
does. In this case, if we can detect that the server is configured to start
and is in fact starting, then we wait for it. We have certain timeouts to
ensure that we don't wait too long. Secondly, if the server starts or stops
after the shell has started, the user only needs to hit "refresh" in one
Explorer window. If at this point we notice that the server has changed state,
then we cause *all* explorer windows to refresh.
Test scenarios
--------------
The following are a list of ad-hoc test scenarios to pursue on this component.
In all cases, assume there are two machines: A and B, and the user is sitting
at machine A.
For the next few scenarios, log on as a normal user (not power user or
administrator, etc).
-- Be sure there is no sharing UI, even for things known to be shared.
Exercise copy hook functionality by renaming/moving/deleting a directory.
-- Rename a directory known to be shared. Log off, Log on as administrator.
NOTE: There is no UI (save for winfile / server manager) to get rid of the
orphaned share! Rename the directory back to the name that was shared.
See if the explorer paints the "sharing" hand on it.
-- Invoke all the APIs programmatically, and be sure they return appropriate
errors.
For the rest of these, log on as a member of the Administrators group.
-- Open My Computer. Be sure the "Sharing..." context-menu item appears on
all local drive objects, on floppy drives, and on CD-ROMs. Be sure it doesn't
appear on network-mapped drive letters. Share each of them.
-- Notice that hard drive roots (c:\, d:\, etc) should be shared by default, as
should the windows directory via ADMIN$. On the sharing property page for
these, press "Permissions" and notice you get a warning message disallowing
permissions changes.
-- Remove and recreate the default shares, including ADMIN$. Create a share
C$ on D:\, and note that it isn't a default share at that point (you can edit
its permissions).
-- Share a directory. Hit apply. Add a number of shares. Hit apply. Make sure
the combo box is correct. Delete a bunch of shares, hit apply. Make sure the
combo is once again correct.
-- Make sure the "New Share" and "Remove Share" appear and disappear at the
proper times.
-- Make sure the tab order doesn't include the "allow x users" edit control
or spin button unless the "Allow" radio button is selected.
-- Make sure the comment is limited to 256 characters, and the share name to
80 characters, in both the "initial mode" property page and the "New Share"
dialog.
-- Make sure context-sensitive help appears on all relevant controls of both
the property page and New Share dialog. Make sure the Help buttons are active
on all five ACL editor dialogs. (When we have a help file).
-- Make sure all keyboard mnemonics are unique, and that all controls have
appropriate mnemonics.
-- Make sure that choosing a share in the combo box, changing a parameter,
choosing another share in the combo box, changing one of its parameters works.
That is, switching between shares in the combo box should show the selected
share's data. Hit apply after these changes. Make sure the data got applied
correctly (use "net share" at the command line, or a separate API tool), and
that further switching between shares in the combo box still displays the
correct data.
-- In "New Share", type a share name that already exists. Get a pop-up and
choose "yes" to reuse the share name. Hit apply and be sure the old one went
away and the new one got created. Be sure the explorer "sharing hands" also
changed appropriately. Do the same test when creating a share directly on the
sharing page in "initial mode".
-- In the property page, delete a share that a user has a connection to.
Delete a share that a user has a connection to *and* a file open on. These are
two different scenarios that should pop up warnings when the user hits "apply".
-- In the explorer, delete, rename, and move (by drag/drop), a shared
directory. Make sure the sharing warning comes up. Do the same thing when
a user has a connection to the share. Do the same thing when a user has a
file open on the connection. These should bring up three different warning
scenarios. Do the same thing for a parent of a shared directory. Do the same
thing for a directory that has more than one shared child directory, each with
connections and open files.
-- Test the APIs
-- Stop the server (via "net stop server") between any two operations.
For instance, after bringing up the property sheet, and editing some items,
stop the server before hitting Apply.
-- Stop the server, then try to rename/delete/move a shared folder in the
explorer.
-- Bring up properties on a shared directory, stop the server, *hit F5 in the
explorer to refresh it, then try to apply share changes.
-- Stop the server, hit "F5" (refresh) in an explorer window to clear the
"sharing" hands, then start the server and hit F5 again to see the sharing
hands reappear.