【问题标题】:Calling unmanaged code from .NET从 .NET 调用非托管代码
【发布时间】:2011-02-05 19:33:03
【问题描述】:

我试图在我的 c# 程序中使用一个 dll,但我似乎无法让它工作。我制作了一个如下所示的测试应用程序。返回值为 0,但它实际上并没有做它应该做的事情。

而以下命令确实有效:

rundll32 cmproxy.dll,SetProxy /source_filename proxy-1.txt /backup_filename roxy.bak /DialRasEntry NULL /TunnelRasEntry DSLVPN /Profile "C:\Documents and ettings\Administrator\Application Data\Microsoft\Network\Connections\Cm\dslvpn.cmp"

代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using System.Net;
using WUApiLib;

namespace nac
{
    class Program
    {
        [DllImport("cmproxy.dll", CharSet = CharSet.Unicode)]
        static extern int SetProxy(string cmdLine);

        static void Main(string[] args)
        {
            string cmdLine = @"/source_filename proxy-1.txt /backup_filename proxy.bak /DialRasEntry NULL /TunnelRasEntry DSLVPN /Profile ""C:\Documents and Settings\Administrator\Application Data\Microsoft\Network\Connections\Cm\dslvpn.cmp""";
            Console.WriteLine(SetProxy(cmdLine));
        }
    }
}

这里是 dumpbin /exports 命令的内容

File Type: DLL

  Section contains the following exports for cmproxy.dll

    00000000 characteristics
    3E7FEF8C time date stamp Tue Mar 25 05:56:28 2003
        0.00 version
           1 ordinal base
           1 number of functions
           1 number of names

    ordinal hint RVA      name

          1    0 00001B68 SetProxy

  Summary

        1000 .data
        1000 .reloc
        1000 .rsrc
        2000 .text

当它工作时,它会为 VPN 连接设置代理服务器。

编辑:

我希望避免从 system.process 运行 rundll32

我还可以提供指向 dll 和我的测试应用程序的链接。虽然上面粘贴的代码就是它所包含的全部内容,并且我认为可以从服务器资源工具包中获得 dll。

更新:

我用 C++ 编写了一个测试 DLL,它简单地回显了它给出的参数。它正在运行,但它说

句柄无效

【问题讨论】:

  • cmproxy.dll 的 .h 是什么样的?
  • 我同意 Per,看看 SetProxy 的函数签名会很有帮助。
  • dll不是我写的,是微软提供的。有没有办法在没有源的情况下获取 .h 文件?
  • 尝试使用 Visual Studio 中的对象浏览器打开 DLL。如果它有效,您将能够查看 DLL 公开的内容,然后查看函数签名。可能 SetProxy 函数签名与您在代码中定义它的方式不同。
  • 表示无法浏览该dll。有趣的是它返回 0,所以人们会假设它有效并且命令行有问题。但是命令行使用rundll32工作,所以我想知道我是否没有正确形成命令行,或者它需要是不同的类型或其他东西

标签: c# dll unmanaged


【解决方案1】:

只是一些思考的食物。这可能是一种可能的解决方法。

也许您可以使用 System.Diagnostics.Process 类从您的代码中运行命令,如下所示:

  System.Diagnostics.Process p = new System.Diagnostics.Process();
  p.StartInfo.Arguments = @"cmproxy.dll,SetProxy /source_filename proxy-1.txt /backup_filename roxy.bak /DialRasEntry NULL /TunnelRasEntry DSLVPN /Profile ""C:\Documents and ettings\Administrator\Application Data\Microsoft\Network\Connections\Cm\dslvpn.cmp\""";
  p.StartInfo.FileName = "rundll32";
  p.Start();

如果您需要在运行时替换一些参数,那么您可以使用 String.Format 来格式化参数并替换您需要的任何内容。

编辑 1:

这里似乎没有正确突出显示代码。我没有 cmproxy.dll,所以我无法测试这个场景。

【讨论】:

  • 对不起,我应该在 OP 中提到这一点,我还没有尝试过,但我认为它确实有效,但我试图避免使用这种方法。
【解决方案2】:

也许Microsoft documentation on RUNDLL32.EXE 会有所帮助?特别是,这部分似乎很有用:

Rundll 入口的参数 要点如下:

hwnd - 应用作所有者窗口的窗口句柄 您的 DLL 创建的任何窗口 hinst - 你的 DLL 的实例句柄 lpszCmdLine - 你的 DLL 应该解析的 ASCIIZ 命令行 nCmdShow - 描述 DLL 的窗口应该如何显示

在以下示例中:

RUNDLL.EXE SETUPX.DLL,InstallHinfSection 132 C:\WINDOWS\INF\SHELL.INF

Rundll 会调用 InstallHinfSection() 入口点 Setupx.dll 中的函数并将其传递给 以下参数:

hwnd = (父窗口句柄) hinst = SETUPX.DLL 的 HINSTANCE lpszCmdLine = "132 C:\WINDOWS\INF\SHELL.INF" nCmdShow = (无论 nCmdShow 被传递给 CreateProcess)

更新 2

这应该适合你:

[DllImport("cmproxy.dll", SetLastError = true, CharSet = CharSet.Unicode)] 
static extern void SetProxy(IntPtr hwnd, IntPtr hinst, string lpszCmdLine, int nCmdShow);

然后这样称呼它:

const int SW_SHOWNORMAL = 1;
IntPtr hWnd = (this as Form).Handle;
IntPtr hInstance = Marshal.GetHINSTANCE(this.GetType().Module);
SetProxy(hWnd, hInstance, cmdLine, SW_SHOWNORMAL);

我使用 shell32.dll 中的 Control_RunDLL 入口点测试了相同的代码,我可以确认它对我来说工作正常。诀窍是让正确的 HWND 和 HINSTANCE 指针作为前两个参数传入。另外,我之前为 nCmdShow 传递了 0,但 according to pinvoke.net,SW_SHOWNORMAL 的值为 1,这可能是您想要的。

【讨论】:

  • 我已经读过这篇文章,不幸的是它对我没有任何启发。我想知道我是否需要更改命令行参数的类型?
  • @Charles Gargent:我刚刚编辑了我的答案。 P/Invoke 代码示例有帮助吗?
  • 我们显然是在同时打字 :) 我已经尝试过您的编辑,但仍然没有变化。我也通过设置 EntryPoint = SetProxy 进行了尝试。还是没有区别。也许 MS 的人会看到这个并给我们答案!
  • @Charles Gargent:好的,看起来这是 hWnd 和 hInstance 参数的问题。我以前只是为那些传递 NULL,但它看起来对某些 DLL 不起作用,所以我添加了代码来展示如何获取有效的窗口和实例句柄。有了这个改变,我可以让它在 shell32.dll 中调用 RunDll 入口点,所以我很有信心这对你现在有用。
  • 恐怕没什么区别。
【解决方案3】:

答案是 CharSet = CharSet.Unicode 应该是 CharSet = CharSet.Ansi

【讨论】:

  • 您能给我们启发吗?你怎么知道的?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-24
  • 2012-01-14
  • 2015-02-24
  • 1970-01-01
  • 2010-09-18
  • 1970-01-01
  • 2013-12-29
相关资源
最近更新 更多