ファイルが別のプロセスによってロックされている場合は、そのファイルを開くことはできません。期間。
Windowsには、特にバックアップクライアントを構築する目的で、Volume Shadow Copyサービス(VSS)があります。ロックされたファイルをコピーし、一貫性のあるスナップショットなどを確保するための準備をしています。APIは少し畳み込まれていますが、堅牢なバックアップソリューションが必要な場合は他にありません。
VSSを使用する例については、オープンソースのHoboCopyバックアップツールを参照してください。
EDIT:いくつかのグーグルの後、私はあなたが望むことをする2つの例を見つけました。私はこれらの仕事を保証することはできませんが、少なくとも彼らは妥当と思われます。
$include "windowssdk.inc"
$include "ntddk.inc"
$include "undocumented.inc"
$include "stdio.inc"
$use "_crtdll.lib"
'-------------------------- example
$include "shlwapi.inc"
$define REPLACE_ALWAYS
' open youtube in internet explorer, watch any video (should be downloaded in 100%)
' then run this program to copy the locked fla***.tmp file from your TEMP directory
istring tmppath[MAX_PATH]
' 1. enumerate fla*.tmp files in TEMP directory
ExpandEnvironmentStrings("%TEMP%\\", tmppath, MAX_PATH)
int pathlen = len(tmppath)
strcpy(&tmppath[pathlen], "fla*.tmp")
UINT hFind = findopen(tmppath)
int nFilesFound = 0
int nFilesCopied = 0
if (hFind)
istring name[256] = findnext(hFind)
while (name[0] <> 0)
strncpy(&tmppath[pathlen], name, MAX_PATH-pathlen)
' tmppath = local path to flash video
' 2. copy the file with renamed extension (supported by media player classic)
istring newpath[MAX_PATH]
newpath = tmppath
PathRenameExtension(newpath, ".flv")
' check if we can open the file directly
HANDLE hFile = CreateFile(tmppath, GENERIC_READ, FILE_SHARE_READ _
| FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, 0, 0)
if (hFile <> INVALID_HANDLE_VALUE)
' file opened, so you can copy it with your favorite file manager
CloseHandle(hFile)
else
nFilesFound++
' the file is opened with exclusive access, call the subroutine below to open it
HANDLE hProcess
hFile = OpenFileEx(tmppath, &hProcess)
if (hFile = INVALID_HANDLE_VALUE)
' failed
MessageBox 0, "failed to open " + tmppath, ""
else
' copy it now ...
$ifdef REPLACE_ALWAYS
HANDLE hOutFile = CreateFile(newpath, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0)
$else
HANDLE hOutFile = CreateFile(newpath, GENERIC_WRITE, 0, 0, CREATE_NEW, 0, 0)
$endif
if (hOutFile = INVALID_HANDLE_VALUE)
' failed ?
MessageBox 0, "failed to create " + newpath, ""
else
' ... but first suspend the owner process (because the handle is duplicated, and
' if the owner process changes file pointer, it will be reflected also in this process)
declare import, NtSuspendProcess(HANDLE hProcess), NTSTATUS
declare import, NtResumeProcess(HANDLE hProcess), NTSTATUS
NtSuspendProcess(hProcess)
' save original file pointer in originalFilePos variable
LARGE_INTEGER originalFilePos
LARGE_INTEGER nullFilePos
nullFilePos.QuadPart = 0q
SetFilePointerEx(hFile, nullFilePos, &originalFilePos, FILE_CURRENT)
' seek to beginning
SetFilePointerEx(hFile, nullFilePos, NULL, FILE_BEGIN)
' copy, using string name as the buffer
DWORD BytesRead, BytesWriten
while (ReadFile(hFile, &name, 256, &BytesRead, 0) and BytesRead)
WriteFile(hOutFile, name, BytesRead, &BytesWriten, 0)
endwhile
'
nFilesCopied++
' restore file pointer
SetFilePointerEx(hFile, originalFilePos, NULL, FILE_BEGIN)
' cleanup
CloseHandle(hOutFile)
' resume the process
NtResumeProcess(hProcess)
endif
CloseHandle(hFile)
endif
endif
name = findnext(hFind)
endwhile
findclose(hFind)
endif
if (MessageBox(0, using("Copied # from # locked .FLV files. Open Directory ?", nFilesCopied, nFilesFound), "", MB_YESNO) = IDYES)
tmppath[pathlen-1] = 0
system tmppath
endif
'-------------------------- code
type SYSTEM_HANDLE_ENTRY
ULONG OwnerPid
BYTE ObjectType
BYTE HandleFlags
USHORT HandleValue
PVOID ObjectPointer
ACCESS_MASK GrantedAccess
endtype
type SYSTEM_HANDLE_INFORMATION
ULONG HandleCount
SYSTEM_HANDLE_ENTRY Handles[1]
endtype
type MY_OBJECT_TYPE_INFORMATION
OBJECT_TYPE_INFORMATION t
iwstring buffer[64]
endtype
type MY_OBJECT_NAME_INFORMATION
OBJECT_NAME_INFORMATION t
iwstring buffer[280]
endtype
declare import, NtQuerySystemInformation(_
int SystemInformationClass,_
PVOID SystemInformation,_
ULONG SystemInformationLength,_
pointer ReturnLength),NTSTATUS
const SystemHandleInformation = 16
sub OpenFileEx(string path, pointer pphProcess),HANDLE
MY_OBJECT_TYPE_INFORMATION htype
MY_OBJECT_NAME_INFORMATION name
*<HANDLE>pphProcess = 0
HANDLE h = INVALID_HANDLE_VALUE
' convert c:\ to \Device\HardDiskVolume...
' 1. extract partition letter
iwstring root[4]
root[0] = path[0], 58, 0
' 2. convert it to \Device\HardDiskVolumeX
iwstring wszNTPath[280]
int cch = QueryDosDeviceW(root, wszNTPath, 280)
if (!cch) then return INVALID_HANDLE_VALUE
' 3. append remaining folders and file name from string path parameter
' so <path> "c:\Program Files" gets converted to <wszNTPath> "\Device\HardDiskVolume1\Program Files"
cch = wcslen(wszNTPath)
_snwprintf(&wszNTPath[cch], 280-cch, L"%S", &path[2])
' now get the list of all handles, and find the handle which name is equal to wszNTPath
ULONG BytesNeeded, BufferSize = 4096
pointer handles = new(char, BufferSize) ' SYSTEM_HANDLE_INFORMATION*
while (handles)
' get the list of all user-mode handles
NTSTATUS status = NtQuerySystemInformation(SystemHandleInformation, handles, BufferSize, &BytesNeeded)
if (status = STATUS_INFO_LENGTH_MISMATCH)
' BytesNeeded is not adjusted, so we need to increase buffer size
delete handles
BufferSize += 32768
handles = new(char, BufferSize)
elseif (!status)
settype handles, SYSTEM_HANDLE_INFORMATION
' sort handles by owning process id
qsort(&*handles.Handles, *handles.HandleCount, len(SYSTEM_HANDLE_ENTRY), &SortHandlesCb)
pointer node = *handles.Handles
settype node, SYSTEM_HANDLE_ENTRY
ULONG OwnerPid = 0
HANDLE hProcess = 0
HANDLE hThisProcess = GetCurrentProcess()
BYTE ObjectTypeFile = 0
while (*handles.HandleCount)
*handles.HandleCount--
if (*node.GrantedAccess & FILE_READ_DATA) ' 13019F
if (OwnerPid <> *node.OwnerPid)
OwnerPid = *node.OwnerPid
if (hProcess) then CloseHandle(hProcess)
hProcess = OpenProcess(PROCESS_DUP_HANDLE|PROCESS_SUSPEND_RESUME, FALSE, OwnerPid)
endif
if (hProcess)
HANDLE hObject
if (DuplicateHandle(hProcess, *node.HandleValue, hThisProcess, &hObject, 0, FALSE, DUPLICATE_SAME_ACCESS))
if (GetFileType(hObject) = FILE_TYPE_DISK)
if (!ObjectTypeFile) ' query object type name as "integer"
if (!NtQueryObject(hObject, ObjectTypeInformation, &htype, len(htype), &BytesNeeded))
if (!_wcsnicmp(htype.t.TypeName.Buffer, L"File", 4))
ObjectTypeFile = *node.ObjectType
endif
endif
endif
' do not query object name with granted access 0x0012019f (deadloock)
if (ObjectTypeFile and (ObjectTypeFile = *node.ObjectType) and (*node.GrantedAccess <> 0x0012019f))
' query file name
if (!NtQueryObject(hObject, ObjectNameInformation, &name, len(name), &BytesNeeded))
if (name.t.Name.Buffer and !wcsicmp(name.t.Name.Buffer, wszNTPath)) ' compare
*<HANDLE>pphProcess = hProcess
delete handles
return hObject
endif
endif
endif
endif
CloseHandle(hObject)
endif
endif
endif
node = &*node[1]
endwhile
if (hProcess) then CloseHandle(hProcess)
delete handles
else
' NtQuerySystemInformation failed
delete handles
endif
endwhile
if (handles) then delete handles
return h
endsub
declare cdecl SortHandlesCb(SYSTEM_HANDLE_ENTRY p1, SYSTEM_HANDLE_ENTRY p2),int
sub SortHandlesCb(SYSTEM_HANDLE_ENTRY p1, SYSTEM_HANDLE_ENTRY p2),int
if (p1.OwnerPid = p2.OwnerPid) then return 0
if (p1.OwnerPid > p2.OwnerPid) then return 1
return -1
endsub
別の厄介な例はhttp://forum.sysinternals.com/topic7974.htmlである:
最初の例では、はっきりとよくコメント(言語は、いくつかの基本の方言が、非常に読みやすいです)。
両方の例では、ネイティブAPI関数とそのドキュメント化されていない機能を使用しています。
基本的な手順は以下のとおりです。
- ロック過程で見られるようなファイルハンドルの値を取得します。これは、
NtQuerySystemInformation
を呼び出してシステム内のすべてのハンドルのリストを取得し、NtQueryObject
を呼び出して、ファイル名が一致するハンドルを見つけます。 ファイル名はNTデバイス形式に変換する必要があります。
- オープンsuffucuent権限(
PROCESS_DUP_HANDLE
とPROCESS_SUSPEND_RESUME
)と呼んでDuiplicateHandle
(ソース、ステップ1からハンドル値、および先としてあなたのプロセスとして、そのプロセスを使用)とハンドル(OpenProcess
)を所有しているプロセス。
NtSuspendProcess
を使用してプロセスを「一時停止」し、ファイルポインタとファイルの内容を変更できないようにします)。
- 複製ハンドルを使用してファイルをコピーします。
- ファイルポインタを復元し、ハンドルを閉じ、プロセスをポストするには
NtResumeProcess
を呼び出します。
EDIT2:個人的に私はロックされたファイルにアクセスするために別の方法を使用していた - マニュアルNTFSを解析すると、生のディスクアクセスを。例えば。ファイル名にMFTエントリが見つかると、データの実行場所をデコードし、それらをrawディスクから読み込みます。rawディスクへのアクセスは常に(管理者特権を持っていれば)利用可能であるため、どのファイルも読み込み可能です。欠点は一貫性保証がゼロであるため、バックアップ目的には適していません。
PS。もし私があなただったら私はまだ公式にサポートされているVSSに行くだろう。バックアップソフトウェアはハッキングに頼るべきではありません。
fopenを使用する代わりに、私はCreateFileを使用しますか? –
@Brunoどのような方法を使用しています。彼らはすべて最終的にCreateFileを呼び出します。 –
バグは申し訳ありませんが、私はduplicateHandle()について読んでいましたが、プロセスハンドルを複製して、他のプロセスが使用しているのと同じファイルを使用できるようにすることはできますか? –