2014-09-26 11 views
5

Ich benutze C# Framework 4.5, NetOffice 1.6 und SharpDevelop 4.4.1, um eine Excel-Arbeitsmappe zu bearbeiten, die sich auf einer Netzwerkfreigabe in Outlook befindet.Programmatisch erhalten Benutzer, der eine Excel-Arbeitsmappe sperrt

An einem gewissen Punkt muß ich die Datei Zugriff des Arbeitsobjekts (EWB) ändern, wie dies zu readwrite:

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

Bevor ich den Dateizugriff ändern, überprüfe ich, ob die Datei auf dem Server gesperrt ist . Wenn die Datei gesperrt ist, benachrichtige ich den Benutzer, die Aktion zu einem späteren Zeitpunkt erneut zu versuchen.

Jetzt möchte ich den Benutzernamen einschließen, der die Excel-Datei in der Benachrichtigung sperrt. Ich habe msdn, netoffice forum, usw. gesucht und habe keine Lösung gefunden. Ich weiß, dass wenn Sie die Excel-Datei readwrite öffnen, wird der Name des Benutzers in der XLSX-Datei gespeichert. Wie kann ich über C# auf diese bestimmte Information zugreifen?

EDIT: landete ich dies zu tun:

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 ""; 
     } 
    } 

Wir verwenden Excel 2003 und Excel 2007 + Dateiformat (.xls und .xlsx). Für .xls musste ich in der .xls Datei selbst suchen. Für .xlsx wird der Benutzer mit Sperrfunktion in der Datei ~ $ temp gespeichert. Ich weiß, für die .xls-Datei ist es schmutziger Code, aber ich habe keine Ahnung, wie das .xls-Dateiformat strukturiert ist. Daher lese ich gerade eine Reihe von Bytes, die den Ascii-Benutzernamen enthalten und eine Regex ausführen, um diesen Benutzernamen zu extrahieren.

+0

haben Sie versucht, Win32_ConnectionShare und WMIC zu betrachten? –

Antwort

8

wird es den Namen des Benutzers gespeichert werden in der xlsx Datei

Nein, nicht die in .xlsx-Datei. Excel erstellt eine andere Datei zum Speichern des Benutzernamens. Es hat das Attribut Versteckte Datei aktiviert, so dass Sie es normalerweise nicht mit Explorer sehen können.

Es hat normalerweise den gleichen Namen wie die Originaldatei, aber das Präfix ~$. Für eine Datei mit dem Namen test.xlsx erhalten Sie eine Datei mit dem Namen ~$test.xlsx. Es ist eine Binärdatei und enthält den Benutzernamen, der sowohl in der Standard-Codepage als auch in utf-16 codiert ist. Ein Hex-Dump zu zeigen, wie es aussieht:

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   │ 

Das oddish 0x0C Wort in der Datei der String-Länge in Zeichen (nicht Bytes), um 54 Zeichen folgen Sie den Benutzernamen zu speichern, mit Leerzeichen aufgefüllt. Die einfachste Weg, es zu lesen mit BinaryReader.ReadString ist():

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(); 
    } 
} 

aber nicht unbedingt die richtige Art und Weise, können Sie den Code verbessern und versuchen, den utf-16-String zu suchen (nicht mit Readstring), wenn 8-Bit-Codierungen funktionieren in Ihrem Gebietsschema nicht gut. Seek(), um zuerst 0x37 zu versetzen. Stellen Sie sicher, dass Sie die Methode korrekt verwenden. Sie enthält eine implizite Racebedingung. Stellen Sie daher sicher, dass Sie nur nach verwenden, da die Operation fehlgeschlagen ist und trotzdem eine leere Zeichenfolge erwartet wird.Ich kann nicht garantieren, dass diese Methode auf allen Excel-Versionen korrekt funktioniert, auch auf zukünftigen, ich habe nur auf einer Workstation-Klassenmaschine auf Office 2013 getestet.

+0

Hallo Hans. Dies scheint nur für lokale Dateien zu funktionieren, nicht für Excel-Dateien im Netzwerk. Ich sehe die ~ $ Datei, wenn ich eine Excel-Datei auf meiner Festplatte öffne und modifiziere. Ich sehe die Datei beim Öffnen aus dem Netzwerk nicht. Ich überprüfte die xlsx-Datei, als ich es im Netzwerk lesen/schreiben öffnete. Der Name des Benutzers, der sie geöffnet hat, wird in der xlsx gespeichert. Also ich denke immer noch, dass ich die Einstellung aus der XLSX-Datei lesen sollte. – nire

+0

Hmm, nein, ziemlich zweifelhaft, es wird eine .xlsx Datei ändern, nur um den Benutzernamen zu schreiben. Die einzige Falte, die ich mir vorstellen kann, ist, dass der Benutzer keinen Schreibzugriff auf den freigegebenen Ordner hat. Aber lassen Sie uns nicht raten, verwenden Sie SysInternals Process Monitor, um zu sehen, was passiert, Sie sehen Excel.exe an den Dateien (n) basteln. –

+0

Hans, du hast Recht. Procmon zeigt an, dass Excel.exe auf ~ $ ...... xlsx mit dem Ergebnis SUCCESS zugreift. Oh Mann, und jetzt sehe ich die Datei ~ $ .... xlsx auf dem Server. Ich habe auch versucht, eine XLS-Datei, für die eine ~ $ Datei nicht erstellt wird. Der Name des Benutzers wird in der tatsächlichen .xls gespeichert. Ich werde deinen Code ausprobieren und zurückmelden. – nire

0

Mit welchem ​​Teil haben Sie Probleme?

, ohne etwas über XSLX zu wissen, kann ich nur vermuten, dass: Sie Datei öffnen möchten, und geben Sie FileAccess.Read & FileShare.ReadWrite wie hier: How to read open excel file at C# danach, verwenden Sie irgendeine Art von Bibliothek XSLX in Datatable zu drehen, und extrahiere die spezifische Zeile, die du brauchst.

+0

Ich benutze die netoffice .NET Wrapper Assemblies, um die Office-Dateien und Anwendungen zu manipulieren. Das Problem ist, ich habe keine Möglichkeit, den Benutzernamen des Benutzers zu extrahieren, die (b) die Excel-Datei sperren. – nire

+0

Nun, es klingt wie Sie müssen wissen, wer bestimmte Datei und die FLAGS hat, die es zu dieser Datei geöffnet hat. PSFile-Dienstprogramm kann es über die Befehlszeile ausführen. "psfile \\ yourremoteshare C: \ test.xlsx". Wenn Sie interessiert sind, wie man es programmatisch macht, können Sie APIMonitor herunterladen und sehen, wie psfile es tut. Ich persönlich bezweifle, dass Sie auf den "Benutzernamen in der xlsx-Datei" zugreifen können, klingt für mich wie eine interne Sache. –

+0

Obwohl meine vorgeschlagene Lösung Administratorrechte erfordert, ist das nicht-Nein. Sie können den API-Monitor verwenden, um zu überprüfen, wie Excel diesen Benutzernamen von einer Remote-Datei erhält. (ZB durch welche API ruft, und ist es intern) –

Verwandte Themen