Ricavare dal FileInfo il processo che tiene aperto il file

martedì 24 febbraio 2009 - 11.04

marianoross Profilo | Newbie

Ciao ragazzi
ho il seguente problema. Ho una directory da cui ricavo tutti i FileInfo contenuti, e poichè alcuni file potrebbero essere aperti, vorrei trovare il modo di individuare il processo che tieni impiegato il file aperto. Avete qualche idea di come fare, o meglio di come individuare il processo o il suo pid?
Ciao Mar

aiedail92 Profilo | Expert

Ciao

Purtroppo non c'è modo di ottenere il processo che tiene aperto il file, se non agendo con un driver in kernel mode, assolutamente non sviluppabile in .net, e comunque di difficile realizzazione anche in C\C++ per la delicatezza dell'ambito dove lavora.

Luca

marianoross Profilo | Newbie

Ciao
scusami, ma pensavo che si potesse fare qualcosa con WMI. Secondo te ci sono possibilità?
Ciao grazie

aiedail92 Profilo | Expert

Con WMI puoi al massimo ottenere il numero di handle aperti per un processo, cosa che però puoi fare molto più velocemente con l'API GetProcessHandleCount.

Volendo potresti usare un tool di terze parti perchè, come ti ho detto, la scrittura di un kernel driver non è affatto semplice:

http://technet.microsoft.com/en-us/sysinternals/bb896655.aspx

Luca

aiedail92 Profilo | Expert

Ciao

Mi sono recentemente imbarcato nel "mondo delle API non documentate" scoprendo che, anche se mamma microsoft sembra non volerlo far sapere in giro, è possibile fare quello che chiedevi anche senza un kernel driver.

Ti rimando qui per una descrizione completa:

http://procoder.forumfree.net/?t=38978927

In fondo all'articolo trovi un link da cui scaricare una dll che dovrai copiare nella cartella di esecuzione della tua applicazione (oppure nella cartella di windows); quindi il codice per usarla da VB.Net o C# è questo:

'VB.Net Imports System.Runtime.InteropServices Public Class TuaForm <StructLayout(LayoutKind.Sequential)> _ Structure FileInformation 'ID del processo che tiene aperto il file Public ProcessID As Integer 'Handle del file aperto dal processo '(è riferito al contesto del processo, non puoi fare praticamente niente con questo) Public FileHandle As IntPtr End Structure 'Importa la funzione dalla dll. Inserisci il percorso completo corretto della dll, 'oppure assicurati che la dll si trovi nella cartella dell'eseguibile <DllImport("WhoLocked.dll")> _ Shared Function GetPidLockingFile( _ <MarshalAs(UnmanagedType.LPWStr)> ByVal filePath As String, _ <[In](), Out()> ByVal outInfo As FileInformation(), _ ByVal maxCount As Integer) As Integer End Function Private Sub TuoButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles TuoButton.Click 'Richiede il file da monitorare Dim OFD As New OpenFileDialog() If (OFD.ShowDialog() <> Windows.Forms.DialogResult.OK) Then Return TuaRichTextBox.Clear() 'Alloca l'array che conterrà gli ID dei processi che tengono aperto il file Dim fileInfo(50) As FileInformation 'Ottiene le informazioni dalla funzione nella Dll, e il numero di processi trovati Dim count As Integer = GetPidLockingFile(OFD.FileName, fileInfo, 50) 'Cicla su tutti i processi mostrando l'output in una RichTextBox For i As Integer = 0 To count - 1 'Scrive le informazioni sulla richtextbox TuaRichTextBox.AppendText(String.Format("Process ID: {0}" & vbCrLf & _ "Handle: 0x{1:X}" & vbCrLf & vbCrLf, _ fileInfo(i).ProcessID, CInt(fileInfo(i).FileHandle))) Next End Sub End Class

//C# public partial class TuaForm : Form { public TuaForm() { InitializeComponent(); } [StructLayout(LayoutKind.Sequential)] struct FileInformation { //PID del processo che tiene aperto il file public int pid; //Handle del file aperto dal processo (nell'ambito del processo) public IntPtr procHandle; } [DllImport(@"WhoLocked.dll")] static extern int GetPidLockingFile( [MarshalAs(UnmanagedType.LPWStr)]String filePath, [In, Out]FileInformation[] outInfo, int maxCount); private void tuoButton_Click(object sender, EventArgs e) { OpenFileDialog ofd = new OpenFileDialog(); if (ofd.ShowDialog() != DialogResult.OK) return; tuaTextBox.Clear(); //Crea una lista per contenere i valori di ritorno FileInformation[] res = new FileInformation[20]; int count = GetPidLockingFile(ofd.FileName, res, 20); //Cicla fra tutti i risultati for (int i = 0; i < count; i++) { tuaTextBox.AppendText(String.Format("Process ID: {0}\r\nHandle: 0x{1:X}\r\n\r\n", res[i].pid, (int)res[i].procHandle)); } } }

Mi rendo conto che il thread è abbastanza datato, ma potrà essere d'aiuto in futuro anche ad altra gente

Luca

CeccoCQ Profilo | Newbie

Ho bisogno del file WhoLocked.dll, dove posso reperirlo? Il link di download non esiste più....

aiedail92 Profilo | Expert

Ti ho risposto anche sull'altro thread. Per i futuri visitatori, una copia dell'archivio è hostata su megaupload a questo indirizzo:

http://www.megaupload.com/?d=8ENLG6DW

Saluti

Luca

CeccoCQ Profilo | Newbie

Hai fatto davvero un ottimo lavoro, ti faccio le mie congratulazioni!!!
Posso chiederti un paio di informazioni?
Io sto lavorando nell'altro senso, ossia data la lista dei processi attivi in un determinato momento, vorrei sapere la path di tutti i file aperti nel sistema da quel processo.
Dunque, ad esempio, aprendo un file JPG/PNG con il visualizzatore di immagini di Windows non riesco a visualizzare la path completa del nome del file, come:
C:\Documents and Settings\User\Documenti\Immagini\miofile.jpg

Come output dell'applicazione della tua dll al mio programma ho solamente:
C:\Documents and Settings\User\Documenti\Immagini
Senza il nome del file appeso alla fine della path.

Purtroppo, questo accade anche quando apro programmi come Paint.

Invece, volendo aprire un pdf, riesco a visualizzare la path completa. Sapresti darmi indicazioni a riguardo?
Grazie 1000 e ancora complimenti per l'ottimo lavoro svolto!

aiedail92 Profilo | Expert

Potrebbe dipendere dal fatto che il programma, dopo aver caricato l'immagine in memoria, chiuda il file. Se è così (e probabilmente è così) non puoi fare molto, il file a tutti gli effetti non è aperto...

L'unica cosa sarebbe intercettare l'apertura del file nel momento in cui avviene (vedi FileSystemWatcher), ma non mi sembra una soluzione che faccia al caso tuo.

Luca

CeccoCQ Profilo | Newbie

Scusa se vado a riesumare questo post ma ho un problema.
Fino a qualche tempo fa ho utilizzato la libreria WhoLocked.dll senza alcun problema su XP.
Adesso ho dovuto fare il porting della mia applicazione su Win7 e non va più, precisamente ho questo errore:

AcessViolationException - {"Tentativo di lettura o scrittura della memoria protetta. Spesso questa condizione indica che altre parti della memoria sono danneggiate."}

quando invoco la funzione GetProcessOpenFiles(proc.Id, fi, 50);
Non sono molto pratico di DLL, ma non è che la libreria funziona solo per WinXP? Puoi aiutarmi a capire?
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2024
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5