Alternatives to try/catch in VSTO

空扰寡人 提交于 2019-12-11 20:10:06

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!