问题
A coworker alerted me to this handy piece of VBA he found on the web, which unlocks a worksheet in Microsoft Excel without a password:
Sub PasswordBreaker()
'Breaks worksheet password protection.
Dim i As Integer, j As Integer, k As Integer
Dim l As Integer, m As Integer, n As Integer
Dim i1 As Integer, i2 As Integer, i3 As Integer
Dim i4 As Integer, i5 As Integer, i6 As Integer
On Error Resume Next
For i = 65 To 66: For j = 65 To 66: For k = 65 To 66
For l = 65 To 66: For m = 65 To 66: For i1 = 65 To 66
For i2 = 65 To 66: For i3 = 65 To 66: For i4 = 65 To 66
For i5 = 65 To 66: For i6 = 65 To 66: For n = 32 To 126
ActiveSheet.Unprotect Chr(i) & Chr(j) & Chr(k) & _
Chr(l) & Chr(m) & Chr(i1) & Chr(i2) & Chr(i3) & _
Chr(i4) & Chr(i5) & Chr(i6) & Chr(n)
If ActiveSheet.ProtectContents = False Then
MsgBox "One usable password is " & Chr(i) & Chr(j) & _
Chr(k) & Chr(l) & Chr(m) & Chr(i1) & Chr(i2) & _
Chr(i3) & Chr(i4) & Chr(i5) & Chr(i6) & Chr(n)
Exit Sub
End If
Next: Next: Next: Next: Next: Next
Next: Next: Next: Next: Next: Next
End Sub
It works, and it does so very quickly.
We have a VSTO extension to Excel, and we wanted to add this feature. A near-literal (still discrete looping, no recursion or anything) translation of the code above into C# is as follows:
public static string Unprotect()
{
var addIn = Globals.ThisAddIn;
Excel.Worksheet sheet = addIn.Application.ActiveSheet;
if (!sheet.ProtectContents)
return "This sheet was not protected";
int[] la = new int[] { 65, 66 };
foreach (int i in la)
foreach (int j in la)
foreach (int k in la)
foreach (int l in la)
foreach (int m in la)
foreach (int i1 in la)
foreach (int i2 in la)
foreach (int i3 in la)
foreach (int i4 in la)
foreach (int i5 in la)
foreach (int i6 in la)
for (int n = 32; n <= 126; n++)
{
string password = string.Format(
"{0}{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}{11}",
(char)i, (char)j, (char)k, (char)l, (char)m,
(char)i1, (char)i2, (char)i3, (char)i4, (char)i5,
(char)i6, (char)n);
try
{
sheet.Unprotect(password);
if (!sheet.ProtectContents)
return password;
}
catch (Exception ex)
{
}
}
return "Fail.";
}
This works equally successfully, however in cases where it takes a long time to find the password, the VBA solution trounces the C# solution in performance. The difference can be < 1 second versus 1 1/2 minutes.
I know try-catch is generally an expensive operation, and having to catch every failed attempt is what's dragging performance down.
I'm guessing the Excel VBA's on error resume next
must be a fairly lightweight operation?
Does anyone know of an alternative to the try-catch in this instance, perhaps an Excel com-specific way to handle this? In my mind I'm thinking of Int32.TryParse or Dictionary.TryGetValue.
来源:https://stackoverflow.com/questions/27434135/alternatives-to-try-catch-in-vsto