问题
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. StringBuilder
s 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