How to create a Serv-U extension DLL in MSVC

Step 1: Create a new project

File - New - Win32 Dynamic-Link Library

A simple DLL project

Step 2: Create a header file for this and future ServU projects

File - New - C/C++ Header File with a filename of ServUDLL.h

Here is the body of ServUDLL.h

	// Serv-U event definitions
	// a copy of the list found in the Serv-U manual
	#define EVNT_None	    	0		// none
	#define EVNT_IPName	    1		// symbolic IP name available
	#define EVNT_Connect	    2		// connection was made
	#define EVNT_Close	    	3		// closed connection
	#define EVNT_BouncedIP	    4		// bounced client because of IP address
	#define EVNT_TooMany	    5		// bounced user because there are too many
	#define EVNT_WrongPass	    6		// too many times wrong password
	#define EVNT_TimeOut	    7		// connection timed out
	#define EVNT_Login	    	8		// use logged in
	#define EVNT_StartUp	    9		// start upload of file
	#define EVNT_EndUp	   	10		// successfull upload of file
	#define EVNT_StartDown	   11           // start of download of file
	#define EVNT_EndDown	   12           // successfull download of file
	#define EVNT_AbortUp	   13		// aborted upload
	#define EVNT_AbortDown	   14		// aborted download
	#define EVNT_Rename	   15		// renamed file/dir
	#define EVNT_DelFile	   16		// deleted file
	#define EVNT_DelDir 	   17		// deleted dir
	#define EVNT_ChgDir	   18		// changed working directory
	#define EVNT_MakeDir	   19		// created directory
	
	// Serv-U event hook definitions
	#define EVNT_HookDown	  100		// hook for file downloads
	#define EVNT_HookUp	  101		// hook for file uploads
	#define EVNT_HookAppend	  102		// hook for append file upload
	#define EVNT_HookUnique	  103		// hook for unique name upload
	#define EVNT_HookRename	  104		// hook for rename file/dir
	#define EVNT_HookDelFile  105		// hook for delete file
	#define EVNT_HookDelDir	  106		// hook for delete dir
	#define EVNT_HookMkd	  107		// hook for make directory
	#define EVNT_HookRmd	  108		// hook for remove directory
	
	// Serv-U sub-event codes
	#define SEVNT_None		0		// no sub-event
	#define SEVNT_ErrWrite		1		// problem writing to disk
	#define SEVNT_ErrRead		2		// problem reading from disk
	#define SEVNT_ErrQuota		3		// insufficient disk quota
	#define SEVNT_ErrTOut		4		// packet timed out
	#define SEVNT_ErrAbort		5		// user aborted transfer
	#define SEVNT_ErrUnknown	6		// unknown error
	#define SEVNT_ErrClose		7		// data connection closed unexpectedly
	
	// return codes for hooks
	#define REVNT_None	    0		// nothing
	#define REVNT_Proceed	    1		// let event pass
	#define REVNT_Abort	    2		// stop event
	#define REVNT_Suspend	    3		// suspend event until decision is made
	
	// event information structure for communications with DLL's
	struct RFTPEventStr {
		// event info
		DWORD Event;			// event type
		DWORD SubEvent;			// sub-event type
		// user info
		DWORD SessionID;		// unique ID of the FTP session
		char User[40];			// user name
		char ClientIP[16];		// IP number of client
		char LocalIP[16];		// IP number the client connected to
		// event attributes
		DWORD Duration;			// duration of events
		DWORD Size;			// size of object (ie. file)
		// hook info
		HWND hWindow;			// window handle to post decision to
		UINT Message;			// message to post
		char* pReplyText;		// pointer to text to send to user
		// scratch pad area
		char AuxOne[512];		// auxiliary area one
		char AuxTwo[512];		// auxiliary area two
	};
	#define SRVU_LoginMesFile	1	// get login message file
	#define SRVU_HomeDir		2	// get home dir
	#define SRVU_Password		3	// verify password
	#define SRVU_IPAccess		4	// verify IP access
	#define SRVU_WriteFile		5	// verify write access
	#define SRVU_ReadFile		6	// verify read access
	#define SRVU_ModifyFile		7	// verify mod./del. file access
	#define SRVU_ExecProg		8	// verify execute access
	#define SRVU_ListDir		9	// verify dir listing access
	#define SRVU_ChangeDir		10	// verify dir change access
	#define SRVU_DeleteDir		11	// verify dir delete access
	#define SRVU_CreateDir		12	// verify dir create access
	#define SRVU_HideHidden		13	// get setting for 'hide hidden files'
	#define SRVU_RelPaths		14	// get setting for 'relative paths'
	#define SRVU_RatioType		15	// get setting for type of ratios
	#define SRVU_RatioDown		16	// get setting for download ratio
	#define SRVU_RatioUp   		17	// get setting for upload ratio
	#define SRVU_RatioCredit	18	// get/adjust ratio credit setting
	#define SRVU_RatioFree		19	// verify if file is free for ratios
	#define SRVU_QuotaEnable	20	// verify if disk quota is enabled
	#define SRVU_QuotaChange	21	// change in disk quota
	#define SRVU_QuotaMax		22	// maximum disk quota
	#define SRVU_AlwaysLogin	23	// always allow login
	#define SRVU_OneLoginPerIP	24	// allow one login per user/IP pair
	#define SRVU_LogClientIP	25	// log client from this IP address
	#define SRVU_SpeedLimit		26	// maximum transfer speed
	#define SRVU_PassChange		27	// change user's password
	#define SRVU_TimeOut		28	// get user time-out value
	#define SRVU_MaxUsers		29	// max. no. of users for account
	#define SRVU_PassChallenge	30	// get password challenge if needed
	#define SRVU_Connect		31	// information only: client connected
	#define SRVU_Close		32	// information only: client disconnected
	#define SRVU_MaxLoginPerIP	33	// max. no. of logins from same IP for user
	#define SRVU_VerifyPasswd	34	// verify old password before changing it
	#define SRVU_AppendFile		35	// verify append file access
	#define SRVU_SignOnMes		36	// get signon message file
	#define SRVU_SignOffMes		37	// get signoff message file
	#define SRVU_Maintenance	39	// switch to maintenance mode
	struct RClientEventStr {
		int Event;			// event code
		int Flag;			// flag, meaning depends on event
		char User[40];			// user name
		char Aux[512];			// auxiliary area, usage depends on event
		char HostIP[16];		// server IP home
		unsigned long SessionID;	// unique session ID
	};
	// If not using MFC
	// exported functions declaration header
	#define EXPORT  extern "C" __declspec (dllexport)               
	// End If not using MFC
	// function definitions
	EXPORT WORD CALLBACK HandleEventHook(RFTPEventStr* pEventStruc);
	EXPORT int HandleClientEvent(RClientEventStr* pEventStruc);

 

