Dependent components for the proxy have to be strong named?

Latest post 02-07-2007 4:38 PM by Roger. 7 replies.
  • 11-16-2006 6:44 PM

    • Roger
    • Top 25 Contributor
    • Joined on 11-09-2006
    • Posts 11

    Dependent components for the proxy have to be strong named?

    Hi there,

    I understand that the VSTA proxy project needs its dependent components to be strong named and put into the GAC. No doubt it has very good reasons for this requirements. But in our product some of the components for the proxy project is not strong named and changing it needs a lot of effort. Just wondering any workaround to allow us to keep them non-strong named?

     Thanks,

    Roger

  • 11-16-2006 10:58 PM In reply to

    • Gary
    • Top 10 Contributor
    • Joined on 07-13-2006
    • Posts 320

    Re: Dependent components for the proxy have to be strong named?

    Roger,

    The proxy assembly should have no dependencies other than .Net framework assemblies (2.0) and VSTA assemblies.

    As you develop your application and revise the VSTA integration layer, only the proxy assembly needs to be strong-named and installed into the GAC. 

    Each time the application's object model changes:

    1. the proxy layer should to be regenerated and installed in the GAC (to propagate the changes to the addin)

    2. the project templates should be removed and regenerated (because the addins must reference the new proxy assembly)

    3. the addins rebuilt (because the addins reference the new proxy assembly)

    Hope this helps,

    Gary 

     

     

     

  • 11-19-2006 3:52 PM In reply to

    • Roger
    • Top 25 Contributor
    • Joined on 11-09-2006
    • Posts 11

    Re: Dependent components for the proxy have to be strong named?

    Hi Gary, 

    >>The proxy assembly should have no dependencies other than .Net framework assemblies (2.0) and VSTA assemblies.

    I guess I could understand the above as the best design practice of the VSTA proxy tier rather than the VSTA proxy assembly does not allow it to rely on the dependencies other than .Net framework and VSTA assemblies.

    In our product, we plan to expose dozens of complicate classes through the Application proxy. Those classes have been defined in a set of existing library components (some of them are not strong named), we would like to reuse those types in those components instead of creating their full wrappers in the VSTA Application component. There are two reasons for it:

    1.       Reducing the duplicate classes definition.

    2.       Reducing the effort of implementing the VSTA proxy tier. To be honest, creating a full wrapper in the VSTA proxy for our existing complicate class definition is almost like an “impossible mission” in an acceptable timeframe.

     And I think when Microsoft designed the VSTA, they may have already took into account that people would use their own dependencies for the proxy assembly. At least this requirement would make the users life much easier when they implement the VSTA proxy tier.

    Roger

     

  • 12-11-2006 9:14 AM In reply to

    Re: Dependent components for the proxy have to be strong named?

    Roger, hi!

    Yes! I done some code tricks at the same problem in our team project.

    First and only way is to install all unsigned assemblies in GAC.

    I done this workaround as follows:

    1. Copy all dependent required assemblies (excluding system components which is already in gac) that is not in GAC into one folder\.

    2. Create install.cmd:

    @echo off
    dir *.dll /b > filelist.txt
    for /f %%i in (filelist.txt) do gacutil /u %%~ni
    asm filelist.txt
    for /f %%i in (filelist.txt) do gacutil /i %%i
    del filelist.txt
     
    3. Write an assembly processor asm.cs and compile into asm.exe:
     
    asm.cs:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Text;
    using System.Threading;
    using System.IO;
    using System.Text.RegularExpressions;

    namespace DASM
    {
    public class Program
    {
    public const string fileExt = "il";
    public const string keyName = "private.snk";
    public static void Main(string[] argv)
    {
    if (argv.Length > 0)
    {
    try
    {

    Console.Out.WriteLine("---");
    StreamReader sr = new StreamReader(argv[0]);
    while (sr.Peek() != -1)
    {
    string fileName = sr.ReadLine();
    if (File.Exists(fileName))
    {
    FileInfo fi = new FileInfo(fileName);
    string outputName = fi.Name.Substring(0, fi.Name.LastIndexOf('.') + 1) + fileExt;
    Console.Out.WriteLine(fileName);

    Console.Out.WriteLine("Disassembling");
    Disassemble(fileName, outputName);
    Console.Out.WriteLine("Patching");
    Patch(outputName);
    Console.Out.WriteLine("Assembing");
    Assemble(outputName);
    }
    }
    Console.Out.WriteLine("---");
    }
    catch (Exception ex)
    {
    Console.Out.WriteLine(ex.Message);
    }
    }

    }


    private static void Assemble(string outputName)
    {
    ProcessStartInfo pi = new ProcessStartInfo("ilasm.exe");
    pi.UseShellExecute = false;
    pi.Arguments = string.Format("{0} /DLL /KEY={1}", outputName, keyName);
    Process myProcess = new Process();
    myProcess.StartInfo = pi;
    myProcess.Start();
    myProcess.WaitForExit();
    }

    private static void Patch(string outputName)
    {
    ProcessStartInfo pi = new ProcessStartInfo("patch.exe");
    pi.UseShellExecute = false;
    pi.Arguments = string.Format("{0}", outputName);
    Process myProcess = new Process();
    myProcess.StartInfo = pi;
    myProcess.Start();
    myProcess.WaitForExit();
    }

    private static void Disassemble(string fileName, string outputName)
    {
    ProcessStartInfo pi = new ProcessStartInfo("ildasm.exe");
    pi.UseShellExecute = false;
    pi.Arguments = string.Format("{0} /OUT={1}", fileName, outputName);
    Process myProcess = new Process();
    myProcess.StartInfo = pi;
    myProcess.Start();
    myProcess.WaitForExit();
    }
    }
    }

     

    4. Generate strong name public key pair private.snk and extract public key token from it:

    sn.exe /k ...

    5. Write simple MSIL-patcher patch.cs and compile it into patch.exe, it shold looks like like this:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Text;
    using System.Threading;
    using System.IO;
    using System.Text.RegularExpressions;

    namespace DASM
    {
    public class Program
    {
    private const string unsignedAssembly = ".assembly extern {0}";
    private const string unsignedAssemblyNewPublicKeyToken = " .publickeytoken = (FA 75 CE 9D D3 2D 00 DC )";
    private const string oldPublicKeyToken = " .hash algorithm 0x00008004";
    private const string newPublicKeyToken =
    @"
    .publickey = (00 24 00 00 04 80 00 00 94 00 00 00 06 02 00 00 // .$..............
    00 24 00 00 52 53 41 31 00 04 00 00 01 00 01 00 // .$..RSA1........
    FB E4 78 0A 50 AF B1 36 F1 2E 3E 47 E5 A1 1B 3E // ..x.P..6..>G...>
    BF 60 B6 0D D1 2F 13 BA E7 D2 07 B1 7F 72 5D 5E // .`.../.......r]^
    98 C9 9B 6E 8E 0B 9B A9 4B 98 FD 18 53 58 0D B4 // ...n....K...SX..
    28 C2 57 67 AB 09 49 CC 4D 5D 9D B4 6E C5 77 29 // (.Wg..I.M]..n.w)
    28 0B D3 45 50 2C AC 8C 03 9D 81 47 B6 80 CA 07 // (..EP,.....G....
    01 15 38 07 35 70 0D C7 28 4B A4 7A FE 03 04 43 // ..8.5p..(K.z...C
    62 8D 98 D0 86 07 8D FE 0C 63 24 4E A5 2A 85 C6 // b........c$N.*..
    2F 07 B8 39 D4 A5 5E BC BD BC FD A6 FA F0 4B B9 ) // /..9..^.......K.
    .hash algorithm 0x00008004"
    ;

    private const string hackToken = " .hash algorithm 0x00008004";
    private const string newVersionToken = " .ver 1:9:7:8";
    private const string versionToken = " .ver 0:0:0:0";

    public static void Main(string[] argv)
    {
    if (argv.Length > 0)
    {
    try
    {
    List<string> list = new List<string>();
    using (StreamReader reader = new StreamReader(argv[0]))
    {
    while (reader.Peek() != -1)
    list.Add(reader.ReadLine());
    }
    Console.Out.WriteLine("Replacing");
    Console.Out.WriteLine(string.Format("--------{0}--------", argv[0]));
    for (int i = 0; i < list.Count; i++)
    {
    string s = list[i];
    if (s.Contains(oldPublicKeyToken))
    {
    Console.Out.WriteLine(newPublicKeyToken);
    list[i] = newPublicKeyToken;
    continue;
    }
    if (i > 0 && list[i - 1] == "{" && list[i + 1] == "}")
    {
    Console.Out.WriteLine(unsignedAssemblyNewPublicKeyToken);
    list.Insert(i, unsignedAssemblyNewPublicKeyToken);
         i++;
    }

    }
    StringBuilder sb = new StringBuilder();
    foreach (string s in list)
    {
    sb.AppendLine(s);
    }
    Console.Out.WriteLine(string.Format("--------{0}--------", argv[0]));
    using (StreamWriter writer = new StreamWriter(argv[0]))
    {
    writer.Write(sb.ToString());
    }
    }
    catch (Exception ex)
    {
    Console.Out.WriteLine(ex.Message);
    }
    }
    }
    }
    }

    This one means that all assemblieas are not signed by the private strong name key pair.

    or like this (this one was used to hack devBiz Team Plain Web Access TFS integration solution):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Text;
    using System.Threading;
    using System.IO;
    using System.Text.RegularExpressions;

    namespace DASM
    {
    public class Program
    {
    private const string oldPublicKeyToken = " .publickeytoken = (D3 E5 E5 03 F8 B0 D4 4E )";
    private const string newPublicKeyToken = " .publickeytoken = (FA 75 CE 9D D3 2D 00 DC )";
    private const string hackToken = " .hash algorithm 0x00008004";
    private const string newVersionToken = " .ver 1:9:7:8";
    private const string versionToken = " .ver 0:0:0:0";

    public static void Main(string[] argv)
    {
    if (argv.Length > 0)
    {
    try
    {
    List<string> list = new List<string>();
    using (StreamReader reader = new StreamReader(argv[0]))
    {
    while (reader.Peek() != -1)
    list.Add(reader.ReadLine());
    }
    Console.Out.WriteLine("Replacing");
    Console.Out.WriteLine(string.Format("--------{0}--------", argv[0]));
    for (int i = 0; i < list.Count; i++)
    {
    string s = list[i];
    if (s.Contains(oldPublicKeyToken))
    {
    list[i] = newPublicKeyToken;
    list[i + 1] = newVersionToken;
    Console.Out.WriteLine(list[i - 2]);
    Console.Out.WriteLine(list[i - 1]);
    Console.Out.WriteLine(list[i]);
    Console.Out.WriteLine(list[i + 1]);
    Console.Out.WriteLine(list[i + 2]);
    i += 2;
    continue;
    }
    if (s.Contains(versionToken))
    {
    if (list[i - 1] == "{" && list[i + 1] == "}")
    {
    list.Insert(i, newPublicKeyToken);
    list[i + 1] = newVersionToken;
    Console.Out.WriteLine(list[i - 1]);
    Console.Out.WriteLine(list[i]);
    Console.Out.WriteLine(list[i + 1]);
    Console.Out.WriteLine(list[i + 2]);
         Console.Out.WriteLine(list[i+3]);
         i+=2;
    }
    }
    if (s.Contains(hackToken))
    {
    list[i + 1] = newVersionToken;
    Console.Out.WriteLine(list[i - 2]);
    Console.Out.WriteLine(list[i - 1]);
    Console.Out.WriteLine(list[i]);
    Console.Out.WriteLine(list[i + 1]);
    Console.Out.WriteLine(list[i + 2]);
    }
    }
    StringBuilder sb = new StringBuilder();
    foreach (string s in list)
    {
    sb.AppendLine(s);
    }
    Console.Out.WriteLine(string.Format("--------{0}--------", argv[0]));
    using (StreamWriter writer = new StreamWriter(argv[0]))
    {
    writer.Write(sb.ToString());
    }
    }
    catch (Exception ex)
    {
    Console.Out.WriteLine(ex.Message);
    }
    }
    }
    }
    }

    this one is slightly different because all assemblies was already signed by unknown private strong name key and are to be used as precompiled Web solution assemblies...

    6. Run install.cmd once, and you have all assemblies working at GAC! Of cause, you need additional not listed here steps if it is not yours assemblies, or they are obfuscated.

    Read license agreement carefully :).

    Good luck!

  • 12-11-2006 3:18 PM In reply to

    • Gary
    • Top 10 Contributor
    • Joined on 07-13-2006
    • Posts 320

    Re: Dependent components for the proxy have to be strong named?

    Yes, I understand and will discuss w/VSTA team this week.

    -G

  • 01-22-2007 6:47 PM In reply to

    • Gary
    • Top 10 Contributor
    • Joined on 07-13-2006
    • Posts 320

    Re: Dependent components for the proxy have to be strong named?

    Hello Roger,

    I think that the workaround described in our outher discussion will cover this issue as well:

    http://www.summsoft.com/forums/239/ShowThread.aspx#239

    With or without a successful proxygen, using base type System.Object would allow the strong-named references to be untied from the proxy assembly.

    1.  You could pass the Application object root through the proxy layer as a System.Object and set a reference to your entire object model (ie: PIA) in the addin.

    2.  Or maybe as a better compromise, proxygen all strong named proxies as normal, but pass all non-strong-named assemblies as System.Objects (ie: as properties off the root object), then set a reference to assemblies in the addin to these only.

    Hope this helps,

    Gary

     

    Filed under: ,
  • 01-25-2007 4:02 PM In reply to

    • Gary
    • Top 10 Contributor
    • Joined on 07-13-2006
    • Posts 320

    Re: Dependent components for the proxy have to be strong named?

    Roger,

    "...proxygen all strong named proxies and pass all non-strong-named assemblies as System.Objects (ie: as properties off the root object) and set a reference assemblies in the addin to these only."

    Further comments from the MS VSTA team:

    Because it is not practical to provide proxygen strong-named assemblies for input (inclusion in the proxy layer), your non-strong-named assemblies can be referenced directly by an addin, but must be deployed in each addin’s ApplicationBase directory (or a subdirectory, if you setup a PrivateBinPath).

     

    Along the same line…there may be a way to simplify this deployment by commonly storing all the non-strong-named assemblies in one root/ApplicationBase directory and setting a PrivateBinPath for each addin’s directory below the root.  You would have to try this to see if it works.

     

    ==

     

    I had another thought:

    It may be easier for you to create interop assemblies for your TLBs (interop assemblies are auto-generated by setting a reference to a COM component in a Visual Studio managed project). 

    Each interop assembly could probably be strong-named, GAC’ed, and referenced by the addin. 

    Then, at startup, the addin’s proxy would supply a generic Object reference passed along from the host app (via IDispatch), and the Object would be cast to a strong type defined in the interop assembly.

     

    Regards,

    Gary

     

  • 02-07-2007 4:38 PM In reply to

    • Roger
    • Top 25 Contributor
    • Joined on 11-09-2006
    • Posts 11

    Re: Dependent components for the proxy have to be strong named?

    Thanks Gary. We'll try the above solutions.

     Roger

Page 1 of 1 (8 items) | RSS
Copyright Summit Software Company, 2008. All rights reserved.