views:

592

answers:

2

InternalsVisibleTo is not working for my managed C++ projects, but it is for my C# projects. Any help would be appreciated. Here is a simplified layout.

Project A - C#, has an internal property I want to access from B/C.
Project B - Managed C++. References A.
Project C - C#, references A.

All projects are signed with the same key. Looking at the compiled assemblies with ILDASM or Reflector show that they are all signed correctly (when I comment out the internal property usage).

In AssemblyInfo.cs in Project A, I have the following InternalsVisibleTo;

[assembly: InternalsVisibleTo( "B, " +
   "PublicKey=00240000048000009400000006020000002400005253413100040000010001007" +
   "50098646D1C04C2A041FAAF801521A769535DE9A04CD3B4DEDCCBF73D1A6456BF4FE5881451" +
   "0E84983C72D0460B8BA85C52A9CACDC4A0785A08E247C335884C2049ECFE6B2C5E20A18FE4B" +
   "9BFF009ADA232E980D220B3C9586C9C5EE29C29AEE8853DB7BB90CF5A4C704F5244E1A1085C" +
   "4306008535049A0EBB00FE47E78DCB" )]

[assembly: InternalsVisibleTo( "C, " +
   "PublicKey=00240000048000009400000006020000002400005253413100040000010001007" +
   "50098646D1C04C2A041FAAF801521A769535DE9A04CD3B4DEDCCBF73D1A6456BF4FE5881451" +
   "0E84983C72D0460B8BA85C52A9CACDC4A0785A08E247C335884C2049ECFE6B2C5E20A18FE4B" +
   "9BFF009ADA232E980D220B3C9586C9C5EE29C29AEE8853DB7BB90CF5A4C704F5244E1A1085C" +
   "4306008535049A0EBB00FE47E78DCB" )]

The keys are cut'n'pasted, so I know they are correct.

When I try to compile, A & C compile fine, but project B fails with

Error 1 error C3767: 'A::MyClass::MyProperty::get': candidate function(s) not accessible c:\Users\<snip>\CppClass.cpp 201 B

The MSDN docs say this works with C++. Is there a bug or something else I need to do?

Is there another way that I can protect a property so that it can only be used by assemblies signed by me? I know I can protect all of my assembly, but can I do it on a granular level like this?

EDIT

Based on comments in MSDN, I changed the attribute to the following, but that still doesn't work.

[assembly: InternalsVisibleTo( "B, " +
   "PublicKey=00240000048000009400000006020000002400005253413100040000010001007" +
   "50098646D1C04C2A041FAAF801521A769535DE9A04CD3B4DEDCCBF73D1A6456BF4FE5881451" +
   "0E84983C72D0460B8BA85C52A9CACDC4A0785A08E247C335884C2049ECFE6B2C5E20A18FE4B" +
   "9BFF009ADA232E980D220B3C9586C9C5EE29C29AEE8853DB7BB90CF5A4C704F5244E1A1085C" +
   "4306008535049A0EBB00FE47E78DCB" ),
InternalsVisibleTo( "C, " +
   "PublicKey=00240000048000009400000006020000002400005253413100040000010001007" +
   "50098646D1C04C2A041FAAF801521A769535DE9A04CD3B4DEDCCBF73D1A6456BF4FE5881451" +
   "0E84983C72D0460B8BA85C52A9CACDC4A0785A08E247C335884C2049ECFE6B2C5E20A18FE4B" +
   "9BFF009ADA232E980D220B3C9586C9C5EE29C29AEE8853DB7BB90CF5A4C704F5244E1A1085C" +
   "4306008535049A0EBB00FE47E78DCB" )]
A: 

This tool can it be useful : PInvoke Interop Assistant
http://www.codeplex.com/clrinterop/Release/ProjectReleases.aspx?ReleaseId=14120

Good luck.

lsalamon
I am using managed C++, PInvoke isn't involved.
Rob Prouse
This isn't relevant to the question at all.
Peter Oehlert
+4  A: 

I found the answer to this. C++ works differently than the other languages. In addition to the InternalsVisibleTo, you must reference assembly A with the as_friend keyword. Since as_friend is not an option in the Add References dialog, you cannot add a project reference, instead, you need to add a reference in each CPP file that you needs it.

#using <A.dll> as_friend

You then also need to change your assembly search path to include the build directory of project A.

IMHO, this is broken and typical of managed C++ being a second class language. Without the ability to do project references, you end up referencing the assembly in the build debug or release directory. This breaks dependencies and the only way you can get it to reference the correct DLL when you change your configuration from debug to release is with ugly #IFDEF DEBUG and relative paths for the #using.

I was also disappointed that this wasn't mentioned in the InternalsVisibleToAttribute documentation. I needed to dig around in the C++ documentation to find the information.

Rob Prouse
Have you found a way to let a C# assembly see the internals of another built with C++? As far as I can tell, there's no way to set anything like as_friend in c#.
Rick Minerich
FWIW, you don't need to use #ifdefs to reference the correct DLL. Instead, you can set the path for #using references in project properties, C/C++, General, Resolve #using references. Here you can use the configuration macros, such as $(ConfigurationName) and others to specify the paths to used assemblies.
Bojan Resnik