/* Copyright (C) 2011, 2012 Sergey V. Mikayev
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* 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
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
#define WIN32_LEAN_AND_MEAN
#include
const char OPL3EMU_DRIVER_NAME[] = "adlmididrv.dll";
const char OPL3EMU_CPLAPPLET_NAME[] = "libadlconfig.cpl";
const char OPL3EMU_SETUPTOOL_NAME[] = "adlmidiconfigtool.exe";
const char WDM_DRIVER_NAME[] = "wdmaud.drv";
const char SYSTEM_DIR_NAME[] = "SYSTEM32";
const char SYSTEM_ROOT_ENV_NAME[] = "SYSTEMROOT";
const char INSTALL_COMMAND[] = "install";
const char UNINSTALL_COMMAND[] = "uninstall";
const char DRIVERS_REGISTRY_KEY[] = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32";
const char PATH_SEPARATOR[] = "\\";
const char SUCCESSFULLY_INSTALLED_MSG[] = "libADLMIDI synth MIDI Driver successfully installed";
const char SUCCESSFULLY_UPDATED_MSG[] = "libADLMIDI synth MIDI Driver successfully updated";
const char SUCCESSFULLY_UNINSTALLED_MSG[] = "libADLMIDI synth MIDI Driver successfully uninstalled";
const char USAGE_MSG[] = "Usage:\n drvsetup install - install driver\n drvsetup uninstall - uninstall driver";
const char CANNOT_OPEN_REGISTRY_ERR[] = "Cannot open registry key";
const char CANNOT_INSTALL_NO_PORTS_ERR[] = "Cannot install libADLMIDI synth MIDI driver:\n There is no MIDI ports available";
const char CANNOT_REGISTER_ERR[] = "Cannot register driver";
const char CANNOT_UNINSTALL_ERR[] = "Cannot uninstall libADLMIDI synth MIDI driver";
const char CANNOT_UNINSTALL_NOT_FOUND_ERR[] = "Cannot uninstall libADLMIDI synth MIDI driver:\n There is no driver registry entry found";
const char CANNOT_INSTALL_PATH_TOO_LONG_ERR[] = "libADLMIDI synth MIDI Driver cannot be installed:\n Installation path is too long";
const char CANNOT_INSTALL_FILE_COPY_ERR[] = "libADLMIDI synth MIDI Driver failed to install:\n File copying error";
const char INFORMATION_TITLE[] = "Information";
const char ERROR_TITLE[] = "Error";
const char REGISTRY_ERROR_TITLE[] = "Registry error";
const char FILE_ERROR_TITLE[] = "File error";
BOOL registerDriver(BOOL *installMode)
{
char str[255];
char drvName[] = "midi0";
DWORD len, res;
BOOL wdmEntryFound = FALSE;
int freeEntry = -1;
HKEY hReg;
int i;
if(RegOpenKeyA(HKEY_LOCAL_MACHINE, DRIVERS_REGISTRY_KEY, &hReg))
{
MessageBoxA(NULL, CANNOT_OPEN_REGISTRY_ERR, REGISTRY_ERROR_TITLE, MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
for(i = 0; i < 10; i++)
{
len = 255;
if(i)
drvName[4] = '0' + i;
else
drvName[4] = 0;
res = RegQueryValueExA(hReg, drvName, NULL, NULL, (LPBYTE)str, &len);
if(res != ERROR_SUCCESS)
{
if((freeEntry == -1) && (res == ERROR_FILE_NOT_FOUND))
freeEntry = i;
continue;
}
if(!_stricmp(str, OPL3EMU_DRIVER_NAME))
{
RegCloseKey(hReg);
*installMode = FALSE;
return TRUE;
}
if(freeEntry != -1) continue;
if(strlen(str) == 0)
freeEntry = i;
else if(!_stricmp(str, WDM_DRIVER_NAME))
{
// Considering multiple WDM entries are just garbage, though one entry shouldn't be modified
if(wdmEntryFound)
freeEntry = i;
else
wdmEntryFound = TRUE;
}
}
if(freeEntry == -1)
{
MessageBoxA(NULL, CANNOT_INSTALL_NO_PORTS_ERR, ERROR_TITLE, MB_OK | MB_ICONEXCLAMATION);
RegCloseKey(hReg);
return FALSE;
}
if(freeEntry)
drvName[4] = '0' + freeEntry;
else
drvName[4] = 0;
res = RegSetValueExA(hReg, drvName, 0, REG_SZ, (LPBYTE)OPL3EMU_DRIVER_NAME, sizeof(OPL3EMU_DRIVER_NAME));
if(res != ERROR_SUCCESS)
{
MessageBoxA(NULL, CANNOT_REGISTER_ERR, REGISTRY_ERROR_TITLE, MB_OK | MB_ICONEXCLAMATION);
RegCloseKey(hReg);
return FALSE;
}
RegCloseKey(hReg);
return TRUE;
}
void unregisterDriver()
{
char str[255];
char drvName[] = "midi0";
DWORD len, res;
HKEY hReg;
int i;
if(RegOpenKeyA(HKEY_LOCAL_MACHINE, DRIVERS_REGISTRY_KEY, &hReg))
{
MessageBoxA(NULL, CANNOT_OPEN_REGISTRY_ERR, REGISTRY_ERROR_TITLE, MB_OK | MB_ICONEXCLAMATION);
return;
}
for(i = 0; i < 10; i++)
{
len = 255;
if(i)
drvName[4] = '0' + i;
else
drvName[4] = 0;
res = RegQueryValueExA(hReg, drvName, NULL, NULL, (LPBYTE)str, &len);
if(res != ERROR_SUCCESS)
continue;
if(!_stricmp(str, OPL3EMU_DRIVER_NAME))
{
res = RegDeleteValueA(hReg, drvName);
if(res != ERROR_SUCCESS)
{
MessageBoxA(NULL, CANNOT_UNINSTALL_ERR, REGISTRY_ERROR_TITLE, MB_OK | MB_ICONEXCLAMATION);
RegCloseKey(hReg);
return;
}
MessageBoxA(NULL, SUCCESSFULLY_UNINSTALLED_MSG, INFORMATION_TITLE, MB_OK | MB_ICONINFORMATION);
RegCloseKey(hReg);
return;
}
}
MessageBoxA(NULL, CANNOT_UNINSTALL_NOT_FOUND_ERR, ERROR_TITLE, MB_OK | MB_ICONEXCLAMATION);
RegCloseKey(hReg);
}
void constructSystemDirName(char *pathName)
{
char sysRoot[MAX_PATH + 1];
GetEnvironmentVariableA(SYSTEM_ROOT_ENV_NAME, sysRoot, MAX_PATH);
strncpy(pathName, sysRoot, MAX_PATH + 1);
strncat(pathName, PATH_SEPARATOR, MAX_PATH - strlen(pathName));
strncat(pathName, SYSTEM_DIR_NAME, MAX_PATH - strlen(pathName));
strncat(pathName, PATH_SEPARATOR, MAX_PATH - strlen(pathName));
}
void constructDriverPathName(char *pathName, const char*fileName)
{
constructSystemDirName(pathName);
strncat(pathName, fileName, MAX_PATH - strlen(pathName));
}
void deleteFileReliably(char *pathName, const char *fileName)
{
const size_t nameSize = strlen(fileName) + 1;
char tmpFilePrefix[MAX_PATH + 1];
char tmpDirName[MAX_PATH + 1];
char tmpPathName[MAX_PATH + 1];
if(DeleteFileA(pathName))
return;
// File doesn't exist, nothing to do
if(ERROR_FILE_NOT_FOUND == GetLastError())
return;
// File can't be deleted, rename it and register pending deletion
strncpy(tmpFilePrefix, fileName, nameSize);
strncat(tmpFilePrefix, ".", nameSize);
constructSystemDirName(tmpDirName);
GetTempFileNameA(tmpDirName, tmpFilePrefix, 0, tmpPathName);
DeleteFileA(tmpPathName);
MoveFileA(pathName, tmpPathName);
MoveFileExA(tmpPathName, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
}
BOOL copyFileIntoSystem(const char *fileName, char **argv)
{
char driverPathName[MAX_PATH + 1];
char setupPathName[MAX_PATH + 1];
int setupPathLen;
setupPathLen = strrchr(argv[0], '\\') - argv[0];
if(setupPathLen > (int)(MAX_PATH - strlen(fileName) + 1 - 2))
{
MessageBoxA(NULL, CANNOT_INSTALL_PATH_TOO_LONG_ERR, ERROR_TITLE, MB_OK | MB_ICONEXCLAMATION);
return 2;
}
constructDriverPathName(driverPathName, fileName);
deleteFileReliably(driverPathName, fileName);
strncpy(setupPathName, argv[0], setupPathLen);
setupPathName[setupPathLen] = 0;
strncat(setupPathName, PATH_SEPARATOR, MAX_PATH - strlen(setupPathName));
strncat(setupPathName, fileName, MAX_PATH - strlen(setupPathName));
if(!CopyFileA(setupPathName, driverPathName, FALSE))
{
MessageBoxA(NULL, CANNOT_INSTALL_FILE_COPY_ERR, FILE_ERROR_TITLE, MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
return TRUE;
}
int main(int argc, char *argv[])
{
char pathName[MAX_PATH + 1];
BOOL installMode;
if(argc != 2 || (_stricmp(INSTALL_COMMAND, argv[1]) != 0 && _stricmp(UNINSTALL_COMMAND, argv[1]) != 0))
{
MessageBoxA(NULL, USAGE_MSG, INFORMATION_TITLE, MB_OK | MB_ICONINFORMATION);
return 1;
}
if(_stricmp(UNINSTALL_COMMAND, argv[1]) == 0)
{
constructDriverPathName(pathName, OPL3EMU_DRIVER_NAME);
deleteFileReliably(pathName, OPL3EMU_DRIVER_NAME);
constructDriverPathName(pathName, OPL3EMU_CPLAPPLET_NAME);
deleteFileReliably(pathName, OPL3EMU_CPLAPPLET_NAME);
constructDriverPathName(pathName, OPL3EMU_SETUPTOOL_NAME);
deleteFileReliably(pathName, OPL3EMU_SETUPTOOL_NAME);
unregisterDriver();
return 0;
}
installMode = TRUE;
if(!registerDriver(&installMode))
return 3;
if(!copyFileIntoSystem(OPL3EMU_DRIVER_NAME, argv))
return 4;
if(!copyFileIntoSystem(OPL3EMU_CPLAPPLET_NAME, argv))
return 4;
if(!copyFileIntoSystem(OPL3EMU_SETUPTOOL_NAME, argv))
return 4;
MessageBoxA(NULL, installMode ? SUCCESSFULLY_INSTALLED_MSG : SUCCESSFULLY_UPDATED_MSG, INFORMATION_TITLE, MB_OK | MB_ICONINFORMATION);
return 0;
}