代码之家  ›  专栏  ›  技术社区  ›  user53794

从C调用.dll时出现奇怪的问题#

  •  1
  • user53794  · 技术社区  · 15 年前

    我正试图从C调用htmltidy库dll。有几个例子在网上流传,但没有确定的…我的麻烦还没有结束。我很确定问题出在P/Invoke声明上…但如果我知道我在哪里出了问题,我就会犹豫。

    我从中得到libtidy.dll http://www.paehl.com/open_source/?HTML_Tidy_for_Windows 这似乎是最新版本。

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

    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";
            }
        }
    }
    

    总之,我有点头疼。任何帮助都将不胜感激!

    3 回复  |  直到 15 年前
        1
  •  3
  •   Stephen Martin    15 年前

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

        [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        
        };        
    
        2
  •  2
  •   core    15 年前

    值得一提的是,我们在工作时试着整理一下,然后换成了htmlagilitypack。

        3
  •  0
  •   Ash    15 年前

    尝试将TidyBuffalloc声明更改为:

    [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。

    在您的示例中,如果inputtml很大,例如50k,则inputaray和inputaray2也将分别为50k。

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

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