Solved

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

Posted on 2013-12-28
6
1,187 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
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
twoTwo  challenge 35 93
zeroFront challenge 7 79
SNMP error No Such Object available on this agent at this OID 3 187
c++, dynamic object by json 1 22
For a while now I'v been searching for a circular progress control, much like the one you get when first starting your Silverlight application. I found a couple that were written in WPF and there were a few written in Silverlight, but all appeared o…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…

911 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

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now