1

我正在尝试从 C# 调用 HtmlTidy 库 dll。网上流传着一些例子,但没有确定的……而且我遇到了无穷无尽的麻烦。我很确定问题出在 p/invoke 声明上……但如果我知道我哪里出错了,那就危险了。

我从http://www.paehl.com/open_source/?HTML_Tidy_for_Windows获得了 libtidy.dll,这似乎是当前版本。

这是一个控制台应用程序,演示了我遇到的问题:

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace ConsoleApplication5
{
    class Program
    {
        [StructLayout(LayoutKind.Sequential)]
        public struct TidyBuffer
        {
            public IntPtr bp;         // Pointer to bytes
            public uint size;         // # bytes currently in use
            public uint allocated;    // # bytes allocated
            public uint next;         // Offset of current input position
        };

        [DllImport("libtidy.dll")]
        public static extern int tidyBufAlloc(ref TidyBuffer tidyBuffer, uint allocSize);


        static void Main(string[] args)
        {
            Console.WriteLine(CleanHtml("<html><body><p>Hello World!</p></body></html>"));
        }

        static string CleanHtml(string inputHtml)
        {
            byte[] inputArray = Encoding.UTF8.GetBytes(inputHtml);
            byte[] inputArray2 = Encoding.UTF8.GetBytes(inputHtml);

            TidyBuffer tidyBuffer2;
            tidyBuffer2.size = 0;
            tidyBuffer2.allocated = 0;
            tidyBuffer2.next = 0;
            tidyBuffer2.bp = IntPtr.Zero;

            //
            // tidyBufAlloc overwrites inputArray2... why? how? seems like
            // tidyBufAlloc is stomping on the stack a bit too much... but
            // how? I've tried changing the calling convention to cdecl and
            // stdcall but no change.
            //
            Console.WriteLine((inputArray2 == null ? "Array2 null" : "Array2 not null"));
            tidyBufAlloc(ref tidyBuffer2, 65535);
            Console.WriteLine((inputArray2 == null ? "Array2 null" : "Array2 not null"));
            return "did nothing";
        }
    }
}

总而言之,我有点难过。任何帮助,将不胜感激!

4

3 回答 3

3

您正在使用 TidyBuffer 结构的旧定义。新结构更大,因此当您调用 allocate 方法时,它会覆盖 inputArray2 的堆栈位置。新定义是:

    [StructLayout(LayoutKind.Sequential)]        
    public struct TidyBuffer        
    {
        public IntPtr allocator;  // Pointer to custom allocator            
        public IntPtr bp;         // Pointer to bytes            
        public uint size;         // # bytes currently in use            
        public uint allocated;    // # bytes allocated            
        public uint next;         // Offset of current input position        
    };        
于 2009-05-17T12:46:31.860 回答
2

对于它的价值,我们在工作中尝试了 Tidy 并切换到 HtmlAgilityPack。

于 2009-05-09T05:44:16.933 回答
0

尝试将您的 tidyBufAlloc 声明更改为:

[DllImport("libtidy.dll", CharSet = CharSet.Ansi)]
private static extern int tidyBufAlloc(ref TidyBuffer Buffer, int allocSize);

注意 CharSet.Ansi 添加和“int allocSize”(而不是 uint)。

此外,请参阅此示例代码以获取在 C# 中使用 HTML Tidy 的示例。

在您的示例中,如果 inputHTML 很大,例如 50K,则 inputArray 和 inputArray2 也将分别为 50K。

然后,您还尝试在 tidyBufAlloc 调用中分配 65K。

如果指针未正确初始化,则很有可能正在使用随机的 .NET 堆地址。因此会覆盖部分或全部看似无关的变量/缓冲区。很可能只是运气,或者您已经分配了大缓冲区,您没有覆盖可能导致无效内存访问错误的代码块。

于 2009-05-09T04:58:06.497 回答