我正在尝试从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";
}
}
}
总而言之,我有点难过。任何帮助将不胜感激!
答案 0 :(得分: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
};
答案 1 :(得分:2)
为了它的价值,我们在工作中尝试了Tidy并切换到HtmlAgilityPack。
答案 2 :(得分:0)
尝试将tidyBufAlloc声明更改为:
[DllImport("libtidy.dll", CharSet = CharSet.Ansi)]
private static extern int tidyBufAlloc(ref TidyBuffer Buffer, int allocSize);
注意CharSet.Ansi的添加和“int allocSize”(而不是uint)。
另外,请参阅此sample code以获取在C#中使用HTML Tidy的示例。
在你的例子中,如果inputHTML很大,比如50K,inputArray和inputArray2也将是50K。
然后您还尝试在tidyBufAlloc调用中分配65K。
如果指针未正确初始化,则很可能使用随机的.NET堆地址。因此,重写部分或全部看似无关的变量/缓冲区。只是好运,或者您已经分配了大缓冲区,您没有覆盖可能导致无效内存访问错误的代码块。