home *** CD-ROM | disk | FTP | other *** search
- /*--------------------------------------------------------------------------
- Samplesp.c -- Sample ODBC setup
-
- This code demonstrates how to interact with the ODBC Installer. These
- functions may be part of your ODBC driver or in a separate DLL.
-
- The ODBC Installer allows a driver to control the management of
- data sources by calling the ConfigDSN entry point in the appropriate
- DLL. When called, ConfigDSN receives four parameters:
-
- hwndParent ---- Handle of the parent window for any dialogs which
- may need to be created. If this handle is NULL,
- then no dialogs should be displayed (that is, the
- request should be processed silently).
-
- fRequest ------ Flag indicating the type of request (add, configure
- (edit), or remove).
-
- lpszDriver ---- Far pointer to a null-terminated string containing
- the name of your driver. This is the same string you
- supply in the ODBC.INF file as your section header
- and which ODBC Setup displays to the user in lieu
- of the actual driver filename. This string needs to
- be passed back to the ODBC Installer when adding a
- new data source name.
-
- lpszAttributes- Far pointer to a list of null-terminated attribute
- keywords. This list is similar to the list passed
- to SQLDriverConnect, except that each key-value
- pair is separated by a null-byte rather than a
- semicolon. The entire list is then terminated with
- a null-byte (that is, two consecutive null-bytes
- mark the end of the list). The keywords accepted
- should be those for SQLDriverConnect which are
- applicable, any new keywords you define for ODBC.INI,
- and any additional keywords you decide to document.
-
- ConfigDSN should return TRUE if the requested operation succeeds and
- FALSE otherwise. The complete prototype for ConfigDSN is:
-
- BOOL FAR PASCAL ConfigDSN(HWND hwndParent,
- UINT fRequest,
- LPSTR lpszDriver,
- LPCSTR lpszAttributes)
-
- Your setup code should not write to ODBC.INI directly to add or remove
- data source names. Instead, link with ODBCINST.LIB (the ODBC Installer
- library) and call SQLWriteDSNToIni and SQLRemoveDSNFromIni.
- Use SQLWriteDSNToIni to add data source names. If the data source name
- already exists, SQLWriteDSNToIni will delete it (removing all of its
- associated keys) and rewrite it. SQLRemoveDSNToIni removes a data
- source name and all of its associated keys.
-
- (c) Microsoft Corp., 1990-1992
- --------------------------------------------------------------------------*/
-
-
- // Includes ----------------------------------------------------------------
- #include <windows.h> // Windows include file
- #include <odbcinst.h> // ODBC installer prototypes
- #include <string.h> // C include files
- #include "sampstp.h" // Local include files
-
-
- // Constants ---------------------------------------------------------------
- #define MIN(x,y) ((x) < (y) ? (x) : (y))
-
- #define MAXPATHLEN (255+1) // Max path length
- #define MAXKEYLEN (15+1) // Max keyword length
- #define MAXDESC (255+1) // Max description length
- #define MAXDSNAME (32+1) // Max data source name length
-
- const char EMPTYSTR []= "";
- const char OPTIONON []= "Yes";
- const char OPTIONOFF []= "No";
-
- // ODBC.INI keywords
- const char ODBC_INI []="ODBC.INI"; // ODBC initialization file
- const char INI_KDESC []="Description"; // Data source description
- const char INI_KOPT1 []="Option1"; // First option
- const char INI_KOPT2 []="Option2"; // Second option
- const char INI_SDEFAULT[] = "Default"; // Default data source name
-
- // Attribute key indexes (into an array of Attr structs, see below)
- #define KEY_DSN 0
- #define KEY_DESC 1
- #define KEY_OPT1 2
- #define KEY_OPT2 3
- #define NUMOFKEYS 4 // Number of keys supported
-
- // Attribute string look-up table (maps keys to associated indexes)
- static struct {
- char szKey[MAXKEYLEN];
- int iKey;
- } s_aLookup[] = { "DSN", KEY_DSN,
- "DESC", KEY_DESC,
- "Description", KEY_DESC,
- "Option1", KEY_OPT1,
- "Option2", KEY_OPT2,
- "", 0
- };
-
-
- // Types -------------------------------------------------------------------
- typedef struct tagAttr {
- BOOL fSupplied;
- char szAttr[MAXPATHLEN];
- } Attr, FAR * LPAttr;
-
-
- // Globals -----------------------------------------------------------------
- // NOTE: All these are used by the dialog procedures
- HGLOBAL hinst; // Dialog instance handle
- HWND hwndParent; // Parent window handle
- LPCSTR lpszDrvr; // Driver description
- HGLOBAL hglbAttr; // Attribute array handle
- LPAttr aAttr; // Attribute array pointer
- BOOL fNewDSN; // New data source flag
- BOOL fDefault; // Default data source flag
- char szDSN[MAXDSNAME]; // Original data source name
-
-
- // Prototypes --------------------------------------------------------------
- void PASCAL CenterDialog (HWND hdlg);
- int FAR PASCAL ConfigDlgProc (HWND hdlg,
- WORD wMsg,
- WORD wParam,
- DWORD lParam);
- BOOL FAR PASCAL ConfigDSN (HWND hwnd,
- UINT fRequest,
- LPCSTR lpszRsv,
- LPCSTR lpszAttributes);
- void PASCAL ParseAttributes (LPCSTR lpszAttributes);
- BOOL PASCAL SetDSNAttributes(HWND hwnd);
-
- int FAR PASCAL LibMain (HANDLE hInstance,
- WORD wDSize,
- WORD wHSize,
- LPSTR lpsz);
- int FAR PASCAL WEP (int nParam);
-
-
- /* LibMain -----------------------------------------------------------------
- Description: DLL init routine (called by LIBENTRY.ASM)
- Input : hinst -- Instance handle
- wDSize - Size of data segment (in words)
- wHSize - Size of heap (in bytes)
- lpsz --- Pointer to associated application command line
- Output : TRUE (always)
- --------------------------------------------------------------------------*/
- int FAR PASCAL LibMain(HANDLE hInstance,
- WORD wDSize,
- WORD wHSize,
- LPSTR lpsz)
- {
- if (wHSize > 0)
- UnlockData(0);
-
- hinst = hInstance;
- return TRUE;
- }
-
-
- /* WEP ---------------------------------------------------------------------
- Description: DLL exit routine
- Input : nParam -- System exit code
- Output : TRUE (always)
- --------------------------------------------------------------------------*/
- int FAR PASCAL WEP (int nParam)
- {
- return TRUE;
- }
-
-
- /* ConfigDSN ---------------------------------------------------------------
- Description: ODBC Setup entry point
- This entry point is called by the ODBC Installer
- (see file header for more details)
- Input : hwnd ----------- Parent window handle
- fRequest ------- Request type (i.e., add, config, or remove)
- lpszDriver ----- Driver name
- lpszAttributes - data source attribute string
- Output : TRUE success, FALSE otherwise
- --------------------------------------------------------------------------*/
- BOOL FAR PASCAL ConfigDSN(HWND hwnd,
- UINT fRequest,
- LPCSTR lpszDriver,
- LPCSTR lpszAttributes)
- {
- BOOL fSuccess; // Success/fail flag
-
- // Allocate attribute array
- hglbAttr = GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
- sizeof(Attr) * NUMOFKEYS);
- if (!hglbAttr)
- return FALSE;
- aAttr = (LPAttr)GlobalLock(hglbAttr);
-
- // Parse attribute string
- if (lpszAttributes) ParseAttributes(lpszAttributes);
-
- // Save original data source name
- if (aAttr[KEY_DSN].fSupplied)
- lstrcpy(szDSN, aAttr[KEY_DSN].szAttr);
- else
- szDSN[0] = '\0';
-
- // Remove data source
- if (ODBC_REMOVE_DSN == fRequest) {
- // Fail if no data source name was supplied
- if (!aAttr[KEY_DSN].fSupplied)
- fSuccess = FALSE;
-
- // Otherwise remove data source from ODBC.INI
- else
- fSuccess = SQLRemoveDSNFromIni(aAttr[KEY_DSN].szAttr);
- }
-
- // Add or Configure data source
- else {
- // Save passed variables for global access (e.g., dialog access)
- hwndParent = hwnd;
- lpszDrvr = lpszDriver;
- fNewDSN = (ODBC_ADD_DSN == fRequest);
- fDefault = !lstrcmpi(aAttr[KEY_DSN].szAttr, INI_SDEFAULT);
-
- // Display the appropriate dialog (if parent window handle supplied)
- if (hwnd) {
- // Display dialog(s)
- fSuccess = (IDOK == DialogBox(hinst,
- MAKEINTRESOURCE(CONFIGDSN),
- hwnd,
- ConfigDlgProc));
- }
-
- else if (aAttr[KEY_DSN].fSupplied)
- fSuccess = SetDSNAttributes(hwnd);
- else
- fSuccess = FALSE;
- }
-
- GlobalUnlock(hglbAttr);
- GlobalFree(hglbAttr);
- return fSuccess;
- }
-
-
- /* CenterDialog ------------------------------------------------------------
- Description: Center the dialog over the parent window
- Input : hdlg -- Dialog window handle
- Output : None
- --------------------------------------------------------------------------*/
- void PASCAL CenterDialog(HWND hdlg)
- {
- RECT rcParent; // Parent window client rect
- RECT rcDlg; // Dialog window rect
- int nLeft, nTop; // Top-left coordinates
- int cWidth, cHeight; // Width and height
-
- // Get frame window client rect in screen coordinates
- GetWindowRect(GetParent(hdlg), &rcParent);
-
- // Determine the top-left point for the dialog to be centered
- GetWindowRect(hdlg, &rcDlg);
- cWidth = rcDlg.right - rcDlg.left;
- cHeight = rcDlg.bottom - rcDlg.top;
- nLeft = rcParent.left +
- (((rcParent.right - rcParent.left) - cWidth ) / 2);
- nTop = rcParent.top +
- (((rcParent.bottom - rcParent.top ) - cHeight) / 2);
- if (nLeft < 0) nLeft = 0;
- if (nTop < 0) nTop = 0;
-
- // Place the dialog
- MoveWindow(hdlg, nLeft, nTop, cWidth, cHeight, TRUE);
- return;
- }
-
-
- /* ConfigDlgProc -----------------------------------------------------------
- Description: Manage add data source name dialog
- Input : hdlg --- Dialog window handle
- wMsg --- Message
- wParam - Message parameter
- lParam - Message parameter
- Output : TRUE if message processed, FALSE otherwise
- --------------------------------------------------------------------------*/
- int FAR PASCAL ConfigDlgProc(HWND hdlg,
- WORD wMsg,
- WORD wParam,
- DWORD lParam)
- {
- switch (wMsg) {
- // Initialize the dialog
- case WM_INITDIALOG: {
- LPCSTR lpszDSN;
-
- CenterDialog(hdlg); // Center dialog
- lpszDSN = aAttr[KEY_DSN].szAttr;
-
- // Initialize dialog fields
- // NOTE: Values supplied in the attribute string will always
- // override settings in ODBC.INI
- SetDlgItemText(hdlg, IDC_DSNAME, lpszDSN);
-
- if (!aAttr[KEY_DESC].fSupplied)
- GetPrivateProfileString(lpszDSN, INI_KDESC,
- EMPTYSTR,
- aAttr[KEY_DESC].szAttr,
- sizeof(aAttr[KEY_DESC].szAttr),
- ODBC_INI);
- SetDlgItemText(hdlg, IDC_DESC, aAttr[KEY_DESC].szAttr);
-
- if (!aAttr[KEY_OPT1].fSupplied)
- GetPrivateProfileString(lpszDSN, INI_KOPT1,
- EMPTYSTR,
- aAttr[KEY_OPT1].szAttr,
- sizeof(aAttr[KEY_OPT1].szAttr),
- ODBC_INI);
- CheckDlgButton(hdlg, IDC_OPTION1,
- !lstrcmpi(aAttr[KEY_OPT1].szAttr, OPTIONON));
-
- if (!aAttr[KEY_OPT2].fSupplied)
- GetPrivateProfileString(lpszDSN, INI_KOPT2,
- EMPTYSTR,
- aAttr[KEY_OPT2].szAttr,
- sizeof(aAttr[KEY_OPT2].szAttr),
- ODBC_INI);
- CheckDlgButton(hdlg, IDC_OPTION2,
- !lstrcmpi(aAttr[KEY_OPT2].szAttr, OPTIONON));
-
- if (fDefault) {
- EnableWindow(GetDlgItem(hdlg, IDC_DSNAME), FALSE);
- EnableWindow(GetDlgItem(hdlg, IDC_DSNAMETEXT), FALSE);
- }
- else
- SendDlgItemMessage(hdlg, IDC_DSNAME,
- EM_LIMITTEXT, (WORD)(MAXDSNAME-1), 0L);
- SendDlgItemMessage(hdlg, IDC_DESC,
- EM_LIMITTEXT, (WORD)(MAXDESC-1), 0L);
- return TRUE; // Focus was not set
- }
-
- // Process buttons
- case WM_COMMAND:
- switch (wParam) {
- // Ensure the OK button is enabled only when a data source name
- // is entered
- case IDC_DSNAME:
- if (HIWORD(lParam) == EN_CHANGE) {
- char szItem[MAXDSNAME]; // Edit control text
-
- // Enable/disable the OK button
- EnableWindow(GetDlgItem(hdlg, IDOK),
- GetDlgItemText(hdlg, IDC_DSNAME,
- szItem, sizeof(szItem)));
- return TRUE;
- }
- break;
-
- // Accept results
- case IDOK: {
- // Retrieve dialog values
- if (!fDefault)
- GetDlgItemText(hdlg, IDC_DSNAME,
- aAttr[KEY_DSN].szAttr,
- sizeof(aAttr[KEY_DSN].szAttr));
- GetDlgItemText(hdlg, IDC_DESC,
- aAttr[KEY_DESC].szAttr,
- sizeof(aAttr[KEY_DESC].szAttr));
- lstrcpy(aAttr[KEY_OPT1].szAttr,
- (IsDlgButtonChecked(hdlg, IDC_OPTION1)
- ? OPTIONON
- : OPTIONOFF));
- lstrcpy(aAttr[KEY_OPT2].szAttr,
- (IsDlgButtonChecked(hdlg, IDC_OPTION2)
- ? OPTIONON
- : OPTIONOFF));
-
- // Update ODBC.INI
- SetDSNAttributes(hdlg);
- }
-
- // Return to caller
- case IDCANCEL:
- EndDialog(hdlg, wParam);
- return TRUE;
- }
- break;
- }
-
- // Message not processed
- return FALSE;
- }
-
-
- /* ParseAttributes ---------------------------------------------------------
- Description: Parse attribute string moving values into the aAttr array
- Input : lpszAttributes - Pointer to attribute string
- Output : None (global aAttr normally updated)
- --------------------------------------------------------------------------*/
- void PASCAL ParseAttributes(LPCSTR lpszAttributes)
- {
- LPCSTR lpsz;
- LPCSTR lpszStart;
- char aszKey[MAXKEYLEN];
- short iElement;
- short cbKey;
-
- for (lpsz=lpszAttributes; *lpsz; lpsz++) {
- // Extract key name (e.g., DSN), it must be terminated by an equals
- lpszStart = lpsz;
- for (;; lpsz++)
- if (!*lpsz) return; // No key was found
- else if (*lpsz == '=') break; // Valid key found
-
- // Determine the key's index in the key table (-1 if not found)
- iElement = -1;
- cbKey = lpsz - lpszStart;
- if (cbKey < sizeof(aszKey)) {
- register short j;
-
- _fmemcpy(aszKey, lpszStart, cbKey);
- aszKey[cbKey] = '\0';
- for (j = 0; *s_aLookup[j].szKey; j++)
- if (!lstrcmpi(s_aLookup[j].szKey, aszKey)) {
- iElement = s_aLookup[j].iKey;
- break;
- }
- }
-
- // Locate end of key value
- lpszStart = ++lpsz;
- for (; *lpsz; lpsz++);
-
- // Save value if key is known
- // NOTE: This code assumes the szAttr buffers in aAttr have been
- // zero initialized
- if (iElement >= 0) {
- aAttr[iElement].fSupplied = TRUE;
- _fmemcpy(aAttr[iElement].szAttr,
- lpszStart,
- MIN(lpsz-lpszStart+1, sizeof(aAttr[0].szAttr)-1));
- }
- }
- return;
- }
-
-
- /* SetDSNAttributes --------------------------------------------------------
- Description: Write data source attributes to ODBC.INI
- Input : hwnd - Parent window handle (plus globals)
- Output : TRUE if successful, FALSE otherwise
- --------------------------------------------------------------------------*/
- BOOL PASCAL SetDSNAttributes(HWND hwnd)
- {
- LPCSTR lpszDSN; // Pointer to data source name
-
- lpszDSN = aAttr[KEY_DSN].szAttr;
-
- // Validate arguments
- if (fNewDSN && !*aAttr[KEY_DSN].szAttr)
- return FALSE;
-
- // Write the data source name
- if (!SQLWriteDSNToIni(lpszDSN, lpszDrvr)) {
- if (hwnd) {
- char szBuf[MAXPATHLEN];
- char szMsg[MAXPATHLEN];
-
- LoadString(hinst, IDS_BADDSN, szBuf, sizeof(szBuf));
- wsprintf(szMsg, szBuf, lpszDSN);
- LoadString(hinst, IDS_MSGTITLE, szBuf, sizeof(szBuf));
- MessageBox(hwnd, szMsg, szBuf, MB_ICONEXCLAMATION | MB_OK);
- }
- return FALSE;
- }
-
- // Update ODBC.INI
- // Save the value if the data source is new, if it was edited, or if
- // it was explicitly supplied
- if (hwndParent ||
- aAttr[KEY_DESC].fSupplied )
- WritePrivateProfileString(lpszDSN,
- INI_KDESC,
- aAttr[KEY_DESC].szAttr,
- ODBC_INI);
-
- if (hwndParent ||
- aAttr[KEY_OPT1].fSupplied )
- WritePrivateProfileString(lpszDSN,
- INI_KOPT1,
- (lstrcmpi(aAttr[KEY_OPT1].szAttr, OPTIONON)
- ? OPTIONOFF
- : OPTIONON),
- ODBC_INI);
-
- if (hwndParent ||
- aAttr[KEY_OPT2].fSupplied )
- WritePrivateProfileString(lpszDSN,
- INI_KOPT2,
- (lstrcmpi(aAttr[KEY_OPT2].szAttr, OPTIONON)
- ? OPTIONOFF
- : OPTIONON),
- ODBC_INI);
-
- // If the data source name has changed, remove the old name
- if (aAttr[KEY_DSN].fSupplied && lstrcmpi(szDSN, aAttr[KEY_DSN].szAttr)) {
- SQLRemoveDSNFromIni(szDSN);
- }
- return TRUE;
- }
-