2014-09-26 11 views
5

Sto usando C# framework 4.5, netoffice 1.6 e sharpdevelop 4.4.1 per manipolare una cartella di lavoro Excel, che si trova su una condivisione di rete, da Outlook.Ottiene automaticamente l'utente che sta bloccando una cartella di lavoro excel

Ad un certo punto ho bisogno di cambiare l'accesso ai file dell'oggetto cartella di lavoro (EWB) per readwrite in questo modo:

ewb.ChangeFileAccess(Excel.Enums.XlFileAccess.xlReadWrite, System.Reflection.Missing.Value, true); 

Prima di cambiare l'accesso del file, controllo se il file è bloccato sul server . Se il file è bloccato, notificherò all'utente di riprovare l'azione in un secondo momento.

Ora, voglio includere il nome utente che blocca il file excel nella notifica. Ho cercato msdn, forum di netoffice, eccetera ... e non ho trovato una soluzione. So che, se apri il file excel readwrite, esso memorizzerà il nome dell'utente nel file xlsx. Come posso accedere a quella particolare informazione attraverso C#?

EDIT: ho finito per fare questo:

public string GetExcelFileOwner(string path, NetOffice.ExcelApi.Enums.XlFileFormat ffmt) { 
     string tempmark = "~$"; 
     if(ffmt==NetOffice.ExcelApi.Enums.XlFileFormat.xlExcel8) { 
      tempmark = ""; 
     } 
     string uspath = Path.Combine(Path.GetDirectoryName(path), tempmark + Path.GetFileName(path)); 
     if (!File.Exists(uspath)) return ""; 
     var sharing = FileShare.ReadWrite | FileShare.Delete; 
     using (var fs = new FileStream(uspath, FileMode.Open, FileAccess.Read, sharing)) 
     using (var br = new BinaryReader(fs, Encoding.Default)) { 
      if(ffmt==NetOffice.ExcelApi.Enums.XlFileFormat.xlExcel8) { 
       byte[] ByteBuffer = new byte[500]; 
       br.BaseStream.Seek(150, SeekOrigin.Begin); 
       br.Read(ByteBuffer, 0, 500); 
       return matchRegex(System.Text.Encoding.UTF8.GetString(ByteBuffer), @"(?=\w\w\w)([\w, ]+)").Trim(); 
      } 
      else { 
       return br.ReadString(); 
      } 
     } 
    } 

    private static string matchRegex(string txt, string rgx) { 
     Regex r; 
     Match m; 
     try { 
      r = new Regex(rgx, RegexOptions.IgnoreCase); 
      m = r.Match(txt); 
      if (m.Success) { 
       return m.Groups[1].Value.ToString(); 
      } 
      else { 
       return ""; 
      } 
     } 
     catch { 
      return ""; 
     } 
    } 

Stiamo usando Excel 2003 ed Excel 2007+ formato di file (.xls e .xlsx). Per .xls ho dovuto cercare nel file .xls stesso. Per .xlsx, l'utente che blocca è memorizzato nel file ~ $ temp. Lo so, per il file .xls, è un codice sporco, ma non ho idea di come sia strutturato il formato file .xls. Pertanto, ho appena letto un sacco di byte che include il nome utente ascii e faccio una regex per estrarre quel nome utente.

+0

hai provato a guardare Win32_ConnectionShare e WMIC? –

risposta

8

memorizzerà il nome dell'utente nel file xlsx

No, non il nel file di .xlsx. Excel crea un altro file per memorizzare il nome utente. Ha l'attributo file nascosto attivato, quindi non puoi normalmente vederlo con Explorer.

Normalmente ha lo stesso nome del file originale, ma ha il prefisso ~$. Quindi per un file denominato test.xlsx otterrai un file denominato ~$test.xlsx. È un file binario e contiene il nome utente codificato sia nella codepage predefinita che in utf-16. Un dump esadecimale per mostrare come si presenta:

0000000000: 0C 48 61 6E 73 20 50 61 │ 73 73 61 6E 74 20 20 20 ♀Hans Passant 
0000000010: 20 20 20 20 20 20 20 20 │ 20 20 20 20 20 20 20 20 
0000000020: 20 20 20 20 20 20 20 20 │ 20 20 20 20 20 20 20 20 
0000000030: 20 20 20 20 20 20 20 0C │ 00 48 00 61 00 6E 00 73   ♀ H a n s 
0000000040: 00 20 00 50 00 61 00 73 │ 00 73 00 61 00 6E 00 74  P a s s a n t 
0000000050: 00 20 00 20 00 20 00 20 │ 00 20 00 20 00 20 00 20 
0000000060: 00 20 00 20 00 20 00 20 │ 00 20 00 20 00 20 00 20 
0000000070: 00 20 00 20 00 20 00 20 │ 00 20 00 20 00 20 00 20 
0000000080: 00 20 00 20 00 20 00 20 │ 00 20 00 20 00 20 00 20 
0000000090: 00 20 00 20 00 20 00 20 │ 00 20 00 20 00 20 00 20 
00000000A0: 00 20 00 20 00   │ 

