Author: ShadowFlare

I(ShadowFlare) improved command line parsing (completely rewrote it), made
some changes for the ansi version, and added some comments into the code
(there was very few previously).

svn path=/trunk/; revision=8182
This commit is contained in:
Art Yerkes 2004-02-15 05:33:19 +00:00
parent 7e4b6ff68a
commit 904bf32b2a

View file

@ -1,311 +1,467 @@
/* /*
* ReactOS rundll32 * ReactOS rundll32
* Copyright (C) 2003 ReactOS Team * Copyright (C) 2003-2004 ReactOS Team
* *
* This program is free software; you can redistribute it and/or modify * COPYRIGHT: See COPYING in the top level directory
* it under the terms of the GNU General Public License as published by * PROJECT: ReactOS rundll32.exe
* the Free Software Foundation; either version 2 of the License, or * FILE: apps/utils/rundll32/rundll32.c
* (at your option) any later version. * PURPOSE: Run a DLL as a program
* * PROGRAMMER: ShadowFlare (blakflare@hotmail.com)
* This program is distributed in the hope that it will be useful, */
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #define WIN32_LEAN_AND_MEAN
* GNU General Public License for more details.
* // Both UNICODE and _UNICODE must be either defined or undefined
* You should have received a copy of the GNU General Public License // because some headers use UNICODE and others use _UNICODE
* along with this program; if not, write to the Free Software #ifdef UNICODE
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #ifndef _UNICODE
*/ #define _UNICODE
/* #endif
* COPYRIGHT: See COPYING in the top level directory #else
* PROJECT: ReactOS rundll32.exe #ifdef _UNICODE
* FILE: apps/utils/rundll32/rundll32.c #define UNICODE
* PURPOSE: Run a DLL as a program #endif
* PROGRAMMER: ShadowFlare (blakflare@hotmail.com) #endif
*/
#include <windows.h>
#define WIN32_LEAN_AND_MEAN #include <stdio.h>
#include <string.h>
// Both UNICODE and _UNICODE must be either defined or undefined #include <malloc.h>
// because some headers use UNICODE and others use _UNICODE #include <tchar.h>
#ifdef UNICODE
#ifndef _UNICODE typedef int (WINAPI *DllWinMainW)(
#define _UNICODE HWND hWnd,
#endif HINSTANCE hInstance,
#else LPWSTR lpwCmdLine,
#ifdef _UNICODE int nCmdShow
#define UNICODE );
#endif typedef int (WINAPI *DllWinMainA)(
#endif HWND hWnd,
HINSTANCE hInstance,
#include <windows.h> LPSTR lpCmdLine,
#include <stdio.h> int nCmdShow
#include <string.h> );
#include <malloc.h>
#include <tchar.h> LPCTSTR DllNotLoaded = _T("LoadLibrary failed to load \"%s\"");
LPCTSTR MissingEntry = _T("Missing entry point:%s\nIn %s");
typedef int (WINAPI *DllWinMainW)( LPCTSTR rundll32_wtitle = _T("rundll32");
HWND hWnd, LPCTSTR rundll32_wclass = _T("rundll32_window");
HINSTANCE hInstance, TCHAR ModuleFileName[MAX_PATH+1];
LPWSTR lpwCmdLine, LPTSTR ModuleTitle;
int nCmdShow
); // CommandLineToArgv converts a command-line string to argc and
typedef int (WINAPI *DllWinMainA)( // argv similar to the ones in the standard main function.
HWND hWnd, // This is a specialized version coded specifically for rundll32
HINSTANCE hInstance, // and is not intended to be used in any other program.
LPSTR lpCmdLine, LPTSTR *WINAPI CommandLineToArgv(LPCTSTR lpCmdLine, int *lpArgc)
int nCmdShow {
); LPTSTR *argv, lpSrc, lpDest, lpArg;
int argc, nBSlash, nNames;
LPCTSTR DllNotLoaded = _T("LoadLibrary failed to load \"%s\""); BOOL bInQuotes, bFirstChar;
LPCTSTR MissingEntry = _T("Missing entry point:%s\nIn %s");
LPCTSTR rundll32_wtitle = _T("rundll32"); // If null was passed in for lpCmdLine, there are no arguments
LPCTSTR rundll32_wclass = _T("rundll32_window"); if (!lpCmdLine) {
TCHAR ModuleFileName[MAX_PATH+1]; if (lpArgc)
LPTSTR ModuleTitle; *lpArgc = 0;
return 0;
LPTSTR FindArgStart(LPTSTR lpStr) }
{
while (*lpStr) { lpSrc = (LPTSTR)lpCmdLine;
switch (*lpStr) { // Skip spaces at beginning
case _T(' '): while (*lpSrc == _T(' ') || *lpSrc == _T('\t'))
case _T('\t'): lpSrc++;
case _T('\r'):
case _T('\n'): // If command-line starts with null, there are no arguments
break; if (*lpSrc == 0) {
default: if (lpArgc)
return lpStr; *lpArgc = 0;
} return 0;
lpStr++; }
}
return lpStr; lpArg = lpSrc;
} argc = 0;
nBSlash = 0;
LPTSTR FindArgEnd(LPTSTR lpStr) bInQuotes = FALSE;
{ bFirstChar = TRUE;
if (*lpStr != _T('\"')) { nNames = 0;
while (*lpStr) {
switch (*lpStr) { // Count the number of arguments
case _T(' '): while (nNames < 4) {
case _T('\t'): if (*lpSrc == 0 || (*lpSrc == _T(',') && nNames == 2) || ((*lpSrc == _T(' ') || *lpSrc == _T('\t')) && !bInQuotes)) {
case _T('\r'): // Whitespace not enclosed in quotes signals the start of another argument
case _T('\n'): argc++;
*(lpStr++) = 0;
return lpStr; // Skip whitespace between arguments
} while (*lpSrc == _T(' ') || *lpSrc == _T('\t') || (*lpSrc == _T(',') && nNames == 2))
lpStr++; lpSrc++;
} if (*lpSrc == 0)
} break;
else { if (nNames >= 3) {
for (++lpStr;*lpStr && *lpStr != _T('\"');++lpStr) {} // Increment the count for the last argument
if (*lpStr == _T('\"')) { argc++;
*(lpStr++) = 0; break;
} }
} nBSlash = 0;
bFirstChar = TRUE;
return lpStr; continue;
} }
else if (*lpSrc == _T('\\')) {
void GetModuleTitle(void) // Count consecutive backslashes
{ nBSlash++;
LPTSTR lpStr; bFirstChar = FALSE;
}
GetModuleFileName(0,ModuleFileName,MAX_PATH); else if (*lpSrc == _T('\"') && !(nBSlash & 1)) {
ModuleTitle = ModuleFileName; // Open or close quotes
bInQuotes = !bInQuotes;
for (lpStr = ModuleFileName;*lpStr;lpStr++) { nBSlash = 0;
if (*lpStr == _T('\\')) }
ModuleTitle = lpStr+1; else {
} // Some other character
nBSlash = 0;
for (lpStr = ModuleTitle;*lpStr;lpStr++) { if (bFirstChar && ((*lpSrc != _T('/') && nNames <= 1) || nNames > 1))
if (_tcsicmp(lpStr,_T(".exe"))==0) nNames++;
break; bFirstChar = FALSE;
} }
lpSrc++;
*lpStr = 0; }
}
// Allocate space for the pointers in argv and the strings in one block
#ifdef UNICODE argv = (LPTSTR *)malloc(argc * sizeof(LPTSTR) + (_tcslen(lpArg) + 1) * sizeof(TCHAR));
#define ConvertToWideChar(lptString) (lptString)
#define FreeConvertedWideChar(lptString) if (!argv) {
#else // Memory allocation failed
if (lpArgc)
LPWSTR ConvertToWideChar(LPCSTR lpString) *lpArgc = 0;
{ return 0;
LPWSTR lpwString; }
size_t nStrLen;
lpSrc = lpArg;
nStrLen = strlen(lpString) + 1; lpDest = lpArg = (LPTSTR)(argv + argc);
argc = 0;
lpwString = (LPWSTR)malloc(nStrLen * sizeof(WCHAR)); nBSlash = 0;
MultiByteToWideChar(0,0,lpString,nStrLen,lpwString,nStrLen); bInQuotes = FALSE;
bFirstChar = TRUE;
return lpwString; nNames = 0;
}
// Fill the argument array
#define FreeConvertedWideChar(lptString) free(lptString) while (nNames < 4) {
#endif if (*lpSrc == 0 || (*lpSrc == _T(',') && nNames == 2) || ((*lpSrc == _T(' ') || *lpSrc == _T('\t')) && !bInQuotes)) {
// Whitespace not enclosed in quotes signals the start of another argument
#ifdef UNICODE // Null-terminate argument
#define ConvertToMultiByte(lptString) DuplicateToMultiByte(lptString,0) *lpDest++ = 0;
#define FreeConvertedMultiByte(lptString) free(lptString) argv[argc++] = lpArg;
#else
#define ConvertToMultiByte(lptString) (lptString) // Skip whitespace between arguments
#define FreeConvertedMultiByte(lptString) while (*lpSrc == _T(' ') || *lpSrc == _T('\t') || (*lpSrc == _T(',') && nNames == 2))
#endif lpSrc++;
if (*lpSrc == 0)
LPSTR DuplicateToMultiByte(LPCTSTR lptString, size_t nBufferSize) break;
{ lpArg = lpDest;
LPSTR lpString; if (nNames >= 3) {
size_t nStrLen; // Copy the rest of the command-line to the last argument
argv[argc++] = lpArg;
nStrLen = _tcslen(lptString) + 1; _tcscpy(lpArg,lpSrc);
if (nBufferSize == 0) nBufferSize = nStrLen; break;
}
lpString = (LPSTR)malloc(nBufferSize); nBSlash = 0;
#ifdef UNICODE bFirstChar = TRUE;
WideCharToMultiByte(0,0,lptString,nStrLen,lpString,nBufferSize,0,0); continue;
#else }
strncpy(lpString,lptString,nBufferSize); else if (*lpSrc == _T('\\')) {
#endif *lpDest++ = _T('\\');
lpSrc++;
return lpString;
} // Count consecutive backslashes
nBSlash++;
LRESULT CALLBACK EmptyWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) bFirstChar = FALSE;
{ }
return DefWindowProc(hWnd, uMsg, wParam, lParam); else if (*lpSrc == _T('\"')) {
} if (!(nBSlash & 1)) {
// If an even number of backslashes are before the quotes,
ATOM RegisterBlankClass(HINSTANCE hInstance) // the quotes don't go in the output
{ lpDest -= nBSlash / 2;
WNDCLASSEX wcex; bInQuotes = !bInQuotes;
}
wcex.cbSize = sizeof(WNDCLASSEX); else {
// If an odd number of backslashes are before the quotes,
wcex.style = 0; // output a quote
wcex.lpfnWndProc = EmptyWindowProc; lpDest -= (nBSlash + 1) / 2;
wcex.cbClsExtra = 0; *lpDest++ = _T('\"');
wcex.cbWndExtra = 0; bFirstChar = FALSE;
wcex.hInstance = hInstance; }
wcex.hIcon = 0; lpSrc++;
wcex.hCursor = 0; nBSlash = 0;
wcex.hbrBackground = 0; }
wcex.lpszMenuName = 0; else {
wcex.lpszClassName = rundll32_wclass; // Copy other characters
wcex.hIconSm = 0; if (bFirstChar && ((*lpSrc != _T('/') && nNames <= 1) || nNames > 1))
nNames++;
return RegisterClassEx(&wcex); *lpDest++ = *lpSrc++;
} nBSlash = 0;
bFirstChar = FALSE;
int WINAPI WinMain( }
HINSTANCE hInstance, }
HINSTANCE hPrevInstance,
LPSTR lpCmdLineA, if (lpArgc)
int nCmdShow *lpArgc = argc;
) return argv;
{ }
LPTSTR lptCmdLineCopy,lptCmdLine,lptDllName,lptFuncName,lptMsgBuffer;
LPSTR lpFuncName,lpaCmdLine; void GetModuleTitle(void)
LPWSTR lpwCmdLine; {
HMODULE hDll; LPTSTR lpStr;
DllWinMainW fnDllWinMainW;
DllWinMainA fnDllWinMainA; GetModuleFileName(0,ModuleFileName,MAX_PATH);
HWND hWindow; ModuleTitle = ModuleFileName;
int nRetVal;
size_t nStrLen; for (lpStr = ModuleFileName;*lpStr;lpStr++) {
if (*lpStr == _T('\\'))
lptCmdLineCopy = _tcsdup(GetCommandLine()); ModuleTitle = lpStr+1;
}
lptCmdLine = FindArgStart(lptCmdLineCopy);
lptCmdLine = FindArgEnd(lptCmdLine); for (lpStr = ModuleTitle;*lpStr;lpStr++) {
lptDllName = FindArgStart(lptCmdLine); if (_tcsicmp(lpStr,_T(".exe"))==0)
while (*lptDllName == _T('/')) break;
lptDllName = FindArgStart(FindArgEnd(++lptDllName)); }
lptCmdLine = FindArgEnd(lptDllName);
if (*lptDllName == _T('\"')) lptDllName++; *lpStr = 0;
}
if (!*lptDllName) {
free(lptCmdLineCopy); // The macro ConvertToWideChar takes a tstring parameter and returns
return 0; // a pointer to a unicode string. A conversion is performed if
} // neccessary. FreeConvertedWideChar string should be used on the
// return value of ConvertToWideChar when the string is no longer
for (lptFuncName = lptDllName;*lptFuncName && *lptFuncName != _T(',');lptFuncName++) {} // needed. The original string or the string that is returned
if (*lptFuncName == _T(',')) { // should not be modified until FreeConvertedWideChar has been called.
*(lptFuncName++) = 0; #ifdef UNICODE
} #define ConvertToWideChar(lptString) (lptString)
else { #define FreeConvertedWideChar(lpwString)
lptFuncName = FindArgStart(lptCmdLine); #else
lptCmdLine = FindArgEnd(lptFuncName);
if (*lptFuncName == _T('\"')) lptFuncName++; LPWSTR ConvertToWideChar(LPCSTR lpString)
} {
LPWSTR lpwString;
if (!*lptFuncName) { size_t nStrLen;
free(lptCmdLineCopy);
return 0; nStrLen = strlen(lpString) + 1;
}
lpwString = (LPWSTR)malloc(nStrLen * sizeof(WCHAR));
if (*lptCmdLine) lptCmdLine = FindArgStart(lptCmdLine); MultiByteToWideChar(0,0,lpString,nStrLen,lpwString,nStrLen);
nRetVal = 0; return lpwString;
}
hDll = LoadLibrary(lptDllName);
if (hDll) { #define FreeConvertedWideChar(lpwString) free(lpwString)
nStrLen = _tcslen(lptFuncName); #endif
lpFuncName = DuplicateToMultiByte(lptFuncName,nStrLen + 2);
// The macro ConvertToMultiByte takes a tstring parameter and returns
lpFuncName[nStrLen] = 'W'; // a pointer to an ansi string. A conversion is performed if
lpFuncName[nStrLen+1] = 0; // neccessary. FreeConvertedMultiByte string should be used on the
fnDllWinMainW = (DllWinMainW)GetProcAddress(hDll,lpFuncName); // return value of ConvertToMultiByte when the string is no longer
fnDllWinMainA = 0; // needed. The original string or the string that is returned
if (!fnDllWinMainW) { // should not be modified until FreeConvertedMultiByte has been called.
lpFuncName[nStrLen] = 'A'; #ifdef UNICODE
fnDllWinMainA = (DllWinMainA)GetProcAddress(hDll,lpFuncName); #define ConvertToMultiByte(lptString) DuplicateToMultiByte(lptString,0)
if (!fnDllWinMainA) { #define FreeConvertedMultiByte(lpaString) free(lpaString)
lpFuncName[nStrLen] = 0; #else
fnDllWinMainA = (DllWinMainA)GetProcAddress(hDll,lpFuncName); #define ConvertToMultiByte(lptString) (lptString)
} #define FreeConvertedMultiByte(lpaString)
} #endif
free(lpFuncName); // DuplicateToMultiByte takes a tstring parameter and always returns
// a pointer to a duplicate ansi string. If nBufferSize is zero,
RegisterBlankClass(hInstance); // the buffer length is the exact size of the string plus the
// Create a window to pass the handle to the dll function // terminating null. If nBufferSize is nonzero, the buffer length
hWindow = CreateWindowEx(0,rundll32_wclass,rundll32_wtitle,0,CW_USEDEFAULT,0,CW_USEDEFAULT,0,0,0,hInstance,0); // is equal to nBufferSize. As with strdup, free should be called
// for the returned string when it is no longer needed.
if (fnDllWinMainW) { LPSTR DuplicateToMultiByte(LPCTSTR lptString, size_t nBufferSize)
lpwCmdLine = ConvertToWideChar(lptCmdLine); {
nRetVal = fnDllWinMainW(hWindow,hInstance,lpwCmdLine,nCmdShow); LPSTR lpString;
FreeConvertedWideChar(lpwCmdLine); size_t nStrLen;
}
else if (fnDllWinMainA) { nStrLen = _tcslen(lptString) + 1;
lpaCmdLine = ConvertToMultiByte(lptCmdLine); if (nBufferSize == 0) nBufferSize = nStrLen;
nRetVal = fnDllWinMainA(hWindow,hInstance,lpaCmdLine,nCmdShow);
FreeConvertedMultiByte(lpaCmdLine); lpString = (LPSTR)malloc(nBufferSize);
} #ifdef UNICODE
else { WideCharToMultiByte(0,0,lptString,nStrLen,lpString,nBufferSize,0,0);
GetModuleTitle(); #else
lptMsgBuffer = (LPTSTR)malloc((_tcslen(MissingEntry) - 4 + _tcslen(lptFuncName) + _tcslen(lptDllName) + 1) * sizeof(TCHAR)); strncpy(lpString,lptString,nBufferSize);
_stprintf(lptMsgBuffer,MissingEntry,lptFuncName,lptDllName); #endif
MessageBox(0,lptMsgBuffer,ModuleTitle,MB_ICONERROR);
free(lptMsgBuffer); return lpString;
} }
DestroyWindow(hWindow); LRESULT CALLBACK EmptyWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
UnregisterClass(rundll32_wclass,hInstance); {
return DefWindowProc(hWnd, uMsg, wParam, lParam);
FreeLibrary(hDll); }
}
else { // Registers a minimal window class for passing to the dll function
GetModuleTitle(); ATOM RegisterBlankClass(HINSTANCE hInstance)
lptMsgBuffer = (LPTSTR)malloc((_tcslen(DllNotLoaded) - 2 + _tcslen(lptDllName) + 1) * sizeof(TCHAR)); {
_stprintf(lptMsgBuffer,DllNotLoaded,lptDllName); WNDCLASSEX wcex;
MessageBox(0,lptMsgBuffer,ModuleTitle,MB_ICONERROR);
free(lptMsgBuffer); wcex.cbSize = sizeof(WNDCLASSEX);
}
wcex.style = 0;
free(lptCmdLineCopy); wcex.lpfnWndProc = EmptyWindowProc;
return nRetVal; wcex.cbClsExtra = 0;
} wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = 0;
wcex.hCursor = 0;
wcex.hbrBackground = 0;
wcex.lpszMenuName = 0;
wcex.lpszClassName = rundll32_wclass;
wcex.hIconSm = 0;
return RegisterClassEx(&wcex);
}
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLineA,
int nCmdShow
)
{
int argc;
LPTSTR *argv;
LPTSTR lptCmdLine,lptDllName,lptFuncName,lptMsgBuffer;
LPSTR lpFuncName,lpaCmdLine;
LPWSTR lpwCmdLine;
HMODULE hDll;
DllWinMainW fnDllWinMainW;
DllWinMainA fnDllWinMainA;
HWND hWindow;
int nRetVal,i;
size_t nStrLen;
// Get command-line in argc-argv format
argv = CommandLineToArgv(GetCommandLine(),&argc);
// Skip all beginning arguments starting with a slash (/)
for (i = 1; i < argc; i++)
if (*argv[i] != _T('/')) break;
// If no dll was specified, there is nothing to do
if (i >= argc) {
if (argv) free(argv);
return 0;
}
lptDllName = argv[i++];
// The next argument, which specifies the name of the dll function,
// can either have a comma between it and the dll filename or a space.
// Using a comma here is the preferred method
if (i < argc)
lptFuncName = argv[i++];
else
lptFuncName = _T("");
// If no function name was specified, nothing needs to be done
if (!*lptFuncName) {
if (argv) free(argv);
return 0;
}
// The rest of the arguments will be passed to dll function
if (i < argc)
lptCmdLine = argv[i];
else
lptCmdLine = _T("");
nRetVal = 0;
// Everything is all setup, so load the dll now
hDll = LoadLibrary(lptDllName);
if (hDll) {
nStrLen = _tcslen(lptFuncName);
// Make a non-unicode version of the function name,
// since that is all GetProcAddress accepts
lpFuncName = DuplicateToMultiByte(lptFuncName,nStrLen + 2);
#ifdef UNICODE
lpFuncName[nStrLen] = 'W';
lpFuncName[nStrLen+1] = 0;
// Get address of unicode version of the dll function if it exists
fnDllWinMainW = (DllWinMainW)GetProcAddress(hDll,lpFuncName);
fnDllWinMainA = 0;
if (!fnDllWinMainW) {
// If no unicode function was found, get the address of the non-unicode function
lpFuncName[nStrLen] = 'A';
fnDllWinMainA = (DllWinMainA)GetProcAddress(hDll,lpFuncName);
if (!fnDllWinMainA) {
// If first non-unicode function was not found, get the address
// of the other non-unicode function
lpFuncName[nStrLen] = 0;
fnDllWinMainA = (DllWinMainA)GetProcAddress(hDll,lpFuncName);
}
}
#else
// Get address of non-unicode version of the dll function if it exists
fnDllWinMainA = (DllWinMainA)GetProcAddress(hDll,lpFuncName);
fnDllWinMainW = 0;
if (!fnDllWinMainA) {
// If first non-unicode function was not found, get the address
// of the other non-unicode function
lpFuncName[nStrLen] = 'A';
lpFuncName[nStrLen+1] = 0;
fnDllWinMainA = (DllWinMainA)GetProcAddress(hDll,lpFuncName);
if (!fnDllWinMainA) {
// If non-unicode function was not found, get the address of the unicode function
lpFuncName[nStrLen] = 'W';
fnDllWinMainW = (DllWinMainW)GetProcAddress(hDll,lpFuncName);
}
}
#endif
free(lpFuncName);
RegisterBlankClass(hInstance);
// Create a window so we can pass a window handle to
// the dll function; this is required
hWindow = CreateWindowEx(0,rundll32_wclass,rundll32_wtitle,0,CW_USEDEFAULT,0,CW_USEDEFAULT,0,0,0,hInstance,0);
if (fnDllWinMainW) {
// Convert the command-line string to unicode and call the dll function
lpwCmdLine = ConvertToWideChar(lptCmdLine);
nRetVal = fnDllWinMainW(hWindow,hInstance,lpwCmdLine,nCmdShow);
FreeConvertedWideChar(lpwCmdLine);
}
else if (fnDllWinMainA) {
// Convert the command-line string to ansi and call the dll function
lpaCmdLine = ConvertToMultiByte(lptCmdLine);
nRetVal = fnDllWinMainA(hWindow,hInstance,lpaCmdLine,nCmdShow);
FreeConvertedMultiByte(lpaCmdLine);
}
else {
// The specified dll function was not found; display an error message
GetModuleTitle();
lptMsgBuffer = (LPTSTR)malloc((_tcslen(MissingEntry) - 4 + _tcslen(lptFuncName) + _tcslen(lptDllName) + 1) * sizeof(TCHAR));
_stprintf(lptMsgBuffer,MissingEntry,lptFuncName,lptDllName);
MessageBox(0,lptMsgBuffer,ModuleTitle,MB_ICONERROR);
free(lptMsgBuffer);
}
DestroyWindow(hWindow);
UnregisterClass(rundll32_wclass,hInstance);
// The dll function has finished executing, so unload it
FreeLibrary(hDll);
}
else {
// The dll could not be loaded; display an error message
GetModuleTitle();
lptMsgBuffer = (LPTSTR)malloc((_tcslen(DllNotLoaded) - 2 + _tcslen(lptDllName) + 1) * sizeof(TCHAR));
_stprintf(lptMsgBuffer,DllNotLoaded,lptDllName);
MessageBox(0,lptMsgBuffer,ModuleTitle,MB_ICONERROR);
free(lptMsgBuffer);
}
if (argv) free(argv);
return nRetVal;
}