Step 3: Create a .DEF file [ProjectName].def

File - New - Text File [ProjectName].def

Here is the body of [ProjectName].def

	; [ProjectName].def : Declares the module parameters for the DLL.
	LIBRARY      "[ProjectName]"
	DESCRIPTION  '[ProjectName] Windows Dynamic Link Library'
	
	EXPORTS
		HandleEventHook @1
		HandleClientEvent @2

Step 4: Add to [ProjectName].cpp

	#include "ServUDLL.h"

and

	WORD CALLBACK HandleEventHook(RFTPEventStr* pEventStruc)
	{
		WORD Ret=REVNT_Proceed;    // return value, default is to allow operation
		char* pName=NULL;          // pointer to path/file name being uploaded/renamed
	
		// disect event
		switch (pEventStruc->Event) 
		{
	//		case EVNT_HookDown:	// hook for file downloads
	//		case EVNT_HookUp:	// hook for file uploads
	//		case EVNT_HookAppend:	// hook for append file upload
	//		case EVNT_HookUnique:	// hook for unique name upload
	//		case EVNT_HookRename:	// hook for rename file/dir
	//		case EVNT_HookDelFile:	// hook for delete file
	//		case EVNT_HookDelDir:	// hook for delete dir
	//		case EVNT_HookMkd:	// hook for make directory
	//		case EVNT_HookRmd:	// hook for remove directory
			case EVNT_StartUp:	// start upload of file
				::MessageBox(NULL, pEventStruc->AuxOne, "Start Upload", MB_OK);
				break;
			case EVNT_AbortUp:	// aborted upload
				::MessageBox(NULL, pEventStruc->AuxOne, "Abort Upload", MB_OK);
				break;
			case EVNT_EndUp:	// successful upload of file
				::MessageBox(NULL, pEventStruc->AuxOne, "End Upload", MB_OK);
				break;
			case EVNT_StartDown:	// start of download of file
				::MessageBox(NULL, pEventStruc->AuxOne, "Start Download", MB_OK);
				break;
			case EVNT_AbortDown:	// aborted download
				::MessageBox(NULL, pEventStruc->AuxOne, "Abort Download", MB_OK);
				break;
			case EVNT_EndDown:	// successful download of file
				::MessageBox(NULL, pEventStruc->AuxOne, "End Download", MB_OK);
				break;
		}
		return(Ret);
	}
