从非托管dll调用函数时出错

时间:2019-01-19 00:45:53

标签: c#

我找到了有关PTOpenProvider的文档,我希望从托管代码(https://docs.microsoft.com/en-us/windows/desktop/api/prntvpt/nf-prntvpt-ptopenprovider)中使用这些文档。

我已将PTOpenProvider声明为

/// <summary>
/// Opens an instance of a print ticket provider.
/// </summary>
/// <param name="pszPrinterName">A pointer to the full name of a print queue.</param>
/// <param name="dwVersion">The version of the Print Schema requested by the caller.</param>
/// <param name="phProvider">A pointer to a handle for the provider.</param>
/// <returns>If the operation succeeds, the return value is S_OK, otherwise the HRESULT contains an error code.</returns>
[DllImport("Prntvpt.dll")]
public static extern IntPtr PTOpenProvider(string pszPrinterName, uint dwVersion,IntPtr phProvider);

并命名为

var printerName = "Foxit Reader PDF Printer";           
IntPtr providerPointer = new IntPtr();
IntPtr result = MethodDeclarations.PTOpenProvider(printerName, 1,       providerPointer);

我收到结果0x80070057,据我了解,该结果指示错误。 问题是:如何获得人类可读的错误描述,以及通常应该怎样调试此类代码(从托管代码中调用非托管函数)。 欢迎链接到有用的文章。 谢谢!

2 个答案:

答案 0 :(得分:2)

您可以在Microsoft's dev website上查找

COM特定的错误代码。

您的特定错误0x80070057generic COM error E_INVALIDARG,基本上一个或多个参数无效。

要回答您的问题,人类可读的描述完全取决于所述图书馆的设计者是否可以记录。 COM调用通常会提供有关发生错误时应去向何方的良好文档,但要查找起来可能很棘手。

在调试错误时,这再次取决于库随附的文档。

TL; DR

查看文档,或通过Google搜索。您是图书馆创造者的摆布。

答案 1 :(得分:0)

导入的函数的声明不正确。有两个错误:

  1. 您需要将第三个参数声明为ref参数,因为该函数需要指向该句柄的指针。 (在这种情况下,我用光了)
  2. 您需要明确声明第一个参数是PWStr。

经过测试的代码:

public enum HRESULT : uint
{
    S_FALSE = 0x0001,
    S_OK = 0x0000,
    E_INVALIDARG = 0x80070057,
    E_OUTOFMEMORY = 0x8007000E,
    E_INVALID_PRINTER_NAME = 0x80070709
}

[DllImport("Prntvpt.dll")]
public static extern HRESULT PTOpenProvider(
    [MarshalAs(UnmanagedType.LPWStr)]string pszPrinterName, 
    uint dwVersion, 
    [Out] out IntPtr phProvider);

[DllImport("Prntvpt.dll")]
public static extern HRESULT PTCloseProvider(
    IntPtr hProvider
);


private void button1_Click(object sender, EventArgs e)
{
    var printerName = @"Fax";
    IntPtr providerHandle;
    HRESULT result = PTOpenProvider(printerName, 1, out providerHandle);

    if(result == HRESULT.S_OK)
    {
        MessageBox.Show("OK. Handled obtained: " + providerHandle);

        PTCloseProvider(providerHandle);
    }
    else
    {
        MessageBox.Show("Error: " + result);
    }
}