【问题标题】:WinApi compression, decompression in python3WinApi压缩、python3中的解压
【发布时间】:2020-05-07 19:56:08
【问题描述】:

我有一个设计用于在 Windows 机器上运行的小型客户端应用程序。它是用 C/C++ 编写的(更多是用 C 语言)。我想让它保持小,因此我不想使用外部库并在客户端坚持使用 WinAPI。

另一方面,我有一个在 python3 中实现的后端服务器。在这里,我很乐意使用任何现有的库。现在我想添加压缩层来提高传输速度。我遇到的问题是WinAPI似乎只提供:

// source: https://docs.microsoft.com/en-us/windows/win32/cmpapi/using-the-compression-api
XPRESS
XPRESS with Huffman encoding 
MSZIP  
LZMS

这似乎是一个独特的微软压缩算法实现,我找不到在 python3 中解压缩服务器端数据的方法。

我有什么遗漏吗?我很想听听一些解决方案:)

提前致谢

更新

我决定按照评论中的建议使用 zlib https://zlib.net/。建议使用 ctypes 的答案也很有趣,但不幸的是我的后端是在 UNIX 系统上运行的。

当我再次使用多线程 CRT(而不是 DLL)编译我的客户端部分时,我遇到了一些问题,因为 zlib 正在与多线程 DLL 链接。如果有人遇到过这样的问题,我在这里找到了一个很棒且超级简单的解决方案:https://yongweiwu.wordpress.com/2017/10/02/a-journey-of-purely-static-linking/ 我会在这里复制粘贴:

zlib
This part requires a small change to the build script (for version 1.2.11).
I need to open win32\Makefile.msc and change all occurrences of ‘-MD’ to ‘-MT’. 
Then these commands will work:

nmake -f win32\Makefile.msc zlib.lib

【问题讨论】:

  • 我想保持小,因此我不想使用外部库并在客户端坚持使用 WinAPI -- 你试过zlib?..
  • 我不想使用外部库:/
  • zlib 是一组实现 flate 压缩算法的 C 代码,与 PDF、PNG、TIFF 文件等中使用的压缩相同。老实说,将其视为外部库是短视的。最终可执行文件的大小差异可能也很小(您可以将“C”源代码添加到您的项目中)。 this link 还建议 Python 支持 zlib。

标签: c++ c winapi compression


【解决方案1】:

我找到了this Python script,并对其进行了逆向工程以生成quick library to handle WinAPI Compression/Decompression。基本上,您可以使用ctypes 并从 Python 调用 WinAPI。请记住,我没有对此进行广泛的测试,但它应该给你一个很好的起点:)

编辑:根据要求,我已经包含了 compressdecompress 函数的实现,以防链接断开。

def compress(UncompressedBuffer, UncompressedBufferSize, Format, Engine):
    CompressedBuffer = (ctypes.c_ubyte * UncompressedBufferSize)()
    CompressionFormatAndEngine = ctypes.c_uint16(Format.value | Engine.value)

    CompressBufferWorkSpaceSize = ctypes.c_uint32()
    CompressFragmentWorkSpaceSize = ctypes.c_uint32()
    WorkSpace = (CompressFragmentWorkSpaceSize.value * ctypes.c_ubyte)()
    FinalCompressedSize = ctypes.c_uint32()

    WinDLLCall(RtlGetCompressionWorkSpaceSize,
               CompressionFormatAndEngine,
               ctypes.byref(CompressBufferWorkSpaceSize),
               ctypes.byref(CompressFragmentWorkSpaceSize))

    WinDLLCall(RtlCompressBuffer,
              CompressionFormatAndEngine,
              ctypes.byref(UncompressedBuffer),
              ctypes.c_uint32(UncompressedBufferSize),
              ctypes.byref(CompressedBuffer),
              ctypes.c_uint32(UncompressedBufferSize),
              UncompressedChunkSize,
              ctypes.byref(FinalCompressedSize),
              ctypes.byref(WorkSpace))

    return CompressedBuffer, FinalCompressedSize

def decompress(CompressedBuffer, CompressedBufferSize, UncompressedBufferSize, Format):
    UncompressedBuffer = (ctypes.c_ubyte * UncompressedBufferSize)()
    FinalUncompressedSize = ctypes.c_uint32()

    WinDLLCall(RtlDecompressBuffer,
               Format,
               ctypes.byref(UncompressedBuffer),
               ctypes.c_uint32(UncompressedBufferSize),
               ctypes.byref(CompressedBuffer),
               ctypes.c_uint32(CompressedBufferSize),
               ctypes.byref(FinalUncompressedSize))

    return UncompressedBuffer, FinalUncompressedSize

WinAPI 函数使用以下代码加载:

import ctypes

RtlDecompressBuffer = ctypes.windll.ntdll.RtlDecompressBuffer
RtlCompressBuffer = ctypes.windll.ntdll.RtlCompressBuffer
RtlGetCompressionWorkSpaceSize = ctypes.windll.ntdll.RtlGetCompressionWorkSpaceSize

如果您最终修补,这里还有一些其他有用的资源:

【讨论】:

  • 这归结为仅链接的答案。一旦你省略了链接,就没有有用的信息了。请参阅How do I write a good answer? 下的“为链接提供上下文” 段落并提供所需的更改。
  • 这实际上是一个很好的答案:) 我没有考虑过 ctypes,但我会的。仍然希望使用其他方法,因为我的后端在 unix 上运行,我必须从 windows 复制 dll。
  • @rob 您不能简单地从 Windows 复制内核模块并期望它在 Windows 以外的任何设备上运行。这在技术层面上是行不通的,而且还具有法律意义。
  • @RobD 正如@IInspectable 所述,复制 DLL 可能有点不靠谱,但我确实找到了这个名为 WIMLIB 的开源库,其中包含压缩算法的实现。该 API 看起来与 WinAPI 非常相似,如果您最终使用 ctypes,您可能只需稍作调整即可使其正常工作。
猜你喜欢
  • 2014-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多