and
	int HandleClientEvent(RClientEventStr* pEventStruc)
	{
		int Ret = 0;		// 0 not handled - 1 handled
		// disect event
		switch (pEventStruc->Event) 
		{
//			case SRVU_LoginMesFile:	// get login message file
//			case SRVU_HomeDir:	// get home dir
//			case SRVU_Password:	// verify password
//			case SRVU_IPAccess:	// verify IP access
//			case SRVU_WriteFile:	// verify write access
//			case SRVU_ReadFile:	// verify read access
//			case SRVU_ModifyFile:	// verify mod./del. file access
//			case SRVU_ExecProg:	// verify execute access
//			case SRVU_ListDir:	// verify dir listing access
//			case SRVU_ChangeDir:	// verify dir change access
//			case SRVU_DeleteDir:	// verify dir delete access
//			case SRVU_CreateDir:	// verify dir create access
//			case SRVU_HideHidden:	// get setting for 'hide hidden files'
//			case SRVU_RelPaths:	// get setting for 'relative paths'
//			case SRVU_RatioType:	// get setting for type of ratios
//			case SRVU_RatioDown:	// get setting for download ratio
//			case SRVU_RatioUp:	// get setting for upload ratio
//			case SRVU_RatioCredit:	// get/adjust ratio credit setting
//			case SRVU_RatioFree:	// verify if file is free for ratios
//			case SRVU_QuotaEnable:	// verify if disk quota is enabled
//			case SRVU_QuotaChange:	// change in disk quota
//			case SRVU_QuotaMax:	// maximum disk quota
//			case SRVU_AlwaysLogin:	// always allow login
//			case SRVU_OneLoginPerIP:	// allow one login per user/IP pair
//			case SRVU_LogClientIP:	// log client from this IP address
//			case SRVU_SpeedLimit:	// maximum transfer speed
//			case SRVU_PassChange:	// change user's password
//			case SRVU_TimeOut:	// get user time-out value
//			case SRVU_MaxUsers:	// max. no. of users for account
//			case SRVU_PassChallenge:	// get password challenge if needed
//			case SRVU_Connect:	// information only: client connected
//			case SRVU_Close:	// information only: client disconnected
//			case SRVU_MaxLoginPerIP:	// max. no. of logins from same IP for user
//			case SRVU_VerifyPasswd:	// verify old password before changing it
//			case SRVU_AppendFile:	// verify append file access
//			case SRVU_SignOnMes:	// get signon message file
//			case SRVU_SignOffMes:	// get signoff message file
//			case SRVU_Maintenance:	// switch to maintenance mode
		}
		return(Ret);
	}

Step 5: Change in [ProjectName].cpp

from

	BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )

to

	extern "C" int APIENTRY
	DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)

 

Step 6: Set Preprocessor Information

Project - Settings - All Configurations

Preprocessor definitions set to:

	WIN32,_WINDOWS,_WINDLL,_MBCS

Step 7: If you want to use MFC (Optional)

7A: In StdAfx.h replace

	// Insert your headers here
	#define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers
	#include <windows.h>

with

	#define VC_EXTRALEAN		// Exclude rarely-used stuff from Windows headers
	#include <afxwin.h>         // MFC core and standard components
	#include <afxext.h>         // MFC extensions
	#ifndef _AFX_NO_AFXCMN_SUPPORT
	#include <afxcmn.h>			// MFC support for Windows Common Controls
	#endif // _AFX_NO_AFXCMN_SUPPORT

 

7B: Then -- Project - Settings - General - Use MFC in a Shared DLL

7C: In ServUDLL.h comment out

	//#define EXPORT  extern "C" __declspec (dllexport) 

 Sample DLL

 Demo of PW_VAL DLL using ADO for validation

 User Specific & Long File Name Event Handler DLL