How to use SQLInstallDriverEx in C#?

那年仲夏 提交于 2019-12-23 17:48:03

问题


How would I rewrite the following function in order to use it in C#? The function is part of odbccp32.dll and is used to install an ODBC driver.

BOOL SQLInstallDriverEx(  
     LPCSTR    lpszDriver,  
     LPCSTR    lpszPathIn,  
     LPSTR     lpszPathOut,  
     WORD      cbPathOutMax,  
     WORD *    pcbPathOut,  
     WORD      fRequest,  
     LPDWORD   lpdwUsageCount);

SQLInstallDriverEx Reference

This is my attempt:

 [DllImport("odbccp32")]
 private static extern bool SQLInstallDriverEx(
      string lpszDriver,
      string lpszPathIn,
      out string lpszPathOut,
      ushort cbPathOutMax,
      out uint pcbPathOut,
      ushort fRequest,
      out uint lpdwUsageCount);

A sample usage would be deeply appreciated as well.


回答1:


p/Invoke Toolkit generates the following:

[DllImport("odbccp32.dll")]
public static extern  bool SQLInstallDriverEx(
     [In, MarshalAs(UnmanagedType.LPStr)] string lpszDriver, 
     [In, MarshalAs(UnmanagedType.LPStr)] string lpszPathIn,
     [MarshalAs(UnmanagedType.LPStr)] System.Text.StringBuilder lpszPathOut, 
     ushort cbPathOutMax, ref ushort pcbPathOut, ushort fRequest, ref uint lpdwUsageCount);

public const ushort ODBC_INSTALL_INQUIRY = 1;
public const ushort ODBC_INSTALL_COMPLETE = 2;

The In/MarshalAs attributes may not be necessary. StringBuilders work for "out" strings as the marshaller knows how to convert under the hood. You need to call the method twice, once to resolve the path/path length and the second to pass those values in. That step can be skipped if you know these before hand, but the path can change from what you provide if the driver already exists or the path is too long. The second call requires that the lpszPathOut be non-null and cbPathOutMax be non-zero.

The driver description that you pass to the method is made up of a list of null-byte terminated strings. The list is terminated with a double null.

// if target path is null, it should default to the system directory
var targetPath = @"c:\windows\system32";
ushort len = 0; uint usageCount=0;

// replace this with your actual driver description, note the double \0 at the end
var driver = "Text\0Driver=TEXT.DLL\0Setup=TXTSETUP.DLL\0FileUsage=1\0"
           + "FileExtns=*.txt,*.csv\0\0";

var ret = SQLInstallDriverEx(driver, targetPath, null, 0, 
                 ref len, ODBC_INSTALL_INQUIRY, ref usageCount);
if (ret) {
    var sbPath = new StringBuilder(len);
    if (ret = SQLInstallDriverEx(driver, targetPath, sbPath, len, 
                 ref len, ODBC_INSTALL_COMPLETE, ref usageCount)) {

        // sbPath will now contain the actual path, which may be different 
        // if there is a previous installation or the path was truncated
        // perhaps check here if that was intended

        // usageCount will be updated by the system
   }
}

if (!ret) {
    // query SqlInstallerError(...) here
}

If the return value is false, you will need to call the SqlInstallerError method which you will have to import as well. Fortunately there is a p/invoke page for this method and how to call it available at http://www.pinvoke.net/default.aspx/odbccp32/SQLInstallerError.html. The error codes and what they mean are already outlined on the MSDN page you linked.

Note that you can skip the two-phase method call and call with ODBC_INSTALL_COMPLETE once, provided you have provided correct buffer/sizes.



来源:https://stackoverflow.com/questions/42683787/how-to-use-sqlinstalldriverex-in-c

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!