Solved

How do I know who is locking the file in my C++ codes ?

Posted on 2013-12-28
6
1,249 Views
Last Modified: 2013-12-29
Hello Experts,

I'm looking for C++ sample code to determine WHO IS LOCKING THE FILE ?
I want to know the process ID of locking specific file.
I know that Process Explorer can do that.
I want to do it in my C++ program.

I guess OpenProcess() and DuplicateHandle() are the key, but I don't know how to implement.

Windows 7 32bit

Please advice
Nobuo Miwa
0
Comment
Question by:NobMiwa
  • 3
  • 2
6 Comments
 
LVL 13

Expert Comment

by:AielloJ
ID: 39743622
NobMiwa,

I don't believe it's possible since file handle information is stored in kernel space.  There are function calls that will tell you the name of the application that has the file open ( IFileIsInUse::GetAppName() ) but not the user.  Even then, the other application opening the file would have to have been written to be cooperative.

Best regards,

AielloJ
0
 
LVL 86

Accepted Solution

by:
jkr earned 500 total points
ID: 39743966
>> I guess OpenProcess() and DuplicateHandle() are the key, but I don't know how to
>> implement.

They're not really the key. You will need to use Windows' Native API (http://netcode.cz/img/83/nativeapi.html) , in particular get a copy of the global handle table by calling 'ZwQuerySystemInformation(SystemHandleInformation,...);' and checking the referenced handles /PIDs. The following code does this, the the structure definitions were taken from Gary Nebbett' book "Native API Reference" (which also contains samples from which this snippet is derived). All you need to do is compiling this and link with ntdll.lib, which comes with the DDK. Alternatively, you could load the Zw* functions dynamically.

#define UNICODE
#define _UNICODE
#include <tchar.h>
#include <stdio.h>

#pragma warning ( disable: 4768)
#include <map>

typedef enum _SYSTEM_INFORMATION_CLASS
{
    SystemHandleInformation = 16,

} SYSTEM_INFORMATION_CLASS;

typedef	struct	_SYSTEM_HANDLE_INFORMATION
{
    ULONG		ProcessId;
    UCHAR		ObjectTypeNumber;
    UCHAR		Flags;
    USHORT		Handle;
    PVOID		Object;
    ACCESS_MASK	GrantedAccess;

}	SYSTEM_HANDLE_INFORMATION,	*PSYSTEM_HANDLE_INFORMATION;

typedef enum _OBJECT_INFORMATION_CLASS
{
    ObjectBasicInformation,
    ObjectNameInformation,
    ObjectTypeInformation,
    ObjectAllTypesInformation,
    ObjectHandleInformation
}	OBJECT_INFORMATION_CLASS;

typedef struct	_OBJECT_BASIC_INFORMATION
{
    ULONG			Attributes;
    ACCESS_MASK		GrantedAccess;
    ULONG			HandleCount;
    ULONG			PointerCount;
    ULONG			PagedPoolUsage;
    ULONG			NonPagedPoolUsage;
    ULONG			Reserved	[	3];
    ULONG			NameInformationLength;
    ULONG			TypeInformationLength;
    ULONG			SecurityDescriptorLength;
    LARGE_INTEGER	CreateTime;

}	OBJECT_BASIC_INFORMATION,	*POBJECT_BASIC_INFORMATION;	

typedef	struct	_OBJECT_TYPE_INFORMATION
{
    UNICODE_STRING	Name;
    ULONG			ObjectCount;
    ULONG			HandleCount;
    ULONG			Reserved1	[	4];
    ULONG			PeakObjectCount;
    ULONG			PeakHandleCount;
    ULONG			Reserved2	[	4];
    ULONG			InvalidAttributes;
    GENERIC_MAPPING	GenericMapping;
    ULONG			ValidAccess;
    UCHAR			Unknown;
    BOOLEAN			MaintainHandleDatabase;
    NT::POOL_TYPE	PoolType;
    ULONG			PagedPoolUsage;
    ULONG			NonPagedPoolUsage;

}	OBJECT_TYPE_INFORMATION,	*POBJECT_TYPE_INFORMATION;

typedef	struct	_OBJECT_NAME_INFORMATION
{
    UNICODE_STRING	Name;
}	OBJECT_NAME_INFORMATION,	*POBJECT_NAME_INFORMATION;


typedef std::map<ULONG, ULONG> pid_map;


extern "C"
NTSTATUS
__stdcall
ZwQuerySystemInformation	(	SYSTEM_INFORMATION_CLASS,
                                PVOID,
                                ULONG,
                                PULONG
                            );

extern "C"
NTSTATUS
__stdcall
ZwQueryObject				(	HANDLE,
                                OBJECT_INFORMATION_CLASS,
                                PVOID,
                                ULONG,
                                PULONG
                            );

extern "C"
NTSTATUS
__stdcall
ZwDuplicateObject			(	HANDLE,
                                HANDLE,
                                HANDLE,
                                PHANDLE,
                                ACCESS_MASK,
                                ULONG,
                                ULONG
                            );

POBJECT_NAME_INFORMATION	
GetObjectNameInformation	(	HANDLE	__hObject, wchar_t* __pwszTypeFilter)
{
    NTSTATUS					_ntStatus;
    OBJECT_BASIC_INFORMATION	_obi;
    POBJECT_TYPE_INFORMATION	_poti;
    POBJECT_NAME_INFORMATION	_poni;
    ULONG						_ul;
    
    ZwQueryObject	(	__hObject,
                        ObjectBasicInformation,
                        &_obi,
                        sizeof	(	_obi),
                        &_ul
                    );

    _ul	=		_obi.TypeInformationLength	+	2;

    _poti	=	( POBJECT_TYPE_INFORMATION)	new	char	[	_ul];

    _ntStatus	=	ZwQueryObject	(	__hObject,
                                        ObjectTypeInformation,
                                        _poti,
                                        _ul,
                                        &_ul
                                    );

    if	(	__pwszTypeFilter	&&	!wcscmp	(	_poti->Name.Buffer, __pwszTypeFilter))
        {
            delete	[]	_poti;

            return	NULL;
        }

    _ul	=		!_obi.NameInformationLength	
            ?	MAX_PATH * sizeof ( WCHAR)
            :	_obi.NameInformationLength;

    _poni	=	( POBJECT_NAME_INFORMATION)	new	char	[	_ul];

    _ntStatus	=	ZwQueryObject	(	__hObject,
                                        ObjectNameInformation,
                                        _poni,
                                        _ul,
                                        &_ul
                                    );

/*
    wprintf	(	L"Obj 0x%8.8x %.*s %.*s\n",	
                __hObject,
                _poni->Name.Length / 2,
                _poni->Name.Buffer,
                _poti->Name.Length / 2,
                _poti->Name.Buffer
            );
*/

    delete	[]	_poti;

    return	(	_poni);
}

void	PrintObjectUsers	(	wchar_t*	__pwszObj,	wchar_t*	__pwszTypeFilter)
{

    pid_map						_pid_map;
    ULONG						_ulPID;
    NTSTATUS					_ntStatus;

    HANDLE						_hObject;
    HANDLE						_hProcess;

    PSYSTEM_HANDLE_INFORMATION	_pshi;
    POBJECT_NAME_INFORMATION	_poni;

    ULONG						_ul		=	0x1000;
    PULONG						_pul	=	new	ULONG	[	_ul];

//	hProcess	=	OpenProcess	(	PROCESS_DUP_HANDLE,	FALSE,	dwPID);

    while	(	STATUS_INFO_LENGTH_MISMATCH	==	ZwQuerySystemInformation	(	SystemHandleInformation,
                                                                                _pul,
                                                                                _ul	*	sizeof	(	ULONG),
                                                                                0
                                                                            )
            )	delete	[]	_pul,	_pul	=	new	ULONG	[	_ul	*=	2];

    _pshi	=	( PSYSTEM_HANDLE_INFORMATION)	( _pul	+	1);

    for	(	ULONG	_i	=	0;	_i	<	*_pul;	_i++)
        {
            _ulPID		=	_pshi	[	_i].ProcessId;

            _hObject	=	NULL;

            _hProcess	=	OpenProcess	(	PROCESS_DUP_HANDLE,	
                                            FALSE,	
                                            _ulPID
                                        );

            if	(	!_hProcess)
                {
                    //wprintf	(	L"FAILED to 'OpenProcess()' for PID %d\n",	_ulPID);
                    continue;
                }

            ZwDuplicateObject	(	_hProcess,
                                    ( HANDLE)	_pshi	[	_i].Handle,
                                    NtCurrentProcess	(),
                                    &_hObject,
                                    0,
                                    0,
                                    DUPLICATE_SAME_ATTRIBUTES
                                );

            if	(	!_hObject)
                {
                    wprintf	(	L"FAILED to 'ZwDuplicateObject()' for PID %d\n",	_ulPID);
                    continue;
                }

            if	(	_hObject)
                {
                    _poni	=	GetObjectNameInformation	(	_hObject, __pwszTypeFilter);

                    if	(	!_poni)	continue;

                    if	(	!_poni->Name.Length)	continue;

                    if	(	wcsstr	(	_poni->Name.Buffer,	__pwszObj))
                        {
                            pid_map::iterator	_i_map	=	_pid_map.find	(	_ulPID);

//							if	(	_i_map	==	_pid_map.end	())
                                {
                                    wprintf	(	L"PID: %d\tNAME: %s\n",
                                                _ulPID,
                                                _poni->Name.Buffer
                                            );

//									_pid_map.insert	(	pid_map::value_type	(	_ulPID,	_ulPID));
                                }
                        }

                    delete	[]	_poni;

                }

            CloseHandle	(	_hObject);
            CloseHandle	(	_hProcess);

        }

    delete	[]	_pul;
}


int	wmain	(	int			__wargc,
                wchar_t**	__wargv
            )
{
    wchar_t*	__pwc;


    if	(	2	!=	__wargc)
            return	(	-1);

    PrintObjectUsers	(	*( __wargv	+	1),	NULL);

    return	(	0);

}

Open in new window


BTW, that also was a subject in http://www.experts-exchange.com/Programming/Languages/CPP/Q_21310246.html
0
 

Author Comment

by:NobMiwa
ID: 39744372
Hello,

Thank you for the information.

I found the one of solution, it works fine on my C++Builder XE2.
But I don't know that is correct...

	HANDLE hProcess = OpenProcess(
				PROCESS_ALL_ACCESS,
				FALSE,
				pid);
	HANDLE handle;
	for(int t=1;t<1000;t++){
		// Duplicate the handle
		if( ::DuplicateHandle(hProcess,
					 (HANDLE)t,
					 GetCurrentProcess(),
					 &handle,
					 GENERIC_READ,
					 FALSE,
					 0) ) {

			wchar_t  path[1024];
			ZeroMemory(path,sizeof(path));
			DWORD rt = GetFinalPathNameByHandle(handle,
			     path,
			     sizeof(path)-1,
			     FILE_NAME_NORMALIZED);
			if (rt>0) {
			    // fullpath here
			}
		}
	}

Open in new window

0
Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

 
LVL 86

Expert Comment

by:jkr
ID: 39745281
Might work, to find a file's name but: How do you obtain the PID you are using in the above? That's what my example does ;o)
0
 

Author Comment

by:NobMiwa
ID: 39745550
Hello,

I customize my code that is using NtQuerySystemInformation and it works.
So now I could get correct file handle now.

I got process ID list from followings..

Process32FirstW(hSnap, &pe32);
Process32FirstW(hSnap, &pe32);

Thank you for the hint.

Nobuo Miwa
0
 

Author Closing Comment

by:NobMiwa
ID: 39745551
Thank you !
0

Featured Post

Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Entering time in Microsoft Access can be difficult. An input mask often bothers users more than helping them and won't catch all typing errors. This article shows how to create a textbox for 24-hour time input with full validation politely catching …
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.

791 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question