Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

957 lines
27 KiB

//***************************************************************************
//
// Library:
// HOMEDRV.DLL
//
//
// Author:
// Joev Dubach
//
//
// Purpose:
// HOMEDRV is a File Manager extension DLL. An extension DLL adds
// a menu to File Manager, contains entry point that processes menu
// commands and notification messages sent by File Manager, and
// queries data and information about the File Manager windows. The
// purpose of an extension DLL is to add administration support
// features to File Manager, for example, file and disk utilities.
// Up to five extension DLLs may be installed at any one time.
//
// HOMEDRV adds a menu called "HomeDrive" to File Manager and
// processes all the messages that are sent by File Manager to the
// HOMEDRV DLL. In particular, it allows the user to select
// "Connect to Home Drive" from the HomeDrive menu. Using RPC, the
// DLL asks a HomeDrive server running on NT for the home share of
// the given user. If it receives this information, it redirects
// a network drive to this share. Then it tells File Manager to
// refresh its windows, so as to bring the new connection up.
//
// Usage:
// File Manager installs the extensions that have entries in the
// [AddOns] section of the WINFILE.INI initialization file. An entry
// consists of a tag and a value. To load HOMEDRV.DLL as a File
// Manager extension, add the following to WINFILE.INI (assuming the
// DLL resides in c:\win\system32):
//
// [AddOns]
// HomeDrive Extension=c:\win\system32\homedrv.dll
//
//
// Menu Options:
// Following menu items belong to the "Extension" menu that is added
// to File Manager:
//
// Connect to Home Drive - Redirects a drive to a given user's share
// About HomeDrive... - Displays About dialog
//
//
// More Info:
// Query on-line help on: FMExtensionProc, File Manager Extensions, RPC
//
//
//***************************************************************************
//
// Inclusions
//
#include <direct.h>
#include <errno.h>
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <ctype.h>
#include <rpc.h> // RPC data structures and APIs
#include <rpcerr.h>
#include <wfext.h>
#include "homedrv.h"
#include "home.h" // header file generated by MIDL compiler
#include "..\homedir.h" // Server/client error codes
//
// Global variables
//
HANDLE ghDllInst; // DLL's instance handle
HMENU ghMenu; // Extension's menu handle
WORD gwMenuDelta; // Delta for extension's menu items
char gOldAddress[STRINGSIZE]; // Server network address
BOOL gRefreshNecessary; // Tells if FM needs to refresh windows
//
// Function prototypes
//
HMENU FAR PASCAL
FMExtensionProc (
HWND hwndExtension,
WORD wMesssage,
LONG lParam
);
BOOL FAR PASCAL
AboutDlgProc (
HWND hDlg,
unsigned uMessage,
WORD wParam,
LONG lParam
);
BOOL FAR PASCAL
MenuADG(
HWND hDlg,
unsigned message,
WORD wParam,
LONG lParam
);
void
Connect(
char * drive,
char *dir
);
void
CheckWinStatus(
UINT status
);
void
CheckRpcStatus(
char *ProcName,
RPC_STATUS status
);
void
CheckMyStatus(
char *ProcName,
MY_STATUS status
);
void
CreateBinding(
char *Address
);
void
DestroyBinding(
void
);
//***************************************************************************
//
// LibMain()
//
// Purpose:
//
// LibMain is called by LibEntry. LibEntry is called by Windows
// when the DLL is loaded. The LibEntry routine is provided
// in the LIBENTRY.OBJ in the SDK Link Libraries disk. (The
// source LIBENTRY.ASM is also provided.)
//
// LibEntry initializes the DLL's heap if a HEAPSIZE value is
// specified in the DLL's DEF file. After this, LibEntry calls
// LibMain. The LibMain function below satisfies that call.
//
// The LibMain function should perform additional initialization
// tasks required by the DLL. LibMain should return a value of
// TRUE if the initialization is successful.
//
//
// Parameters:
//
// IN:
// hLibInst - DLLs instance handle
// wDataSeg - Data segment
// cbHeapSize - Size of the DLL's heap
// lpszCmdLine - Command line
//
// OUT:
// N/A
//
// Return Value:
//
// TRUE if the initialization is successful; FALSE otherwise.
//
//***************************************************************************
int FAR PASCAL
LibMain (
HANDLE hLibInst,
WORD wDataSeg,
WORD cbHeapSize,
LPSTR lpszCmdLine
)
{
char server[STRINGSIZE];
if(GetPrivateProfileString("HomeDrive", // Section of winfile.ini
"Server", // Variable
"", // Default
server, // Where to put it
STRINGSIZE,
"winfile.ini"))
{
CreateBinding(server);
strcpy(gOldAddress,server); // save the address
}
ghDllInst = hLibInst;
return (TRUE);
} // LibMain()
//***************************************************************************
//
// WEP()
//
// Purpose:
//
// Performs cleanup tasks when the .DLL is unloaded; in this case,
// it destroys the binding to the RPC HomeDrive server. The WEP()
// is called automatically by Windows when the DLL is unloaded.
//
// Make sure that the WEP() is @1 RESIDENTNAME in the EXPORTS
// section of the .DEF file. This ensures that the WEP() can
// be called as quickly as possible. Incidently, this is why
// the WEP() is called the WEP() instead of WindowsExitProcedure().
// It takes up the minimum amount of space and is quickly located.
//
//
// Parameters:
//
// IN:
// bSystemExit - Type of exit
//
// OUT:
// N/A
//
// Return Value:
//
// TRUE.
//
//***************************************************************************
int FAR PASCAL
WEP(
int bSystemExit
)
{
DestroyBinding();
return (TRUE);
} // WEP()
//***************************************************************************
//
// FMExtensionProc()
//
// Purpose:
//
// This is an application-defined callback function. It processes menu
// commands and messages sent to HOMEDRV.DLL.
//
//
// Parameters:
//
// IN:
// hwndExtension - Identifies the File Manager window
// wMessage - Message sent to extension DLL
// lParam - Message information
//
// OUT:
// N/A
//
// Return Value:
//
// When the wMessage is FMEVENT_INITMENU, handle to extension's menu
// should be returned; otherwise a NULL value.
//
//***************************************************************************
HMENU FAR PASCAL
FMExtensionProc (
HWND hwndExtension,
WORD wMessage,
LONG lParam
)
{
LPFMS_LOAD lpLoad;
FARPROC lpDialogProc;
FARPROC lpProc; // pointer to the chosen function
switch (wMessage)
{
// ****************** File Manager Events
case FMEVENT_LOAD:
lpLoad = (LPFMS_LOAD) lParam;
// Assign the menu handle from the DLL's resource
ghMenu = LoadMenu (ghDllInst, "ExtensionMenu");
lpLoad->hMenu = ghMenu;
// This is the delta we are being assigned.
gwMenuDelta = lpLoad->wMenuDelta;
// Size of the load structure
lpLoad->dwSize = sizeof (FMS_LOAD);
// Assign the popup menu name for this extension
lstrcpy (lpLoad->szMenuName, "Ho&meDrive");
// Return that handle
return (ghMenu);
// ****************** Extension menu commands
case IDM_CONNECT:
gRefreshNecessary=FALSE;
lpProc = MakeProcInstance(MenuADG, ghDllInst);
DialogBox(ghDllInst, // current instance
"CONNECTBOX", // resource to use
hwndExtension, // parent handle
lpProc); // About() instance address
if (gRefreshNecessary)
{
SendMessage(hwndExtension,
FM_REFRESH_WINDOWS, // To bring the drive up
1, // Non-zero refreshes all windows
0L);
}
FreeProcInstance(AboutDlgProc);
break;
case IDM_ABOUTEXT:
lpDialogProc = MakeProcInstance(AboutDlgProc, ghDllInst);
DialogBox (ghDllInst,
"ABOUTBOX",
hwndExtension,
lpDialogProc);
FreeProcInstance(AboutDlgProc);
break;
}
return (NULL);
} // FMExtensionProc()
//***************************************************************************
//
// AboutDlgProc()
//
// Purpose:
//
// Procedure to handle About dialog messages. This dialog displays
// copyright and help information.
//
//
// Parameters:
//
// IN:
// hDlg - Dialog window handle
// uMessage - Dialog message
// wParam - Message information
// lParam - Additional message information
//
// OUT:
// N/A
//
// Return Value:
//
// Appropriate value for the dialog message.
//
//***************************************************************************
BOOL FAR PASCAL
AboutDlgProc(
HWND hDlg,
unsigned uMessage,
WORD wParam,
LONG lParam
)
{
#define ICONLEFTCOORD 8
#define ICONTOPCOORD 8
#define ICONRIGHTCOORD 40
#define ICONBOTTOMCOORD 40
#define ICONXLOC 9
#define ICONYLOC 8
HDC hdc;
int i;
DWORD temp;
int x;
int y;
static HWND hIcon[16];
volatile int j;
static BOOL FirstTime=TRUE;
static BOOL CookieOn=FALSE;
switch (uMessage)
{
case WM_INITDIALOG:
for(i=0;i<16;i++)
hIcon[i]=LoadIcon(ghDllInst,MAKEINTRESOURCE(ANIM1+i));
return (TRUE);
case WM_COMMAND:
switch (wParam)
{
case IDOK:
case IDCANCEL:
for(i=0;i<16;i++)
DestroyIcon(hIcon[i]);
EndDialog (hDlg, TRUE);
return (TRUE);
default:
break;
} // switch (wParam)
case WM_LBUTTONUP:
case WM_RBUTTONUP:
if((CookieOn != (uMessage==WM_LBUTTONUP)) && (wParam & MK_CONTROL))
{
hdc=GetDC(hDlg);
temp=GetCurrentPosition(hdc);
x=LOWORD(lParam)-LOWORD(temp);
y=HIWORD(lParam)-HIWORD(temp);
if((x>ICONLEFTCOORD)&&(x<ICONRIGHTCOORD)&&
(y>ICONTOPCOORD)&&(y<ICONBOTTOMCOORD))
{
if(uMessage==WM_LBUTTONUP)
{
i=1;
}
else
{
i=15;
}
for(;(i<16) && (i>0);)
{
DrawIcon(hdc,ICONXLOC,ICONYLOC,hIcon[i]);
if(!FirstTime)
{
for(j=0;j<30000;j++);
}
if(uMessage==WM_LBUTTONUP)
{
i++;
}
else
{
i--;
}
}
DrawIcon(hdc,ICONXLOC,ICONYLOC,hIcon[0]);
FirstTime=FALSE;
if(uMessage==WM_LBUTTONUP)
{
ShowWindow(GetDlgItem(hDlg,ID_OPAQUERECT),SW_SHOWNORMAL);
ShowWindow(GetDlgItem(hDlg,ID_CREDITS),SW_SHOWNORMAL);
CookieOn=TRUE;
}
else
{
ShowWindow(GetDlgItem(hDlg,ID_OPAQUERECT),SW_HIDE);
ShowWindow(GetDlgItem(hDlg,ID_CREDITS),SW_HIDE);
CookieOn=FALSE;
}
ReleaseDC(hDlg,hdc);
return(TRUE);
}
else
{
ReleaseDC(hDlg,hdc);
}
}
break;
case WM_DESTROY:
CookieOn=FALSE;
} // switch (message)
return (FALSE);
} // AboutDlgProc
/****************************************************************************
FUNCTION: MenuADG(HWND, unsigned, WORD, LONG)
PURPOSE: Processes messages for the "Connect" dialog box.
MESSAGES:
WM_INITDIALOG - initialize dialog box
WM_COMMAND - Input received
COMMENTS:
****************************************************************************/
BOOL FAR PASCAL
MenuADG(
HWND hDlg, // window handle of the dialog box
unsigned message, // type of message
WORD wParam, // message-specific information
LONG lParam
)
{
char name[STRINGSIZE];
char dir[STRINGSIZE];
char server[STRINGSIZE];
char drive[3]="E:"; // It would be a shame to change 3 to STRINGSIZE.
HWND hWndListBox;
MY_STATUS TempStat;
switch (message) {
case WM_INITDIALOG: // message: initialize dialog box
// Initialize Drive list box
hWndListBox = GetDlgItem(hDlg, IDDRIVE);
while(drive[0]<='Z')
{
SendMessage(hWndListBox,
LB_ADDSTRING,
0,
(LONG) ((char _far *) drive));
(drive[0])++;
}
// Get defaults from stored data in winfile.ini
if(GetPrivateProfileString("HomeDrive", // Section of winfile.ini
"Name", // Variable
"", // Default
name, // Where to put it
STRINGSIZE,
"winfile.ini"))
{
SetDlgItemText(hDlg, IDNAME, name);
}
SetDlgItemText(hDlg, IDSERVER, gOldAddress);
if(GetPrivateProfileString("HomeDrive", // Section of winfile.ini
"Drive", // Variable
"", // Default
drive, // Where to put it
3,
"winfile.ini"))
{
SendMessage(hWndListBox,
LB_SELECTSTRING,
(UINT) -1,
(LONG) ((char _far *) drive));
}
return (TRUE);
case WM_COMMAND: // message: received a command
switch (wParam)
{
case IDOK: // "OK" box selected?
hWndListBox = GetDlgItem(hDlg, IDDRIVE);
GetDlgItemText(hDlg,IDNAME,name,STRINGSIZE);
GetDlgItemText(hDlg,IDSERVER,server,STRINGSIZE);
if (strcmp(gOldAddress,server)) // server has changed
{
DestroyBinding();
CreateBinding(server);
strcpy(gOldAddress,server);
}
SendMessage(hWndListBox,
LB_GETTEXT,
(WORD) SendMessage(hWndListBox,
LB_GETCURSEL,
0,
0L),
(LONG) ((char _far *) drive));
// Save defaults
WritePrivateProfileString("HomeDrive","Name",name,
"winfile.ini");
WritePrivateProfileString("HomeDrive","Server",server,
"winfile.ini");
WritePrivateProfileString("HomeDrive","Drive",drive,
"winfile.ini");
RpcTryExcept
{
CheckMyStatus(
"RPC Get call",
TempStat = RpcHomesvrGet(name,dir)
);
if (!TempStat)
{
Connect(drive,dir);
}
}
RpcExcept(1)
{
CheckRpcStatus("Runtime library reported an exception",
RpcExceptionCode()
);
}
RpcEndExcept
if (!TempStat)
{
EndDialog(hDlg, TRUE);
}
return (TRUE);
case IDCANCEL:
EndDialog(hDlg, TRUE);
return (TRUE);
case IDDRIVE:
// If the user double clicks the list box, treat it as OK.
if (HIWORD(lParam)==LBN_DBLCLK)
{
SendMessage(hDlg,WM_COMMAND,IDOK,0L);
}
}
break;
}
return (FALSE); // Didn't process a message
}
void
Connect(
char *Drive,
char *Dir
)
{
// I assume that the share is valid. The syntax is checked by the
// HomeDrive administrative application when it's entered into the
// database, so it's a good bet.
char Share[STRINGSIZE];
char Subdir[STRINGSIZE];
char CurrConnect[STRINGSIZE];
UINT BuffSize=STRINGSIZE;
UINT status;
int i=0;
int j=0;
int k;
// Parse the share information.
for(k=1;k<=4;k++)
{
while(Dir[i]!='\\' && Dir[i]!='\0')
{
Share[i]=Dir[i];
i++;
}
Share[i]=Dir[i];
i++;
}
Share[--i]='\0';
while(Dir[i]!='\0')
{
Subdir[j]=Dir[i];
i++;
j++;
}
Subdir[j]='\0';
switch(status=WNetGetConnection(Drive,CurrConnect,&BuffSize))
{
case WN_NOT_CONNECTED:
gRefreshNecessary=TRUE;
status=WNetAddConnection(Share,"",Drive);
CheckWinStatus(status);
// If the File Manager had more hooks, I'd actually do this.
//if (status==WN_SUCCESS)
// {
// change directory
// change drive
// }
break;
case WN_CONNECTION_CLOSED:
gRefreshNecessary=TRUE;
status=WNetCancelConnection(Drive,TRUE); // TRUE _forces_ close
CheckWinStatus(status);
if (status==WN_SUCCESS)
{
status=WNetAddConnection(Share,"",Drive);
CheckWinStatus(status);
//if (status==WN_SUCCESS)
// {
// change directory
// change drive
// }
}
break;
case WN_SUCCESS:
if(strcmp(_strlwr(CurrConnect),Share)!=0) // Share is lowercase
{
gRefreshNecessary=TRUE;
status=WNetCancelConnection(Drive,TRUE); // TRUE _forces_ close
CheckWinStatus(status);
if (status==WN_SUCCESS)
{
status=WNetAddConnection(Share,"",Drive);
CheckWinStatus(status);
//if (status==WN_SUCCESS)
// {
// change directory
// change drive
// }
}
}
//else // already connected
// {
// change directory
// change drive
// }
break;
default:
CheckWinStatus(status);
}
}
void
CheckWinStatus(
UINT status
)
{
char temp[60];
switch (status)
{
case WN_SUCCESS:
break;
case WN_NOT_SUPPORTED:
MessageBox(HWND_DESKTOP,
"That function is not supported by your network.",
"Error",
MB_OK);
break;
case WN_OUT_OF_MEMORY:
MessageBox(HWND_DESKTOP,
"Out of memory.",
"Error",
MB_OK);
break;
case WN_NET_ERROR:
MessageBox(HWND_DESKTOP,
"An error occured on the network.",
"Error",
MB_OK);
break;
case WN_BAD_NETNAME:
MessageBox(HWND_DESKTOP,
"Your network share could not be reached.",
"Error",
MB_OK);
break;
case WN_BAD_PASSWORD:
case WN_ACCESS_DENIED:
MessageBox(HWND_DESKTOP,
"Access denied. Check your password, or see your system administrator.",
"Error",
MB_OK);
break;
case WN_BAD_VALUE:
case WN_BAD_LOCALNAME:
MessageBox(HWND_DESKTOP,
"Invalid drive specification.",
"Error",
MB_OK);
break;
case WN_OPEN_FILES:
MessageBox(HWND_DESKTOP,
"Could not delete previous connection. Try closing files open on that drive.",
"Error",
MB_OK);
break;
case WN_BAD_POINTER:
case WN_MORE_DATA:
default:
wsprintf(temp,
"Internal error %u; contact your system administrator.",
status);
MessageBox(HWND_DESKTOP,
temp,
"Error",
MB_OK);
}
}
void
CheckRpcStatus(
char *ProcName,
MY_STATUS status
)
{
char buffer[10];
char temp[100] = "RPC Exception in ";
switch (status)
{
case RPC_S_INVALID_STRING_BINDING:
case RPC_S_SERVER_UNAVAILABLE:
case RPC_S_CALL_FAILED_DNE:
case RPC_S_ACCESS_DENIED:
MessageBox(HWND_DESKTOP,
"Check that the HomeDrive server is running on an accessible server.",
strcat(
temp,
ProcName
),
MB_OK);
break;
case RPC_S_OK:
break;
default:
MessageBox(HWND_DESKTOP,
_itoa(status,buffer,10),
strcat(
temp,
ProcName
),
MB_OK);
}
}
void
CheckMyStatus(
char *ProcName,
MY_STATUS status
)
{
char buffer[10];
switch (status) {
case HOMEDIR_S_OK:
break;
case HOMEDIR_S_ENTRY_ALREADY_EXISTS:
MessageBox(HWND_DESKTOP,
"That name is already in the database.",
"Error",
MB_OK);
break;
case HOMEDIR_S_ENTRY_NOT_FOUND:
MessageBox(HWND_DESKTOP,
"That name is not in the database.",
"Error",
MB_OK);
break;
default: // This should never happen
MessageBox(HWND_DESKTOP,
_itoa(
status,
buffer,
10
),
"Fatal Error",
MB_OK);
}
}
// ====================================================================
// MIDL allocate and free
// ====================================================================
void *
MIDL_user_allocate(
size_t len
)
{
return(malloc(len));
}
void
MIDL_user_free(
void * ptr
)
{
free(ptr);
}
void
CreateBinding(
char *pszNetworkAddress
)
{
char * pszUuid = "12345678-1234-1234-1234-123456789ABC";
char * pszProtocolSequence = "ncacn_np";
char * pszEndpoint = "\\pipe\\home";
char * pszOptions = NULL;
char * pszStringBinding = NULL;
// FUTURE ENHANCEMENT: use the locator to find the server.
/*
RPC_NS_HANDLE ImportContext;
CheckRpcStatus("RpcNsBindingImportBegin",
RpcNsBindingImportBegin(
RPC_C_NS_SYNTAX_DEFAULT,
"/.:/Home",
home_ClientIfHandle,
NULL,
&ImportContext
)
);
CheckRpcStatus("RpcNsBindingImportNext",
RpcNsBindingImportNext(
ImportContext,
&home_BindingHandle
)
);
CheckRpcStatus("RpcNsBindingImportDone",
RpcNsBindingImportDone(&ImportContext)
);
*/
//
CheckRpcStatus("RpcStringBindingCompose",
RpcStringBindingCompose(
(unsigned char *) pszUuid,
(unsigned char *) pszProtocolSequence,
(unsigned char *) pszNetworkAddress,
(unsigned char *) pszEndpoint,
(unsigned char *) pszOptions,
(unsigned char * *) &pszStringBinding
)
);
// Set the binding handle that will be used to bind to the server.
CheckRpcStatus("RpcBindingFromStringBinding",
RpcBindingFromStringBinding(
(unsigned char *) pszStringBinding,
&home_BindingHandle
)
);
CheckRpcStatus("RpcStringFree",
RpcStringFree((unsigned char * *) &pszStringBinding)
);
//
}
void
DestroyBinding(
void
)
{
CheckRpcStatus("RpcBindingFree",
RpcBindingFree(&home_BindingHandle));
}