P /调用基本CRT函数的问题(即putchar,puts)

时间:2010-11-21 20:14:02

标签: c# debugging interop pinvoke

我注意到一些非常奇怪的事情。我试图将CRT函数称为“putchar”,但无法使其工作。所以我仔细检查了我没有遗漏的东西,我直接从MSDN上的P / Invoke教程复制代码,看看它是否有效。

http://msdn.microsoft.com/en-us/library/aa288468%28VS.71%29.aspx

你会注意到他们导入了“put”。

所以我测试了从MSDN复制的确切代码。它没用!所以现在我感到沮丧。我以前从未遇到过这个问题。

然后我就这样碰巧运行没有调试(点击ctrl + f5),它运作正常!我测试了输出到控制台的其他函数,调试时它们都不起作用,但是在没有调试时都能正常工作。

然后我写了一个简单的C dll,它导出了一个名为“PrintChar(char c)”的函数。当我从C#调用该函数时,即使我正在调试它也没有任何问题。

这是什么处理?

2 个答案:

答案 0 :(得分:2)

这是一个糟糕的例子,使用C-Runtime Library DLL来调用puts。继续阅读教程,因为那里有很好的信息,但是尝试改为调用Win32 API。

以下是对p / invoke的更好介绍:http://msdn.microsoft.com/en-us/magazine/cc164123.aspx

它已经过时了,但信息仍然很好。

<强>被修改

我的解释是错误的。

我去寻找正确的解释,我发现C-Runtime puts方法和.NET Framework Console.Write方法在它们写入控制台的方式上有所不同(Console.Write适用于p / invoke to puts的位置不)。我想也许答案就在那里,所以我掀起了这个示威:

using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;

class Program
{
    public static void Main() 
    {
        int written;
        string outputString = "Hello, World!\r\n";
        byte[] outputBytes = Encoding.Default.GetBytes(outputString);

        //
        // This is the way the C-Runtime Library method puts does it

        IntPtr conOutHandle = CreateFile("CONOUT$", 0x40000000, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero);
        WriteConsole(conOutHandle, outputBytes, outputString.Length, out written, IntPtr.Zero);

        //
        // This is the way Console.Write does it

        IntPtr stdOutputHandle = GetStdHandle(STD_OUTPUT_HANDLE);
        WriteFile(stdOutputHandle, outputBytes, outputBytes.Length, out written, IntPtr.Zero);


        // Pause if running under debugger 
        if (Debugger.IsAttached)
        {
            Console.Write("Press any key to continue . . . ");
            Console.ReadKey();
        }
    }

    const int STD_OUTPUT_HANDLE = -11;

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr GetStdHandle(int nStdHandle);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern int WriteFile(IntPtr handle, [In] byte[] bytes, int numBytesToWrite, out int numBytesWritten, IntPtr mustBeZero);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    static extern IntPtr CreateFile(string lpFileName, int dwDesiredAccess, FileShare dwShareMode, IntPtr securityAttrs, FileMode dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile);

    [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
    static extern bool WriteConsole(IntPtr hConsoleOutput, [In] byte[] lpBuffer, int nNumberOfCharsToWrite, out int lpNumberOfCharsWritten, IntPtr mustBeZero);

}

这两个都在调试器下成功输出,即使启用了托管过程。所以这是一个死胡同。

我想分享一下,如果它导致别人弄清楚为什么它会发生 - 汉斯?

答案 1 :(得分:2)

Visual Studio托管过程能够将控制台输出重定向到“输出”窗口。究竟是如何设法完成的,根本没有记录,但它会妨碍这里。它拦截WriteFile()调用,该调用生成puts()。

的输出

Project + Properties,Debug选项卡,取消选中“启用Visual Studio托管过程”。在同一页面上,启用非托管调试也可以解决问题。