Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python mmap:can';t在不知道其大小的情况下附加到现有区域(窗口)_Python_Windows_Mmap - Fatal编程技术网

Python mmap:can';t在不知道其大小的情况下附加到现有区域(窗口)

Python mmap:can';t在不知道其大小的情况下附加到现有区域(窗口),python,windows,mmap,Python,Windows,Mmap,我试图连接到另一个应用程序创建的现有共享内存区域,而不是用Python编写的(这就是它的插件模块相互通信的方式)。在Windows上,它使用命名的内核对象,而不是文件系统中的文件;Python的mmap模块通过标记名参数支持这一点。问题是我无法预先知道共享区域的大小-这是另一个应用程序的配置参数,根据预期的数据量进行调整。对于基于文件的共享区域,为大小传递零将使用文件的现有大小,但这显然不适用于标记区域。以下是我尝试的简化版本: import mmap, random TAGNAME = 'S

我试图连接到另一个应用程序创建的现有共享内存区域,而不是用Python编写的(这就是它的插件模块相互通信的方式)。在Windows上,它使用命名的内核对象,而不是文件系统中的文件;Python的mmap模块通过
标记名
参数支持这一点。问题是我无法预先知道共享区域的大小-这是另一个应用程序的配置参数,根据预期的数据量进行调整。对于基于文件的共享区域,为大小传递零将使用文件的现有大小,但这显然不适用于标记区域。以下是我尝试的简化版本:

import mmap, random

TAGNAME = 'SHM_1001'

# This is a simulation of what the other application does.
# The size isn't actually random, I simply don't know in advance what it is.
m1 = mmap.mmap(-1, random.randint(1e3, 1e6), TAGNAME)

# This is what I'm trying to do in my application, to attach to the same region.
m2 = mmap.mmap(-1, 0, TAGNAME)
# WindowsError: [Error 87] The parameter is incorrect
如果我指定一个小的非零大小,那么我可以成功地附加到该区域-但是当然,我只能访问该区域开始处的那么多字节。如果我指定的大小大于区域的实际大小(可能等于它所能拥有的最大大小),我会得到一个访问错误。这个问题在Python2.7和3.4中都存在


将大小传递为零的方法肯定在系统调用级别起作用——这正是此应用程序的每个现有C/C++插件的工作方式——因此问题显然出在Python的mmap()调用包装器中。有什么办法可以让它工作吗?

它应该是这样工作的:

如果长度大于文件的当前大小,则文件为 扩展为包含长度字节。如果长度为0,则为最大长度 映射的大小是文件的当前大小,但如果文件为 空窗口引发异常(无法创建空映射) 在Windows上)


但目前看来,这是一个已知的错误:

中的参数验证在调用系统服务之前出错,如果调用该服务,将找到现有的部分。当
hFile
无效时使用0 size\u HANDLE\u VALUE
(-1)无效,因为
CreateFileMapping
假定(在本例中错误地)需要从分页文件分配节。我假设C插件正在调用(即)

您可以使用ctypes、PyWin32或C扩展模块。调用
OpenFileMappingW
后,调用
MapViewOfFile
,然后调用
VirtualQuery
以获取映射的区域大小,四舍五入到页面边界

下面是一个使用ctypes的示例

from ctypes import *
from ctypes.wintypes import *

kernel32 = WinDLL('kernel32', use_last_error=True)

FILE_MAP_COPY       = 0x0001
FILE_MAP_WRITE      = 0x0002
FILE_MAP_READ       = 0x0004
FILE_MAP_ALL_ACCESS = 0x001f
FILE_MAP_EXECUTE    = 0x0020

PVOID = LPVOID
SIZE_T = c_size_t

class MEMORY_BASIC_INFORMATION(Structure):
    _fields_ = (('BaseAddress',       PVOID),
                ('AllocationBase',    PVOID),
                ('AllocationProtect', DWORD),
                ('RegionSize',        SIZE_T),
                ('State',             DWORD),
                ('Protect',           DWORD),
                ('Type',              DWORD))

PMEMORY_BASIC_INFORMATION = POINTER(MEMORY_BASIC_INFORMATION)

def errcheck_bool(result, func, args):
    if not result:
        raise WinError(get_last_error())
    return args

kernel32.VirtualQuery.errcheck = errcheck_bool
kernel32.VirtualQuery.restype = SIZE_T
kernel32.VirtualQuery.argtypes = (
    LPCVOID,                   # _In_opt_ lpAddress
    PMEMORY_BASIC_INFORMATION, # _Out_    lpBuffer
    SIZE_T)                    # _In_     dwLength

kernel32.OpenFileMappingW.errcheck = errcheck_bool
kernel32.OpenFileMappingW.restype = HANDLE
kernel32.OpenFileMappingW.argtypes = (
    DWORD,   # _In_ dwDesiredAccess
    BOOL,    # _In_ bInheritHandle
    LPCWSTR) # _In_ lpName

kernel32.MapViewOfFile.errcheck = errcheck_bool
kernel32.MapViewOfFile.restype = LPVOID
kernel32.MapViewOfFile.argtypes = (
    HANDLE, # _In_ hFileMappingObject
    DWORD,  # _In_ dwDesiredAccess
    DWORD,  # _In_ dwFileOffsetHigh
    DWORD,  # _In_ dwFileOffsetLow
    SIZE_T) # _In_ dwNumberOfBytesToMap

kernel32.CloseHandle.errcheck = errcheck_bool
kernel32.CloseHandle.argtypes = (HANDLE,)

if __name__ == '__main__':
    import mmap

    NPAGES = 9
    PAGE_SIZE = 4096

    TAGNAME = 'SHM_1001'
    mm1 = mmap.mmap(-1, PAGE_SIZE * NPAGES, TAGNAME)

    hMap = kernel32.OpenFileMappingW(FILE_MAP_ALL_ACCESS, False, TAGNAME)
    pBuf = kernel32.MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0)
    kernel32.CloseHandle(hMap)

    mbi = MEMORY_BASIC_INFORMATION()
    kernel32.VirtualQuery(pBuf, byref(mbi), PAGE_SIZE)

    assert divmod(mbi.RegionSize, PAGE_SIZE) == (NPAGES, 0)
    mm2 = (c_char * mbi.RegionSize).from_address(pBuf)

    # write using the mmap object
    mm1.seek(100)
    mm1.write(b'Windows')

    # read using the ctypes array
    assert mm2[100:107] == b'Windows'