銀月の符号

Python 使い見習いの日記・雑記

レシピ追加、ファイルをロックする

今日は「161:ファイルをロックする」を書いた 。ページは存在したのになぜか白紙だったのを昨日見つけたので。1年以上この状態だったのだけど放置されていた模様。

書いてて気づいたのは、ヘルプファイルの『Windows NT Files -- Locking』にあるコード例が正常動作しないという点。

import win32file
import win32con
import win32security
import win32api
import pywintypes

highbits=0xffff0000 #high-order 32 bits of byte range to lock
file="c:\\\\wilma.txt"
secur_att = win32security.SECURITY_ATTRIBUTES()
secur_att.Initialize()

hfile=win32file.CreateFile(file,
        win32con.GENERIC_READ|win32con.GENERIC_WRITE,
        win32con.FILE_SHARE_READ|win32con.FILE_SHARE_WRITE,
        secur_att, #default
        win32con.OPEN_ALWAYS,
        win32con.FILE_ATTRIBUTE_NORMAL ,0)

ov=pywintypes.OVERLAPPED() #used to indicate starting region to lock
win32file.LockFileEx(hfile,win32con.LOCKFILE_EXCLUSIVE_LOCK,0,highbits,ov)
win32api.Sleep(4000) #do something here
win32file.UnlockFileEx(hfile,0,highbits,ov)
hfile.Close()

LockFileEx の dwFileOffsetHigh 引数に 0xffff0000 を入れると 'OverflowError: long int too large to convert to int' になる。 0x7fffffff までなら入る。ここは DWORD のはずなのに (signed) int に直そうとしてしまっているのかな。当方環境は Python 2.5.4 , Windows XP 。 PyWin32 のバージョンは 252 。

PyWin32 が動かないならば ctypes の出番か?

from ctypes import windll, WINFUNCTYPE, POINTER, byref, Structure
from ctypes.wintypes import BOOL, HANDLE, DWORD
import win32file

class OVERLAPPED(Structure):
    _fields_ = [
            ('Internal', DWORD),
            ('InternalHigh', DWORD),
            ('Offset', DWORD),
            ('OffsetHigh', DWORD),
            ('hEvent', HANDLE),
            ]

LockFileEx = WINFUNCTYPE(
        BOOL, HANDLE, DWORD, DWORD, DWORD, DWORD, POINTER(OVERLAPPED))(
                ('LockFileEx', windll.kernel32),
                (
                    (1, 'hFile)'),
                    (1, 'dwFlags'),
                    (1, 'dwReserved'),
                    (1, 'nNumberOfBytesToLockLow'),
                    (1, 'nNumberOfBytesToLockHigh'),
                    (1, 'lpOverlapped'),
                    ),
                )

UnlockFileEx = WINFUNCTYPE(
        BOOL, HANDLE, DWORD, DWORD, DWORD, POINTER(OVERLAPPED))(
                ('UnlockFileEx', windll.kernel32),
                (
                    (1, 'hFile)'),
                    (1, 'dwReserved'),
                    (1, 'nNumberOfBytesToLockLow'),
                    (1, 'nNumberOfBytesToLockHigh'),
                    (1, 'lpOverlapped'),
                    ),
                )

def lock(fobj, flag=0):
    overlapped = OVERLAPPED()
    handle = win32file._get_osfhandle(fobj.fileno())
    return LockFileEx(
            handle, flag, 0, 0, 0xffff0000, byref(overlapped))

def unlock(fobj):
    overlapped = OVERLAPPED()
    handle = win32file._get_osfhandle(fobj.fileno())
    return UnlockFileEx(
            handle, 0, 0, 0xffff0000, byref(overlapped))