libdb/lang/sql/odbc/inst.c
2011-09-13 13:44:24 -04:00

340 lines
7.7 KiB
C

/**
* @file inst.c
* SQLite ODBC Driver installer/uninstaller for WIN32
*
* $Id: inst.c,v 1.12 2009/05/03 04:22:18 chw Exp chw $
*
* Copyright (c) 2001-2007 Christian Werner <chw@ch-werner.de>
*
* See the file "license.terms" for information on usage
* and redistribution of this file and for a
* DISCLAIMER OF ALL WARRANTIES.
*/
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <odbcinst.h>
#include <winver.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#ifdef _WIN64
#define NUMDRVS 1
static char *DriverName[NUMDRVS] = {
"SQLite3 ODBC Driver"
};
static char *DSName[NUMDRVS] = {
"SQLite3 Datasource"
};
static char *DriverDLL[NUMDRVS] = {
"sqlite3odbc.dll"
};
#ifdef WITH_SQLITE_DLLS
static char *EngineDLL[NUMDRVS] = {
"sqlite3.dll"
};
#endif
#else
#define NUMDRVS 3
static char *DriverName[NUMDRVS] = {
"SQLite ODBC Driver",
"SQLite ODBC (UTF-8) Driver",
"SQLite3 ODBC Driver"
};
static char *DSName[NUMDRVS] = {
"SQLite Datasource",
"SQLite UTF-8 Datasource",
"SQLite3 Datasource"
};
static char *DriverDLL[NUMDRVS] = {
"sqliteodbc.dll",
"sqliteodbcu.dll",
"sqlite3odbc.dll"
};
#ifdef WITH_SQLITE_DLLS
static char *EngineDLL[NUMDRVS] = {
"sqlite.dll",
"sqliteu.dll",
"sqlite3.dll"
};
#endif
#endif
static int quiet = 0;
static int nosys = 0;
/**
* Handler for ODBC installation error messages.
* @param name name of API function for which to show error messages
*/
static BOOL
ProcessErrorMessages(char *name)
{
WORD err = 1;
DWORD code;
char errmsg[301];
WORD errlen, errmax = sizeof (errmsg) - 1;
int rc;
BOOL ret = FALSE;
do {
errmsg[0] = '\0';
rc = SQLInstallerError(err, &code, errmsg, errmax, &errlen);
if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
MessageBox(NULL, errmsg, name,
MB_ICONSTOP|MB_OK|MB_TASKMODAL|MB_SETFOREGROUND);
ret = TRUE;
}
err++;
} while (rc != SQL_NO_DATA);
return ret;
}
/**
* Copy or delete SQLite3 module DLLs
* @param dllname file name of driver DLL
* @param path install directory for modules
* @param del flag, when true, delete DLLs in install directory
*/
static BOOL
CopyOrDelModules(char *dllname, char *path, BOOL del)
{
char firstpat[MAX_PATH];
WIN32_FIND_DATA fdata;
HANDLE h;
DWORD err;
if (strncmp(dllname, "sqlite3", 7)) {
return TRUE;
}
firstpat[0] = '\0';
if (del) {
strcpy(firstpat, path);
strcat(firstpat, "\\");
}
strcat(firstpat, "sqlite3_mod*.dll");
h = FindFirstFile(firstpat, &fdata);
if (h == INVALID_HANDLE_VALUE) {
return TRUE;
}
do {
if (del) {
DeleteFile(fdata.cFileName);
} else {
char buf[1024];
sprintf(buf, "%s\\%s", path, fdata.cFileName);
if (!CopyFile(fdata.cFileName, buf, 0)) {
sprintf(buf, "Copy %s to %s failed", fdata.cFileName, path);
MessageBox(NULL, buf, "CopyFile",
MB_ICONSTOP|MB_OK|MB_TASKMODAL|MB_SETFOREGROUND);
FindClose(h);
return FALSE;
}
}
} while (FindNextFile(h, &fdata));
err = GetLastError();
FindClose(h);
return err == ERROR_NO_MORE_FILES;
}
/**
* Driver installer/uninstaller.
* @param remove true for uninstall
* @param drivername print name of driver
* @param dllname file name of driver DLL
* @param dll2name file name of additional DLL
* @param dsname name for data source
*/
static BOOL
InUn(int remove, char *drivername, char *dllname, char *dll2name, char *dsname)
{
char path[301], driver[300], attr[300], inst[400], inst2[400];
WORD pathmax = sizeof (path) - 1, pathlen;
DWORD usecnt, mincnt;
if (SQLInstallDriverManager(path, pathmax, &pathlen)) {
char *p;
sprintf(driver, "%s;Driver=%s;Setup=%s;",
drivername, dllname, dllname);
p = driver;
while (*p) {
if (*p == ';') {
*p = '\0';
}
++p;
}
usecnt = 0;
SQLInstallDriverEx(driver, NULL, path, pathmax, &pathlen,
ODBC_INSTALL_INQUIRY, &usecnt);
sprintf(driver, "%s;Driver=%s\\%s;Setup=%s\\%s;",
drivername, path, dllname, path, dllname);
p = driver;
while (*p) {
if (*p == ';') {
*p = '\0';
}
++p;
}
sprintf(inst, "%s\\%s", path, dllname);
if (dll2name) {
sprintf(inst2, "%s\\%s", path, dll2name);
}
if (!remove && usecnt > 0) {
/* first install try: copy over driver dll, keeping DSNs */
if (GetFileAttributes(dllname) != 0xFFFFFFFF &&
CopyFile(dllname, inst, 0) &&
CopyOrDelModules(dllname, path, 0)) {
if (dll2name != NULL) {
CopyFile(dll2name, inst2, 0);
}
return TRUE;
}
}
mincnt = remove ? 1 : 0;
while (usecnt != mincnt) {
if (!SQLRemoveDriver(driver, TRUE, &usecnt)) {
break;
}
}
if (remove) {
if (!SQLRemoveDriver(driver, TRUE, &usecnt)) {
ProcessErrorMessages("SQLRemoveDriver");
return FALSE;
}
if (!usecnt) {
char buf[512];
DeleteFile(inst);
/* but keep inst2 */
CopyOrDelModules(dllname, path, 1);
if (!quiet) {
sprintf(buf, "%s uninstalled.", drivername);
MessageBox(NULL, buf, "Info",
MB_ICONINFORMATION|MB_OK|MB_TASKMODAL|
MB_SETFOREGROUND);
}
}
if (nosys) {
goto done;
}
sprintf(attr, "DSN=%s;Database=sqlite.db;", dsname);
p = attr;
while (*p) {
if (*p == ';') {
*p = '\0';
}
++p;
}
SQLConfigDataSource(NULL, ODBC_REMOVE_SYS_DSN, drivername, attr);
goto done;
}
if (GetFileAttributes(dllname) == 0xFFFFFFFF) {
return FALSE;
}
if (!CopyFile(dllname, inst, 0)) {
char buf[512];
sprintf(buf, "Copy %s to %s failed", dllname, inst);
MessageBox(NULL, buf, "CopyFile",
MB_ICONSTOP|MB_OK|MB_TASKMODAL|MB_SETFOREGROUND);
return FALSE;
}
if (dll2name != NULL && !CopyFile(dll2name, inst2, 0)) {
char buf[512];
sprintf(buf, "Copy %s to %s failed", dll2name, inst2);
MessageBox(NULL, buf, "CopyFile",
MB_ICONSTOP|MB_OK|MB_TASKMODAL|MB_SETFOREGROUND);
/* but go on hoping that an SQLite engine is in place */
}
if (!CopyOrDelModules(dllname, path, 0)) {
return FALSE;
}
if (!SQLInstallDriverEx(driver, path, path, pathmax, &pathlen,
ODBC_INSTALL_COMPLETE, &usecnt)) {
ProcessErrorMessages("SQLInstallDriverEx");
return FALSE;
}
if (nosys) {
goto done;
}
sprintf(attr, "DSN=%s;Database=sqlite.db;", dsname);
p = attr;
while (*p) {
if (*p == ';') {
*p = '\0';
}
++p;
}
SQLConfigDataSource(NULL, ODBC_REMOVE_SYS_DSN, drivername, attr);
if (!SQLConfigDataSource(NULL, ODBC_ADD_SYS_DSN, drivername, attr)) {
ProcessErrorMessages("SQLConfigDataSource");
return FALSE;
}
} else {
ProcessErrorMessages("SQLInstallDriverManager");
return FALSE;
}
done:
return TRUE;
}
/**
* Main function of installer/uninstaller.
* This is the Win32 GUI main entry point.
* It (un)registers the ODBC driver(s) and deletes or
* copies the driver DLL(s) to the system folder.
*/
int APIENTRY
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
char path[300], *p;
int i, remove;
BOOL ret[3];
GetModuleFileName(NULL, path, sizeof (path));
p = path;
while (*p) {
*p = tolower(*p);
++p;
}
p = strrchr(path, '\\');
if (p == NULL) {
p = path;
} else {
*p = '\0';
++p;
SetCurrentDirectory(path);
}
remove = strstr(p, "uninst") != NULL;
quiet = strstr(p, "instq") != NULL;
nosys = strstr(p, "nosys") != NULL;
for (i = 0; i < NUMDRVS; i++) {
#ifdef WITH_SQLITE_DLLS
p = EngineDLL[i];
#else
p = NULL;
#endif
ret[i] = InUn(remove, DriverName[i], DriverDLL[i], p, DSName[i]);
}
for (i = 1; i < NUMDRVS; i++) {
ret[0] = ret[0] || ret[i];
}
if (!remove && ret[0]) {
if (!quiet) {
MessageBox(NULL, "SQLite ODBC Driver(s) installed.", "Info",
MB_ICONINFORMATION|MB_OK|MB_TASKMODAL|MB_SETFOREGROUND);
}
}
exit(0);
}