La parola Oddish 0x0C nel file è la lunghezza della stringa in caratteri (non byte), seguito da 54 caratteri per memorizzare il nome utente, imbottito con spazi. Il modo più semplice per leggere è con BinaryReader.ReadString():

public static string GetExcelFileOwner(string path) { 
    string uspath = Path.Combine(Path.GetDirectoryName(path), "~$" + Path.GetFileName(path)); 
    if (!File.Exists(uspath)) return ""; 
    var sharing = FileShare.ReadWrite | FileShare.Delete; 
    using (var fs = new FileStream(uspath, FileMode.Open, FileAccess.Read, sharing)) 
    using (var br = new BinaryReader(fs, Encoding.Default)) { 
     return br.ReadString(); 
    } 
} 

Ma non necessariamente il modo più corretto, si potrebbe desiderare di migliorare il codice e cercare di individuare la stringa UTF-16 (non con ReadString) se Le codifiche a 8 bit non funzionano bene nelle tue impostazioni internazionali. Cerca() prima di sfalsare 0x37. Assicurati di utilizzare il metodo correttamente, ha una condizione di competizione implicita, quindi assicurati di usarlo solo dopo l'operazione e non aspettarti che restituisca una stringa vuota.Non posso garantire che questo metodo funzioni correttamente su tutte le versioni di Excel, comprese quelle future, ho solo provato per Office 2013 su una macchina di classe workstation.

+0

Ciao Hans. Questo sembra funzionare solo per i file locali, non per i file Excel che si trovano sulla rete. Vedo il file $ quando apro e modifico un file excel sul mio disco rigido. Non vedo il file quando si apre dalla rete. Ho controllato il file xlsx quando l'ho aperto in lettura/scrittura sulla rete. Il nome dell'utente che l'ha aperto è memorizzato in xlsx. Quindi penso ancora che dovrei leggere l'impostazione dal file xlsx. – nire

+0

Hmm, no, è piuttosto dubbio che modificherà un file .xlsx solo per scrivere il nome utente. L'unica ruga che posso pensare è che l'utente non ha accesso in scrittura alla cartella condivisa. Ma non indoviniamoci, usa Process Monitor di SysInternals per vedere cosa sta succedendo, vedrai che Excel.exe armeggia con il/i file/i. –

+0

Hans, hai ragione. Procmon mostra che Excel.exe accede a ~ $ ...... xlsx con risultato SUCCESSO. Oh uomo, e ora vedo il file ~ $ .... xlsx sul server. Ho anche provato un file xls, per il quale non viene creato un file ~ $. Il nome dell'utente è memorizzato nel .xls effettivo. Proverò il tuo codice e riferirò. – nire

0

In quale parte hai problemi?

senza sapere nulla di XSLX, posso solo immaginare che: si desidera aprire il file e specificare FileAccess.Read & FileShare.ReadWrite come qui: How to read open excel file at C# dopo di che, è utilizzare una sorta di biblioteca per trasformare XSLX in DataTable, e estrai la riga specifica di cui hai bisogno.

+0

Utilizzo gli assembly del wrapper .NET di netoffice per manipolare i file e le applicazioni dell'ufficio. Il problema è che non ho modo di estrarre il nome utente dell'utente che sta (b) bloccando il file excel. – nire

+0

Beh, sembra che tu abbia bisogno di sapere chi ha aperto un file specifico e i FLAGS che ha su quel file. L'utilità PSFile può farlo tramite la riga di comando. "psfile \\ yourremoteshare C: \ test.xlsx". Se sei interessato a farlo a livello di programmazione, puoi scaricare APIMonitor e vedere come lo fa psfile. Personalmente dubito che sia possibile accedere al "nome utente nel file xlsx", mi sembra una cosa interiore. –

+0

Anche se la mia soluzione suggerita richiede diritti di amministratore, che è no-no. Puoi utilizzare il monitoraggio API per verificare come Excel riceve quel nome utente dal file remoto. (Ad esempio attraverso il quale le chiamate API, ed è interno) –

Problemi correlati