Solved

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

Posted on 2013-12-28
6
1,361 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Visualize your virtual and backup environments

Create well-organized and polished visualizations of your virtual and backup environments when planning VMware vSphere, Microsoft Hyper-V or Veeam deployments. It helps you to gain better visibility and valuable business insights.

 
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

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

Have you tried to learn about Unicode, UTF-8, and multibyte text encoding and all the articles are just too "academic" or too technical? This article aims to make the whole topic easy for just about anyone to understand.
In this post we will learn different types of Android Layout and some basics of an Android App.
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.
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

632 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