Странная проблема вызова .DLL из C # - PullRequest
1 голос
/ 09 мая 2009

Я пытаюсь вызвать библиотеку HtmlTidy из C #. В сети есть несколько примеров, но ничего определенного нет ... и у меня нет проблем. Я почти уверен, что проблема в объявлении 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 ]

3 голосов
/ 17 мая 2009

Вы работаете со старым определением структуры 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        
    };        
2 голосов
/ 09 мая 2009

Для чего бы то ни было, мы попробовали Tidy на работе и переключились на HtmlAgilityPack.

0 голосов
/ 09 мая 2009

Попробуйте изменить объявление tidyBufAlloc на:

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

Обратите внимание на дополнение CharSet.Ansi и "int allocSize" (вместо uint).

Также, посмотрите этот пример кода для примера использования HTML Tidy в C #.

В вашем примере, если inputHTML большой, скажем, 50K, inputArray и inputArray2 также будут иметь размер 50K каждый.

Затем вы также пытаетесь выделить 65 КБ в вызове tidyBufAlloc.

Если указатель не инициализирован правильно, вполне возможно, что используется случайный адрес кучи .NET. Следовательно, происходит перезапись части или всей кажущейся не связанной переменной / буфера. Вероятно, вам просто повезло, или вы уже выделили большие буферы, что вы не перезаписываете блок кода, который может вызвать ошибку доступа к недействительной памяти.

...