odbc_installer / calldll: infinite loop encountered

Thomas Heller theller at python.net
Thu Feb 6 15:36:16 EST 2003


"David" <dlashar at sprynet.com> writes:

> > Would it be a good idea to port the odbc stuff from calldll to ctypes?
> > I would try to give all support I can, but I cannot do it alone.
> 
> As noted in a separate but related posting, I am brand new to this technique
> of making C calls via Python.  But, yes, that's precisely what I'm seeking
> to do... and it's only a few methods on seemingly a single dll that need to
> be called in order to make a DSN entry.  I'm not by any means certain (this
> is terra incognita for me!), but it seems that it's odbccp32.dll that
> exposes the necessary methods, which seem to be SQLConfigDataSource,
> SQLInstallDriverEx, and SQLConfigDriver.  Details for the genuinely
> knowledgeable are in the ODBC Programmer's Reference:
> 
> http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/da
> sdkodbcoverview_whatsnew.asp.
> 
> Hope that helps, i.e., clarifies the need.  And apologies if this is too
> Win-related.  I'm just trying to put as much of my app in Python as I can.
> Thanks,
> 

Here is a simple module which wraps the SQLConfigDriver and
SQLConfigDataSource functions:

----- snip -----
from ctypes import windll, c_int, byref, c_string

odbccp32 = windll.odbccp32
user32 = windll.user32

class ODBCError(Exception):
    pass

def _ODBCInstallerBool(result):
    if result == 0:
        # integer to store the error code
        err_code = c_int()
        # 256 byte buffer for error message
        err_message = c_string("\000" * 256)
        err_msg_len = c_int()
        result = odbccp32.SQLInstallerError(1,
                                            byref(err_code),
                                            err_message,
                                            len(err_message),
                                            byref(err_msg_len))
        if result == 0:
            raise ODBCError, (err_code.value, err_message.value)
        else:
            raise ODBCError, "Unknown error"

# use the _ODBCInstallerBool function to check for errors
odbccp32.SQLConfigDataSource.restype = _ODBCInstallerBool

def SQLConfigDataSource(hwnd, request, driver, attributes):
    odbccp32.SQLConfigDataSource(hwnd, request, driver, attributes)

msg = c_string("\000" * 256)
msgout = c_int()

# use the _ODBCInstallerBool function to check for errors
odbccp32.SQLConfigDriver.restype = _ODBCInstallerBool

def SQLConfigDriver(hwnd, request, driver, args):
    msg = c_string("\000" * 256)
    msgout = c_int()
    odbccp32.SQLConfigDriver(0, request, driver, args,
                             msg, len(msg), byref(msgout))
    return msg.value

ODBC_ADD_DSN = 1

ODBC_CONFIG_DRIVER = 3
----- EOF -----

You can use it in this way:

>>> from sql_config import * # not good style, but...
>>> SQLConfigDriver(0, ODBC_CONFIG_DRIVER,
...                 "Silly driver", "CPTimeout=20")
Traceback (most recent call last):
  File "<stdin>", line 2, in ?
  File "sql_config.py", line 42, in SQLConfigDriver
    msg, len(msg), byref(msgout))
  File "sql_config.py", line 22, in _ODBCInstallerBool
    raise ODBCError, (err_code.value, err_message.value)
sql_config.ODBCError: (6, 'Component not found in the registry')
>>> SQLConfigDriver(0, ODBC_CONFIG_DRIVER,
...                 "Microsoft Access Driver (*.mdb)", "CPTimeout=20")
''
>>> SQLConfigDataSource(0, ODBC_ADD_DSN,
...                 "Microsoft Access Driver (*.mdb)", "foo=spam")
Traceback (most recent call last):
  File "<stdin>", line 2, in ?
  File "sql_config.py", line 30, in SQLConfigDataSource
    odbccp32.SQLConfigDataSource(hwnd, request, driver, attributes)
  File "sql_config.py", line 22, in _ODBCInstallerBool
    raise ODBCError, (err_code.value, err_message.value)
sql_config.ODBCError: (9, 'Invalid DSN')
>>> SQLConfigDataSource(0, ODBC_ADD_DSN,
...                 "Microsoft Access Driver (*.mdb)",
...                 "DSN=New Data Source\0Description=Hi\0")
>>>

I wish I had more time to explain this, but hopefully you are
able to figure it out yourself.

Thomas




More information about the Python-list mailing list