【问题标题】:How to use function SQLGetPrivateProfileString from odbccp32.dll, using Delphi如何使用 odbccp32.dll 中的函数 SQLGetPrivateProfileString,使用 Delphi
【发布时间】:2016-07-13 17:07:08
【问题描述】:

我发现这个讨论帖可以追溯到 2004 年:

Calling SQLDataSources

它展示了如何在不直接进入注册表的情况下检索 DSN 条目列表。

到目前为止,Delphi 没有问题。顺便说一句,我在 Windows 7 上使用 Delphi 2007。

现在,我只想选择引用 MS Access 数据库的条目,所以我尝试在示例中只添加几行。

首先我声明了这一点:

function SQLGetPrivateProfileString( 
  lpszSection, lpszEntry, lpszDefault, lpszRetBuffer: PChar; 
  cbRetBuffer: Integer; 
  lpszFilename: PChar): integer; stdcall; 

并且正在实施中:

function SQLGetPrivateProfileString; external 'odbccp32.dll' name 'SQLGetPrivateProfileString'; 

然后我在示例中间的某处添加了以下行:

Result := SQLGetPrivateProfileString('ODBC Data Sources', Buffer1, 'Driver', RetBuf, 100, 'odbc.ini'); 

RetBuf 声明为PChar

我能够检索驱动程序字符串,如注册表中 ODBC 下所示。调用 GetMemFreeMem 来初始化和清理 RetBuf 似乎对保持我的程序稳定至关重要。

我的问题是:如何检索所涉及的*.MDB 文件(或*.ACCDB 文件)的路径。我试过这个无济于事:

SQLGetPrivateProfileString(nil, Buffer1, 'DBQ', RetBuf, 128, 'odbc.ini')

当然,我对SQLGetPrivateProfileString() 函数的一个好的替代方案很感兴趣。

任何帮助将不胜感激。

附:我在“comp.lang.pascal.delphi.databases”新闻组中交叉发布了一个类似的问题,抱歉。

【问题讨论】:

  • 究竟是什么问题。您的代码中有错误,但您没有显示任何代码,甚至没有进行任何调试。
  • 指定 Delphi 版本。我想知道你是否被 Unicode vs ansi 字符串和字符误导了......
  • 显示的声明适用于 Delphi 2007 和更早版本,其中 PCharPAnsiChar,但不适用于 Delphi 2009+,其中 PCharPWideCharSQLGetPrivateProfileString() 不接受 Unicode 字符串,只接受 Ansi 字符串,因此您应该明确使用 PAnsiChar 而不是一般的 PChar
  • 我猜你在连接数据库之前需要文件的路径?因为一旦连接上,您就可以使用属性SQL_DATA_SOURCE_NAME 调用SQLGetInfo(),它将保存mdb 文件的路径。

标签: windows delphi ms-access odbc dsn


【解决方案1】:

感谢大家的所有建议。是的,我打算将它用于允许用户选择数据库文件(*.MDB 或 *.ACCDB)的程序,即在连接到任何数据库之前。关于函数 SQLGetPrivateProfileString:由于它的参数 lpszDefault,我特别困惑。我已经意识到为这个参数提供一个空字符串就足够了。应要求,我在下面添加我的代码(删除了一些细节)。对于高于 2007 的 Delphi 版本,需要调整一些内容。

const 
  SQL_SUCCESS = 0;
  SQL_NO_DATA = 100;
  SQL_FETCH_NEXT = 1;
  SQL_FETCH_FIRST = 2
  SQL_MAX_DSN_LENGTH = 32;
  SQL_MAX_OPTION_STRING_LENGTH = 256;

procedure TForm1.Button2Click(Sender: TObject);
var
  EnvironmentHandle: Pointer;;
  Buffer1: array[0..SQL_MAX_DSN_LENGTH] of Char;
  Buffer2: array[0..SQL_MAX_OPTION_STRING_LENGTH] of Char;
  RetBuf1, RetBuf2: PChar;
  Len1, Len2: SmallInt;
  DataSourceName, DriverName, PathToFile: string;
  Result, i: Integer;
begin
  if SQLAllocEnv(EnvironmentHandle) = SQL_SUCCESS then
  try
    try
      i := 0;
      Result := SQLDataSources(EnvironmentHandle, SQL_FETCH_FIRST, Buffer1, SizeOf(Buffer1), Len1, Buffer2, SizeOf(Buffer2), Len2);
      if Result = SQL_SUCCESS then
      repeat
        try
          // Initialise
          DataSourceName := '';
          DriverName := '';
          PathToFile := '';

          // Prepare to find out about the driver
          SetString(DataSourceName, Buffer1, Len1);
          GetMem(RetBuf1, 200);
          Result := SQLGetPrivateProfileString('ODBC Data Sources', Buffer1, '', RetBuf1, 200, 'odbc.ini');

          // If it went well, then only show the result when it's an Access database
          if Result > 0 then
          begin
            if (Pos('access', LowerCase(RetBuf1)) > 0) then
            begin
              // Get the driver of the current DSN entry
              SetString(DriverName, RetBuf1, Result);

              // Try to retrieve the path to the file
              if (Pos('access', LowerCase(RetBuf1)) > 0) then
              begin
                // The Access database files are registered with key 'DBQ'              
                GetMem(RetBuf2, 200);
                Result := SQLGetPrivateProfileString(Buffer1, 'DBQ', '', RetBuf2, 200, 'odbc.ini')
                if Result > 0 then
                begin
                  SetString(PathToFile, RetBuf2, Result);
                  if Pos('~', PathToFile) > 0 then PathToFile := WinapiGetLongPathName(PathToFile);
                end;
                FreeMem(RetBuf2);

                // Arrange the output, if it's relevant
                if not FileExists(PathToFile) then Continue;
                AdvStringGrid1.Cells[0, i + 1] := DataSourceName;
                AdvStringGrid1.Cells[1, i + 1] := DriverName;
                AdvStringGrid1.Cells[2, i + 1] := PathToFile;
                AdvStringGrid1.RowCount := i + 2;
                Inc(i);
              end;
            end;
          end;

          // Prepare for the next loop
          FreeMem(RetBuf1);
        finally
          Result := SQLDataSources(EnvironmentHandle, SQL_FETCH_NEXT, Buffer1, SizeOf(Buffer1), Len1, Buffer2, SizeOf(Buffer2), Len2);
        end;
      until (Result = SQL_NO_DATA)

     except on E:Exception do
      ShowMessage(E.Message);
    end;
  finally
    SQLFreeEnv(EnvironmentHandle);
  end;
end;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-27
    • 2023-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多