/*++ Copyright (c) 1991-92 Microsoft Corporation Module Name: msginit.c Abstract: Messenger Service Initialization Routines. The following is a list of functions in this file: MsgInitializeMsgr BufferInit InitSharedData SetComputerName GetNumNets MsgGetBufSize SetUpMessageFile Author: Dan Lafferty (danl) 18-Jul-1991 Environment: User Mode - Win32 Notes: optional-notes Revision History: 27-Jun-1995 AnirudhS LocalFree(dataPtr) must be called AFTER MsgFreeSupportSeg, because the latter tries to _close a handle stored in dataPtr. 08-Feb-1994 Danl Removed the restriction that the memory allocated had to be restricted to less than a 64K segment. We don't worry about segments anymore. 12-Jan-1993 Danl In error paths where we call MsgCloseWakeupSems, I need to do the LocalFree(dataPtr) after the call to MsgCloseWakeupSems. Otherwise, it access violates because MsgCloseWakeupSems uses the shared date in the block pointed to by the dataPtr. 21-Apr-1992 JohnRo Fixed bug printing a status when message name add fails. Changed to use FORMAT_ equates throughout. 18-Feb-1992 ritaw Convert to Win32 service control APIs. 18-Jul-1991 danl Created as a composite of the original LM2,0 routines. --*/ // // Includes // #include // atol #include "msrv.h" // Messenger prototypes and constants #include // Service control APIs #include // NetpAssert, FORMAT_ equates. #include // DataTypes and runtime APIs #include // generated by the MIDL complier #include // NetpNtStatusToApiStatus prototypes #include // NetpStartRpcServer #include // Unicode string macros #include // memcpy #include // NetWrkstaTransportEnum #include // NetApiBufferFree #include // UNUSED macro #include // NetpNetBiosReset #include "msgdbg.h" // MSG_LOG #include "heap.h" // heap management routines and macros. #include "msgdata.h" // Global data #include "msgsec.h" // Messenger security information #include "msgnames.h" // MSGR_INTERFACE_NAME #include "msgtext.h" // MTXT_MsgsvcTitle // // Defines // // The following is the size of the first offset area in the shared buffer. // The size of this area is dependent on a runtime variable - the number // of nets. The BOOKKEEPING_SIZE is calculated from the SD offsets // described in msrv.h. // #define BOOKKEEPING_SIZE(n) (SDNAMEFLAGS + \ (n * NCBMAX) + \ (n * NCBMAX) + \ (n * NCBMAX * (NCBNAMSZ+4)) + \ (n * NCBMAX * (NCBNAMSZ+4)) + \ (n * NCBMAX * sizeof(DWORD))) #define MAXSEG (0xffff) #define LMI_PARM_M_SIZMESSBUF TEXT("/sizmessbuf") // // Global Data // static DWORD bufferSize; // Message buffer size static DWORD msrv_pid; // pid of message server extern LPTSTR MessageFileName; // // Local Function Prototypes // STATIC VOID MsgBufferInit( IN USHORT buflen ); NET_API_STATUS MsgInitSharedData( DWORD NumNets ); STATIC BOOL MsgSetComputerName( DWORD NumNets ); STATIC DWORD MsgGetNumNets(VOID); NET_API_STATUS MsgGetBufSize ( IN DWORD argc, IN LPTSTR *argv, OUT LPDWORD bufferSize, OUT LPTSTR *lastarg ); DWORD MsgSetUpMessageFile(VOID); STATIC VOID MsgInitMessageBoxTitle( VOID ); NET_API_STATUS MsgInitializeMsgr( DWORD argc, LPTSTR *argv ) /*++ Routine Description: Registers the control handler with the dispatcher thread. Then it performs all initialization including the starting of the RPC server. If any of the initialization fails, MsgStatusUpdate is called so that the status is updated and the thread is terminated. Arguments: Return Value: --*/ { NET_API_STATUS status; LPTSTR lastarg; DWORD NumNets; DWORD hint_count = 0; DWORD msgrState; DWORD bufLen; // // Initialize the Time format. Since no users are logged on, we use // the information for the default user. // InitializeCriticalSection(&TimeFormatCritSec); NetpGetTimeFormat(&GlobalTimeFormat); // // Initialize the Thread Manager. This initializes some locks used // on the Thread and Status databases. // MsgThreadManagerInit(); // // Initialize the status structure // MsgStatusInit(); // // Register this service with the ControlHandler. // Now we can accept control requests and be requested to UNINSTALL. // MSG_LOG(TRACE, "Calling NetServiceRegisterCtrlHandler\n",0); if ((MsgrStatusHandle = RegisterServiceCtrlHandler( SERVICE_MESSENGER, MsgrCtrlHandler )) == (SERVICE_STATUS_HANDLE) NULL) { status = GetLastError(); MSG_LOG(ERROR, "FAILURE: RegisterServiceCtrlHandler status = " FORMAT_API_STATUS "\n", status); return( MsgBeginForcedShutdown ( IMMEDIATE, status)); } // // Notify that installation is pending // msgrState = MsgStatusUpdate(STARTING); if (msgrState != STARTING) { // // An UNINSTALL control request must have been received // return(msgrState); } // // Check that the workstation is started // MSG_LOG(TRACE, "Calling NetServiceControl\n",0); if (! NetpIsServiceStarted(SERVICE_WORKSTATION)) { MSG_LOG(ERROR, "WorkStation Service is not started\n",0); return (MsgBeginForcedShutdown( IMMEDIATE, NERR_WkstaNotStarted)); } // *** INSTALLATION HINT *** msgrState = MsgStatusUpdate(STARTING); if (msgrState != STARTING) { return(msgrState); } // // Check command line for buffer size. If none given, // use the default buffer size. // lastarg is a pointer to the argument string that was found // to be bad. // status = MsgGetBufSize ( argc, argv, &bufferSize, &lastarg ); if (status != NERR_Success) { MSG_LOG(ERROR, "MsgGetBufSize Failed\n",0); return (MsgBeginForcedShutdown( IMMEDIATE, status)); } // *** INSTALLATION HINT *** msgrState = MsgStatusUpdate(STARTING); if (msgrState != STARTING) { return(msgrState); } if (bufferSize > MAX_SIZMESSBUF || bufferSize < MIN_SIZMESSBUF) { MSG_LOG(ERROR, "Message Buffer Size is illegal\n",0); return (MsgBeginForcedShutdown( IMMEDIATE, ERROR_INVALID_PARAMETER)); } // // This is the size of the buffer (that SDBUFFER points to) in the // shared data area. This is calculated as: // // The size of a message buffer (bufferSize) // plus // space for 4 Multi-block message headers and names, // plus // space for one Multi-block text header for each text block that // fits into the message buffer. (bufferSize/TXTMAX). // // The number of headers is rounded up by one. // (bufferSize+TXTMAX-1)/TXTMAX // bufferSize += (4 * (sizeof(MBB) + (2 * NCBNAMSZ))) + ((( (bufferSize+TXTMAX-1)/TXTMAX) + 1) * sizeof(MBT)); MSG_LOG(TRACE, "Calling MsgGetNumNets\n",0); NumNets = MsgGetNumNets(); if ( NumNets == 0 ) { MSG_LOG(ERROR, "No nets to connect to\n",0); return (MsgBeginForcedShutdown( IMMEDIATE, NERR_NoNetworkResource)); } // ***** INSTALLATION HINT ***** msgrState = MsgStatusUpdate(STARTING); if (msgrState != STARTING) { return(msgrState); } // // Initialize shared memory areas. // MSG_LOG(TRACE, "Calling MsgInitSharedData\n",0); status = MsgInitSharedData(NumNets); if (status != NERR_Success) { MSG_LOG(ERROR, "InitSharedData Failure\n",0); return (MsgBeginForcedShutdown( IMMEDIATE, NERR_NoRoom)); } // ***** INSTALLATION HINT ***** msgrState = MsgStatusUpdate(STARTING); if (msgrState != STARTING) { return(msgrState); } //***************************************** // // STUFF FROM Init_msrv() in MSRV.C // //***************************************** heap = SD_BUFFER(); // Initialize data heap pointer heapln = SD_BUFLEN(); // Initialize data heap length // // Set up the segement to hold the net bios handles, lana-nums // and wakeup Semaphores. // MSG_LOG(TRACE, "Calling MsgInitSupportSeg\n",0); if ( MsgInitSupportSeg() ) { LocalFree (dataPtr); // Free shared data MSG_LOG(ERROR, "InitSupportSeg Failed\n",0); return (MsgBeginForcedShutdown( IMMEDIATE, NERR_NoRoom)); } // // Now initialize global net bios handles & lana nums. // MSG_LOG(TRACE, "Calling MsgInit_NetBios\n",0); if (!MsgInit_NetBios()) { MsgFreeSupportSeg(); LocalFree (dataPtr); // Free shared data MSG_LOG(ERROR, "Init_NetBios Failed\n",0); return (MsgBeginForcedShutdown( IMMEDIATE, ERROR_OPEN_FAILED)); } // // Get the wake up semaphore handles. // MSG_LOG(TRACE, "Calling MsgCreateWakeupSems\n",0); if (!MsgCreateWakeupSems(SD_NUMNETS())) { MsgCloseWakeupSems(); // Close the ones that have been created MsgFreeSupportSeg(); LocalFree (dataPtr); // Free shared data MSG_LOG(ERROR, "CreateWakeupSems Failed\n",0); return (MsgBeginForcedShutdown( IMMEDIATE, NERR_NoRoom)); } // // Ask the Worksta for the computer name. If the computer // has no name, then abort. // // The computername and the username are in unicode format. // // NOTE: the username that is returned is a name we may want to add // to the table. // MSG_LOG(TRACE, "Getting the ComputerName\n",0); bufLen = sizeof(machineName); *machineName = TEXT('\0'); if (!GetComputerName(machineName,&bufLen)) { MSG_LOG(ERROR,"GetComputerName failed \n",0); status = GetLastError(); } if ( (status != NERR_Success) || (*machineName == TEXT('\0')) || (*machineName == TEXT(' '))) { // // fatal error if no name // MsgCloseWakeupSems(); MsgFreeSupportSeg(); LocalFree (dataPtr); // Free shared data MSG_LOG(ERROR, "GetWkstaNames Failed\n",0); return (MsgBeginForcedShutdown( IMMEDIATE, NERR_NoComputerName)); } machineName[NCBNAMSZ] = TEXT('\0'); // make sure it's terminated MachineNameLen = (SHORT) STRLEN(machineName); // // Open NETBIOS for use by messenger. // If any failures occur beyond this we must remember to close. // MsgsvcGlobalData->NetBiosOpen(); // // Set computer name on adapters - if any // MSG_LOG(TRACE, "Calling MsgSetComputerName\n",0); if(MsgSetComputerName(SD_NUMNETS()) != 0) { MsgCloseWakeupSems(); MsgFreeSupportSeg(); LocalFree (dataPtr); // Free shared data MSG_LOG(ERROR, "SetComputerName Failed\n",0); return (MsgBeginForcedShutdown( IMMEDIATE, NERR_NoComputerName)); } // // Change from IMMEDIATE Shutdowns to PENDING shutdowns. // This is because at this point we have names on the adapters // to clean up. // // // The NCBs and NCB buffers belong in a seperate segment so // DosAlloc the segment here. // MSG_LOG(TRACE, "Calling MsgInitNCBSeg\n",0); if( MsgInitNCBSeg() ) { MSG_LOG(ERROR, "InitNCBSeg Failed\n",0); return (MsgBeginForcedShutdown( PENDING, NERR_NoRoom)); } // // Allocate the the Service segment. // MSG_LOG(TRACE, "Calling MsgInitServiceSeg\n",0); if ( MsgInitServiceSeg() ) { MSG_LOG(ERROR, "InitServiceSeg Failed\n",0); return (MsgBeginForcedShutdown( PENDING, NERR_NoRoom)); } // // Build the name of the file that is to be used to get the // message header and tail. Don't care about errors, since // any error will result in the file not being used and is // resorting to the old standby strings. // MSG_LOG(TRACE, "Calling MsgSetUpMessageFile\n",0); MsgSetUpMessageFile(); // // Start the Group messenger thread to handle all domain messaging // SD_NUMNETS() is the position in the wakeupSem array for the // mailslot event. // MSG_LOG(TRACE, "Calling MsgInitGroupSupport\n",0); if ( status = MsgInitGroupSupport( SD_NUMNETS() ) ) { MSG_LOG(ERROR, "InitGroupSupport Failed\n",0); return (MsgBeginForcedShutdown( PENDING, NERR_GrpMsgProcessor)); } // // Initialize the Display Code // if (!MsgDisplayInit()) { MSG_LOG(ERROR, "Could not initialize the display functions\n",0); return (MsgBeginForcedShutdown( PENDING, NERR_NoRoom)); // BUGBUG: Make this meaningful! } // // Create the security descriptor that is to be used in access // checks on the API interface. // MSG_LOG(TRACE, "Calling MsgCreateMessageNameObject\n",0); status = MsgCreateMessageNameObject(); if (status != NERR_Success) { MSG_LOG(ERROR, "MsgCreateMessageNameObject (security descriptor) " "Failed\n", 0); return (MsgBeginForcedShutdown( PENDING, status)); } // // Initialize the text for the message box title. // MsgInitMessageBoxTitle(); // // Installation is successful and complete. If there is a // user logged on then an attempt is made to add the user name // to this message server. No attempt is made at error reporting // if this fails, there may not be a user logged on, and if there is, // the user name may already exist as a message name on another // station. // // This is when we add usernames to the message table if we can. // Sometime this needs to handle multiple users??? (not in version 1) // MsgAddUserNames(); // // Start the Messengers RPC server. // // NOTE: Now all RPC servers in services.exe share the same pipe name. // However, in order to support communication with version 1.0 of WinNt, // it is necessary for the Client Pipe name to remain the same as // it was in version 1.0. Mapping to the new name is performed in // the Named Pipe File System code. // MSG_LOG(TRACE, "MsgInitializeMsgr:Getting ready to start RPC server\n",0); status = MsgsvcGlobalData->StartRpcServer( MsgsvcGlobalData->SvcsRpcPipeName, msgsvc_ServerIfHandle); if (status != RPC_S_OK) { MSG_LOG(ERROR, "RPC Initialization Failed " FORMAT_RPC_STATUS "\n", status); return (MsgBeginForcedShutdown( PENDING, status)); } // // Update the status to indicate that installation is complete. // Get the current state back in case the ControlHandling thread has // told us to shutdown. // MSG_LOG(TRACE, "Exiting MsgInitializeMsgr - Init Done!\n",0); return (MsgStatusUpdate(RUNNING)); } STATIC VOID MsgBufferInit( IN USHORT buflen // Buffer length ) /*++ Routine Description: This function is called during initialization to set up the message buffer in the shared data area. This function assumes that the shared data area is locked in memory, that the access semaphore for the shared data area is set, and that the global far pointer, dataPtr, is valid. BufferInit() initializes the heap structure of the buffer. SIDE EFFECTS The buffer in shared memory is initialized. Arguments: buflen - buffer length Return Value: none --*/ { LPHEAPHDR hp; // Heap block pointer hp = (LPHEAPHDR) SD_BUFFER(); // Get the address of buffer HP_SIZE(*hp) = buflen; // Set the size of the first block HP_FLAG(*hp) = 0; // Unallocated SD_BUFLEN() = buflen; // Save the length of the buffer } DWORD MsgInitSharedData( DWORD NumNets ) /*++ Routine Description: This function creates and initializes the shared data area. It sets up the computer name and initializes the message buffer. SIDE EFFECTS Calls MsgBufferInit(). Arguments: NumNets - Number of network adapters to support. Return Value: RETURN NERR_Success if the operation was successful ERROR_NOT_ENOUGH_MEMORY - If the memory alloc for the shared memory segment fails. --*/ { DWORD i,j; // Index ULONG size; // // Create and initialize shared data area. // size = bufferSize + BOOKKEEPING_SIZE(NumNets); dataPtr = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, size); if (dataPtr == NULL) { MSG_LOG(ERROR,"[MSG]InitSharedData:LocalAlloc Failure " FORMAT_API_STATUS "\n", GetLastError()); return(ERROR_NOT_ENOUGH_MEMORY); } // // Initialize the shared data lock. The shared data is shared between // the API threads and the worker threads. // MsgDatabaseLock(MSG_INITIALIZE,"InitSharedData"); // // Initialize the "used-to-be shared" data // SD_NUMNETS() = NumNets; SD_MSRV() = 0; // No message server active SD_LOGNAM()[0] = '\0'; // No log file yet SD_MESLOG() = 0; // Message logging disabled SD_MESQF() = INULL; // Message queue is empty SD_MESQB() = INULL; for ( j = 0; j < SD_NUMNETS(); j++ ) { for(i = 0; i < NCBMAX; ++i) { // // Mark entries as free // SD_NAMEFLAGS(j,i) = NFDEL; } } // // Initialize the message buffer // MsgBufferInit((USHORT)bufferSize); // // NT NOTE: // Skip Initializing the Support Set and Wakeup sems. // Init_msrv will end up doing that. // return(NERR_Success); } STATIC BOOL MsgSetComputerName( IN DWORD NumNets ) /*++ Routine Description: This function sets up the shared data area for the computer name so that it can receive messages. This function sets things up so that the computer name will be able to receive messages. First, it adds the user name form of the computer name to the local adapter. If successful, it then initializes one slot in the name table in the shared data area: a computer name receiving messages SIDE EFFECTS Locks the init data segment around net bios usage. Calls the net bios. Makes entries in the shared data area. Arguments: NumNets - The number of network adapters that is supported Return Value: 0 = success non-zero = failure --*/ { NET_API_STATUS status; NCB ncb; /* Network Control Block */ // ASTAT adapterStatus; /* Adapter status buffer */ UCHAR res; DWORD i; unsigned short j; struct { ADAPTER_STATUS AdapterStatus; NAME_BUFFER NameBuffer[16]; } Astat; // // Loop for each net. // for ( i = 0; i < NumNets; i++ ) { // NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW // // Reset the adapter // MSG_LOG1(TRACE,"Calling NetBiosReset for lana #%d\n",net_lana_num[i]); status = MsgsvcGlobalData->NetBiosReset(net_lana_num[i]); if (status != NERR_Success) { MSG_LOG(ERROR,"MsgSetComputerName: NetBiosReset failed " FORMAT_API_STATUS "\n", status); MSG_LOG(ERROR,"MsgSetComputerName: AdapterNum " FORMAT_DWORD "\n",i); // // If it fails, skip to the Next Net. // continue; } // // // NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW // // Set call name for local adapter // clearncb(&ncb); status = MsgFmtNcbName( ncb.ncb_name, machineName, 3); if (status != NERR_Success) { MSG_LOG(ERROR,"SetComputerName: Format name failed!",0); return ((BOOL)1); } ncb.ncb_command = NCBADDNAME; // Add name (wait) ncb.ncb_lana_num = net_lana_num[i]; // Use the LANMAN adapter // // Copy the name // (At this point the name is ansi - not unicode) // memcpy(SD_NAMES(i,0), ncb.ncb_name, NCBNAMSZ); MSG_LOG1(TRACE,"MsgSetComputerName: Adding ComputerName to lana #%d\n", net_lana_num[i]); if( (res = Msgsendncb( &ncb, i)) != 0) { MSG_LOG1(TRACE,"SetComputerName: NetBios ADDNAME failed 0x%x\n",res); if( (res & 0xff) == NRC_DUPNAME) { // // If the name already exists on the adapter card (the // workstation may have added it), we want to get the // name number and pretend that we just added it. // // Name already exists. Issue an ASTAT to find the name // number. // clearncb(&ncb); ncb.ncb_buffer = (char FAR *) &Astat; // Set buffer address ncb.ncb_length = sizeof(Astat); // Set buffer length ncb.ncb_callname[0] = '*'; // local adapter status ncb.ncb_command = NCBASTAT; // Adapter status (wait) res = Msgsendncb(&ncb,i); if( res != NRC_GOODRET) { // // Failed to add name // //Close_NetBios(); MSG_LOG1(ERROR, "SetComputerName:sendncb (ASTAT) failed 0x%x\n",res); return((BOOL)1); } // // Loop to name number // for(j = 0; j< Astat.AdapterStatus.name_count; ++j) { if(((Astat.NameBuffer[j].name_flags & 7) == 4) && (memcmp( Astat.NameBuffer[j].name, SD_NAMES(i,0), NCBNAMSZ) == 0)) { break; // Found the name } } if( j == Astat.AdapterStatus.name_count) { // // Failed to find // //Close_NetBios(); MSG_LOG(ERROR, "SetComputerName:DupName-failed to find NameNum\n",0); return((BOOL)1); } SD_NAMENUMS(i,0) = Astat.NameBuffer[j].name_num; // Save num MSG_LOG1(TRACE,"SetComputerName: use existing name num (%d) instead\n", Astat.NameBuffer[j].name_num); } else { // // Fail if name not on the card after the call // // Close_NetBios(); MSG_LOG(ERROR, "SetComputerName:Name Not on Card. netbios rc = 0x%x\n",res); return((BOOL)1); } } else { SD_NAMENUMS(i,0) = ncb.ncb_num; // Save the name number } SD_NAMEFLAGS(i,0) = NFNEW | NFMACHNAME; // Name is new } // End for all nets // Close_NetBios(); return((BOOL)0); /* Success */ } STATIC DWORD MsgGetNumNets(VOID) /*++ Routine Description: Arguments: Return Value: --*/ { NCB ncb; LANA_ENUM lanaBuffer; unsigned char nbStatus; // // Find the number of networks by sending an enum request via Netbios. // clearncb(&ncb); ncb.ncb_command = NCBENUM; // Enumerate LANA nums (wait) ncb.ncb_buffer = (char FAR *)&lanaBuffer; ncb.ncb_length = sizeof(LANA_ENUM); nbStatus = Netbios (&ncb); if (nbStatus != NRC_GOODRET) { MSG_LOG(ERROR, "GetNumNets:Netbios LanaEnum failed rc=" FORMAT_DWORD "\n", (DWORD) nbStatus); return(FALSE); } return((DWORD)lanaBuffer.length); #ifdef replaced LPBYTE transportInfo; int count=0; USHORT loopback_found = 0; NET_API_STATUS status; DWORD entriesRead; DWORD totalEntries; // // First try and find the networks mananged by the LAN manager // // NOTE: This call will fail if there are more than MSNGR_MAX_NETS // in the machine. This is not a problem unless there are fewer // than MSNGR_MAX_NETS that would qualify for messaging service. // In this case, it might be argued that the messenger should start. // For now, this is not the case. - ERICPE // status = NetWkstaTransportEnum ( NULL, // server name (local) 0, // level &transportInfo, // bufptr -1, // preferred maximum length &entriesRead, // entries read &totalEntries, // total entries NULL); // resumeHandle // // Free up the buffer that RPC allocated for us. // NetApiBufferFree(transportInfo); if (status != NERR_Success) { MSG_LOG(ERROR,"GetNumNets:NetWkstaTransportEnum failed " FORMAT_API_STATUS "\n", status); return(0); } MSG_LOG(TRACE,"GetNumNets: numnets = " FORMAT_DWORD "\n", totalEntries); return(totalEntries); #endif } NET_API_STATUS MsgGetBufSize ( IN DWORD argc, IN LPTSTR *argv, OUT LPDWORD bufferSize, OUT LPTSTR *lastarg ) /*++ Routine Description: This routine parses through the command line arguments in search of the buffer size. This is the only valid argument and is of the following form: /sizmessbuf:[bytes] Where bytes is the number of bytes for the message buffer defining the size of messages the messenger can receive. The range is 512-62000. The default is 4096. If a passed in sizmessbuf is an illegal value, an error will be returned. Arguments that are not switches (prefixed by "/") are ignored. Invalid switches cause a failure, and the text of the bad switch is passed back in lastarg. Arguments: argc - This is the count of the number of arguments that is passed in. argv - This is a pointer to an array of pointers to arguments. bufferSize - This is a pointer to where the buffer size is to be stored. If a bufferSize was not found on the command line, the default is placed in here. lastarg - This is a pointer to a location where a pointer to a switch argument that was in error is to be placed. Return Value: NERR_Success - No errors, the returned bufferSize is valid and lastarg does not contain any error information. ERROR_INVALID_PARAMETER - The command line switch is not a valid one for this service. --*/ { DWORD switchNameSize; BOOL fromCmdLine = FALSE; DWORD i; LPTSTR pSizeString; // // Check the passed in command args. // *lastarg = NULL; *bufferSize = 0; for (i=0; i 62000)) { MSG_LOG(ERROR,"MsgGetBufSize:BufferSize out of range\n",0); return( ERROR_INVALID_PARAMETER); } return (NERR_Success); } DWORD MsgSetUpMessageFile ( VOID ) /*++ Routine Description: Builds the name of the message file that is to be used in any subsequent DosGetMessage calls. The name is built in the Global variable MessageFileName, and is constructed using the following template. lanroot\netprog\net.msg Arguments: none Return Value: NERR_Success - The operation was successful ERROR_NOT_ENOUGH_MEMORY - Couldn't allocate memory for MessageFileName. --*/ { // // allocate some space for the message file name to be built. // MessageFileName = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, (MSGFILENAMLEN+sizeof(TCHAR))); if (MessageFileName == NULL) { MSG_LOG(ERROR,"[MSG]SetUpMessageFile:LocalAlloc Failure " FORMAT_API_STATUS "\n", GetLastError()); return(ERROR_NOT_ENOUGH_MEMORY); } // // BUGBUG: The following function finds the LAN root directory and // builds a filename with that. What will we do in NT? // #ifdef later result = NetIMakeLMFileName ( MESSAGE_FILE, MessageFileName, PATHLEN+1); if ( result ) { MessageFileName[0] = '\0'; } #endif // // Temporary fix. Use a fixed filename and use the temporary // DosGetMessage (until we get a win32 equivalent). // This message filename is defined in lmcons.h // STRCPY(MessageFileName,MESSAGE_FILENAME); return (NERR_Success); } STATIC VOID MsgInitMessageBoxTitle( VOID ) /*++ Routine Description: Obtains the title text for the message box used to display messages. If the title is successfully obtained from the message file, then that title is pointed to by GlobalAllocatedMsgTitle and GlobalMessageBoxTitle. If unsuccessful, then GlobalMessageBoxTitle left pointing to the DefaultMessageBoxTitle. NOTE: If successful, a buffer is allocated by this function. The pointer stored in GlobalAllocatedMsgTitle and it should be freed when done with this buffer. Arguments: Return Value: none --*/ { LPVOID hModule; DWORD msgSize; DWORD status=NO_ERROR; GlobalAllocatedMsgTitle = NULL; hModule = LoadLibrary( L"netmsg.dll"); if ( hModule == NULL) { status = GetLastError(); MSG_LOG1(ERROR, "LoadLibrary() fails with winError = %d\n", GetLastError()); return; } msgSize = FormatMessageW( FORMAT_MESSAGE_FROM_HMODULE | // dwFlags FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_ALLOCATE_BUFFER, hModule, MTXT_MsgsvcTitle, // MessageId 0, // dwLanguageId (LPWSTR)&GlobalAllocatedMsgTitle, // lpBuffer 0, // nSize NULL); if (msgSize == 0) { status = GetLastError(); MSG_LOG1(ERROR,"Could not find MessageBox title in a message file %d\n", status); } else { GlobalMessageBoxTitle = GlobalAllocatedMsgTitle; } FreeLibrary(hModule); return; }