RtlCompressBuffer API в C # - PullRequest
       9

RtlCompressBuffer API в C #

5 голосов
/ 17 июля 2011

Я пытаюсь использовать функции RtlGetCompressionWorkSpaceSize и RtlCompressBuffer в проекте C #.

Вот что у меня есть:

class Program
{
    const uint COMPRESSION_FORMAT_LZNT1 = 2;
    const uint COMPRESSION_ENGINE_MAXIMUM = 0x100;

    [DllImport("ntdll.dll")]
    static extern uint RtlGetCompressionWorkSpaceSize(uint CompressionFormat, out uint pNeededBufferSize, out uint Unknown);

    [DllImport("ntdll.dll")]
    static extern uint RtlCompressBuffer(uint CompressionFormat, byte[] SourceBuffer, uint SourceBufferLength, out byte[] DestinationBuffer,
        uint DestinationBufferLength, uint Unknown, out uint pDestinationSize, IntPtr WorkspaceBuffer);

    static void Main(string[] args)
    {
        uint dwSize = 0;
        uint dwRet = 0;
        uint ret = RtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_MAXIMUM, out dwSize, out dwRet);

        IntPtr pMem = Marshal.AllocHGlobal((int)dwSize);
        byte[] buffer = new byte[1024];
        byte[] outBuf = new byte[1024];
        uint destSize = 0;
        ret = RtlCompressBuffer(COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_MAXIMUM, buffer, 1024, out outBuf, 1024, 0, out destSize, pMem);

        Console.Write(ret.ToString());
        Console.Read();
    }
}

RtlGetCompressionWorkSpaceSize работает, так как возвращает 0 (NTкод успеха), но когда я вызываю RtlCompressBuffer, я получаю ошибку нарушения доступа к памяти.

РЕДАКТИРОВАТЬ: С помощью ответа Дэвида я исправил проблему, и правильный код приведен ниже.

    const ushort COMPRESSION_FORMAT_LZNT1 = 2;
    const ushort COMPRESSION_ENGINE_MAXIMUM = 0x100;

    [DllImport("ntdll.dll")]
    static extern uint RtlGetCompressionWorkSpaceSize(ushort CompressionFormat, out uint pNeededBufferSize, out uint Unknown);

    [DllImport("ntdll.dll")]
    static extern uint RtlCompressBuffer(ushort CompressionFormat, byte[] SourceBuffer, int SourceBufferLength, byte[] DestinationBuffer,
        int DestinationBufferLength, uint Unknown, out int pDestinationSize, IntPtr WorkspaceBuffer);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    internal static extern IntPtr LocalAlloc(int uFlags, IntPtr sizetdwBytes);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr LocalFree(IntPtr hMem);

    internal static byte[] Compress(byte[] buffer)
    {
        var outBuf = new byte[buffer.Length * 6];
        uint dwSize = 0, dwRet = 0;
        uint ret = RtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_MAXIMUM, out dwSize, out dwRet);
        if (ret != 0)
        {
            return null;
        }

        int dstSize = 0;
        IntPtr hWork = LocalAlloc(0, new IntPtr(dwSize));
        ret = RtlCompressBuffer(COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_MAXIMUM, buffer,
            buffer.Length, outBuf, outBuf.Length, 0, out dstSize, hWork);
        if (ret != 0)
        {
            return null;
        }

        LocalFree(hWork);

        Array.Resize(ref outBuf, dstSize);
        return outBuf;
    }

1 Ответ

5 голосов
/ 17 июля 2011

Вы очень близко к этому. Проблема в том, что эта часть вашего P / invoke для RtlCompressBuffer:

out byte[] DestinationBuffer

Маршаллинг по умолчанию для byte[] предназначен для маршалинга содержимого массива в обоих направлениях, от управляемого к неуправляемому, а затем обратно, когда функция возвращается. Определение C RtlCompressBuffer помечено __out, но это означает, что содержимое массива __out, а не указатель __out.

Измените ваш P / invoke на

byte[] DestinationBuffer

и аналогичным образом при звонке на RtlCompressBuffer измените out outBuf на outBuf, и вам будет хорошо идти.

Имейте в виду, что ваш код в текущем состоянии вернет код состояния STATUS_BUFFER_ALL_ZEROS, поэтому не думайте, что это ненулевое возвращаемое значение указывает на ошибку.

Одна конечная точка, первый параметр для обоих вызовов P /, CompressionFormat, должна быть объявлена ​​как ushort.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...