How to get mshtml.IHTMLDocument6 or mshtml.IHTMLDocument7? - c#

I am using IE11 in Windows 7.
Then I added a reference in C# project c:\Windows\System32\mshtml.tld and try to get mshtml.IHTMLDocument6 or mshtml.IHTMLDocument7, but VS2013 doesn't see it.
I can only get mshtml.IHTMLDocument, mshtml.IHTMLDocument2 .. mshtml.IHTMLDocument5.
IHTMLDocument7 interface https://msdn.microsoft.com/ru-ru/library/windows/hardware/ff975572

Select the MSHTML assembly reference, look at its Path property and you'll see the problem:
C:\WINDOWS\assembly\GAC\Microsoft.mshtml\7.0.3300.0__b03f5f7f11d50a3a\Microsoft.mshtml.dll
This is the PIA for the mshtml type library, installed on any programmer's machine that has VS installed. Version 7.0.3300 is a version number from the .NET 1.0 era, it is 14 years old. Predates IE11 of course, that's why it doesn't have the later interface types. Using the PIA is never the wrong thing to do, it ensures that your program will run with any version of IE, all the way back to IE6.
But that's not what you want, you'll have to generate your own interop library from the IE11 type library. Run the Visual Studio Command Prompt, navigate to your project directory and type this command:
Tlbimp c:\windows\system32\mshtml.tlb /out:Interop.mshtml.dll
It will trundle for quite a while, it is a big one, and spit out several warnings about the PIA being present and several obscure methods and types that cannot be directly used from a .NET program. You can ignore them, they didn't work in the PIA either.
You now have the Interop.mshtml.dll file in your project directory. Back to VS, delete the old MSHTML reference and use Project > Add Reference > Browse to select the new one you just created. Its "Embed Interop Types" property is True by default, no longer a need for a PIA at all and you don't have to deploy the file with your program. Check the file into source control so you only have to do it once.
And be careful, your program can die with an E_NOINTERFACE exception when it runs on machine that doesn't have the required version of IE installed. You can use the as operator to cast the document reference to IHtmlDocument7, it will be null if IE is old.

Related

Run two versions of the same unmanaged dll (referenced by C#-app)

Background
I have two softwares, written in C#, using the same third-party dll to get telephony-capabilities.
Problem
When I deploy a new version of one of these softwares, I also deploy a new version of the dll. This one overwrites the references to the older dll, causing my other software to stop working, since the new dll isn't backwards compatible.
Attempted solutions
Deploy the new software with a registration-free version of the dll.
This doesn't work since the dll doesn't have a strong name. Result from sn:
C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools>sn.exe -e "theDll.dll" key
Microsoft (R) .NET Framework Strong Name Utility Version 4.0.30319.17929
Copyright (c) Microsoft Corporation. All rights reserved.
theDll.dll does not represent a strongly named assembly
Ask the vendor for a strongly named version
This resulted in a "huh?". The dll works well however, so I don't want to look for a new vendor if I dont really have to.
Give the dll a strong name using ildasm:
C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools>ildasm.exe "theDll.dll" /out=theDll.il
error : 'theDll.dll' has no valid CLR header and cannot be disassembled
Which seems to imply that the dll is unmanaged, and thus not possible to strongly name (if I'm not mistaken).
Use SetDllDirectory and LoadLibrary to load the correct version of the dll.
This seems to kinda work, at least I can load the correct dll from a specified place without registering it. This seems like a rather involved way to do it though.
Questions
Has anyone done this the "LoadLibrary"-way and can verify that it works well for a dll where you need to instantiate some classes?
Does anyone have a better solution?
This instruction told me how to construct an appropriate manifest file for an unmanaged COM: https://msdn.microsoft.com/en-us/library/ms973913.aspx
A few important points I don't feel they covered so that I easily understood:
Oleview.exe is one way of getting the info you'll need for the manifest. It is possible to find your dll both by using Object classes-> All objects (provided it is registered with regsvr32) or by using File-> View TypeLib. I felt both these were needed before I had all information (they display different information).
When you have your manifest file, it is sufficient to chose "Add reference" in Visual studio, selecting the "Browse"-tag and then the COM-manifest you created. After that, programming is exactly as if the COM had been registered. VS will create the manifest for your program.
Of course you'll need to make sure your setup project deploys the .dll and its manifest to the same folder as your .exe.

How can I add a reference to a project of a Windows native DLL?

I'm trying to add Windows/System32/Shell32.dll DLL to my project. The issue is, it copies the reference to the directory! Since this is a windows file, it shouldn't have to come with me if I were to deploy my application.
I have tried stopping it from copying to the directory, tried looking for how to embed the resource in the application and even added reference paths to System32. It seems so much more challenging than the program just using the local DLL from the system...
What can I do?
Shell32.dll is a COM component. You should not get a copy of it in your project. What you get instead is Interop.Shell32.dll. Which is a .NET assembly, not a copy of Shell32.dll. It contains the COM interface and class declarations, converted from the type library definition inside Shell32.dll to friendly .NET declarations that the CLR knows how to easily handle.
This is an optimization, it avoids having to make the conversion at runtime. Which is expensive, subject to various options (check the MSDN docs for Tlbimp.exe) and may easily fail because there is no general requirement that the type library is also available on the target machine.
You must deploy Interop.Shell32.dll to the target machine, just like you do with any .NET class libraries you'd use.
Do note that this interop library is no longer needed on .NET 4 and VS2010. Which acquired the "Embed Interop Types" feature. In other words, instead of keeping the interop types in a separate assembly, the C# and VB.NET compilers can now embed them in your program. Very highly recommended, just set the option to True in the Properties window view of the Shell32 reference.

Assembly binding error when building Office add-in: "FindRibbons" task failed unexpectedly

We're trying to set up a Jenkins (build server) job to build our Office add-in based on VSTO. However, I keep getting a strange error that fails the build process after the DLL is copied to the bin directory of the project:
Error 11 The "FindRibbons" task failed unexpectedly.
System.IO.FileNotFoundException:
Could not load file or assembly 'MyAddIn, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null' or one of its dependencies.
The system cannot find the file specified.
File name: 'MyAddIn, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'
So the problem is that the "FindRibbons" task, triggered by the Office add-in build target, has successfully identified the MyAddIn DLL as being an Office Add-In, but is not able to locate and load it!
Any ideas? I'd love to be able to debug the FindRibbons task directly but hooking into and debugging the compile process seems a little extreme...
Here are some observations:
In our build server's Fusion logs for binding the MyAddIn assembly it looks like it's looking in the folder where MSBuild.exe lives (C:\Windows\Microsoft.NET\Framework\v4.0.30319\) and nowhere else.
On my dev machine, there is no Fusion log entry for MyAddIn! But the build process succeeds and Kivo works fine.
On both my dev and build machines I also have Fusion log entries for WhereRefBind!Host=(LocalMachine)!FileName=(PresentationCore.dll) and ExplicitBind!FileName=(MyAddIn.dll) which show the binding succeeding.
This error comes up on the build server whether I use Visual Studio or MSBuild from the command line to build the project.
I've ensured that the .NET/MSBuild/VS2012 versions are identical on both my dev machine and the build server and the error still occurs. The only difference seems to be that the build server is running Windows Server 2012 (since it's Azure, and we can't spin up a Windows 7 image).
This has worked for me every time I upgrade Visual Studio - I don't use ribbons.
This worked for my solution, but use at your own risk:
Open the following file in an XML editor (make a backup first): C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\OfficeTools\Microsoft.VisualStudio.Tools.Office.targets (the v10.0 part may be different for you, e.g., it might be v14.0)
Remove the following section:
<FindRibbons AssemblyName="$(AbsolutePathToCustomization)" TargetFramework="$(TargetFrameworkVersion)">
<Output TaskParameter="RibbonTypes" ItemName="RibbonTypesCollection"/>
</FindRibbons>
Replace all occurrences of "#(RibbonTypesCollection)" with the empty string ""
Save the file and restart the visual studio
If you migrated the project from a previous version of Visual Studio, be sure to remove the ExcelLocale1033 and SecurityTransparent attributes from the AssemblyInfo.cs file (as answered by Swati in this other question)
If the project still fails to build, it may be because your .csproj file has some references to msbuild's tasks of previous versions of Visual Studio. I suggest you to create a new empty Excel AddIn project, and uses the msbuild structure of the new project file as base for your project.
I had this problem. It was apparently caused because I changed the "Copy Local" setting on reference "Microsoft.Office.Tools.Common.v4.0.Utilities" from True to False. ISYN. (I sh*t you not)
I had upgraded a project from VS2012 to VS2013 and noticed that that reference was the only one set to "Copy Local = True". So I set it to false, because it was different. This caused the error. Changing it back to True solved it.
I had the same error message and finally found a fix. The problem stemmed from the VSTO project being targeted for .NET 4.0 (it seems this is the minimum for VSTO4), while also referencing an assembly built for .NET 3.5. The real culprit was that I had a class in the VSTO project deriving from an interface defined in the .NET 3.5 assembly that in turn derived from a .NET 3.5 library interface. i.e.,
using System.Xml;
class MyVSTOClass : IMy35AssembyInterface // This caused the error
class MyVSTOClass : IXmlSerializable // This compiled OK
using System.Xml;
interface IMy35AssembyInterface : IXmlSerializable
The fix was to update the .csproj to explicitly reference the older version of System.Xml.dll and System.Data.dll which would otherwise default to 4.0 and conflict with the 3.5 assembly references.
<Reference Include="System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
      <!--<Aliases>Data2</Aliases>-->
      <HintPath>C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Data.dll</HintPath>
      <SpecificVersion>True</SpecificVersion>
      <Private>False</Private>
    </Reference>
 <Reference Include="System.XML, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
      <!--<Aliases>Xml2</Aliases>-->
      <HintPath>C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Xml.dll</HintPath>
      <SpecificVersion>True</SpecificVersion>
      <Private>False</Private>
    </Reference>
For those who need to simultaneously reference both the newer and older versions of a DLL, note that it is in theory possible using:
extern alias XmlDll1
using XmlDll1::System.Xml
See http://geekswithblogs.net/narent/archive/2008/11/11/126940.aspx for more info.
This problem can also be caused by adding a reference to an unsigned assembly to a signed/strong named add-in project. In my case I added the RestSharp Nuget package and started receiving this error on build as soon as I referenced RestSharp in code. After some digging I noticed that RestSharp was the only unsigned assembly in the project references. If you have this problem, there are 3 possible solutions:
In the case of RestSharp, I found that there was a signed version available on Nuget - searched for "restsharp signed" and installing that solved the problem.
If you have access to the source code, you can configure Visual Studio to build a signed version of the assembly in the Project Properties page.
If you do not have access to the source code, you can sign the assembly with your own key by following these instructions.
I had the same error and none of the answers from the internet help me fix this problem. The reason why I was getting that error is because I was referencing an assembly of type Console Application. I changed that assembly to be of type ClassLibrary and I did not got that exception any more.
Also I would only get that exception when inheriting from a class that was located on my ConsoleApplication. It took me forever to figure it out.
May be a little late here, but I just resolved this for myself - after following numerous suggestions (via google) all of which did not solve my problem I manually went down the line. Turns out I had compiled a set of libraries with a dependent assembly with a lower version (not the latest). In my main project I also had a reference to this dependency but it was pulled via nuget and was at the latest & greatest version. For some reason VS.NET couldn't figure that out and would completely trip out and drop the error you posted. Once I updated the set of libraries to the latest version of the dependency all worked as normal.
The crazy part is - it worked fine initially and then out of nowhere the issue came about. Hope this helps someone along the way.
After enabling Fusion the output showed that it was looking for the assembly in the msbuild/ folder.
I just encountered this same situation today, futzing around for a bit, restarting VS and then rebooting my machine without any success. Than one warning popped out at me - One of my dependent assemblies was not strong named. Setting that assembly to be strong-named solved the problem.
I had the same issue, and even after reading KKG's answer I could not resolve mine.
It turned out to be much simpler for me, but not less frustrating and time consuming. I was working in a Win8.1 VM which does not ship with .net3.5 by default. My .net4 VSTO4 project was referencing an assembly that requires 3.5 somewhere. The same project compiled find on my other VM which was Server2008 and had 3.5 enabled.
In my case, the cause for this error was the mere existence of a field of a generic value type in the assembly (not kidding), e.g.:
class Foo
{
ImmutableArray<int> foo;
}
Workaround (if the additional indirection is acceptable performance-wise):
Wrap the value type in a reference type. This can be done generically with something like
public sealed class Box<T>
{
public readonly T value;
public Box(T value)
{
this.value = value;
}
}
then foo can be of type Box<ImmutableArray<int>>.
I have experienced this same issue with an add-in for Outlook.
The solution for me was to set Embed Interop Types to True on my reference to Office.dll.
This however caused the add-in to crash during startup with an Access Denied on Microsoft.Office.Interop.Outlook. I fixed that issue by setting Embed Interop Types to True on all references to Microsoft.Office.Interop.Outlook.dll as well.
This error can be caused by a clash of dependency versions. For example:
YourAddIn
-- OtherLibrary v1.3
-- BaseLibrary v1.0
-- BaseLibrary v2.0
If a newer version of BaseLibrary v2.0 is released and updated in your project, however this version introduce a breaking change in your other dependency OtherLibrary, you will see this exception because OtherLibrary is still trying to find the old methods that doesn't exist in newer assembly.
Update OtherLibrary with the latest packages will resolve this clash of dependency versions.
This can also happen if the Microsoft.Office.Tools.Outlook.v4.0.Utilities reference is set to <Private>False</Private>.
<Reference Include="Microsoft.Office.Tools.Outlook.v4.0.Utilities">
<!-- Required for FindRibbons task -->
<Private>True</Private>
</Reference>

How does the ".NET for Metro style apps" reference in VS11 Beta work, exactly?

When you create a new C# Metro style app in VS11 beta, it only has two references: one to Windows.winmd, which is a file and I get that; and one to ".NET for Metro style apps", which appears to point to the .NETCore folder under Reference Assemblies and not to any file in particular. The File Type property for both references is "SDK".
Am I right in guessing that the folder reference effectively references every file in that folder? Are there any particular compile-time things that go on there that are interesting? Is there a way I can create a folder which can be referenced the same way?
You can see this when you bump up the build verbosity, Tools + Options, Projects and Solutions, Build and Run, MSBuild project build output verbosity setting. It gets interesting just after "TargetMonikerDisplayName" with a message that shows what reference assemblies it calculates and the Task "Csc" notification that shows the command line options being passed to the C# compiler.
You'll see it passes them all. I've got 71 references assemblies in the .NETCore\v4.5 directory and the compiler gets 72 /reference options, 1 extra for Windows.winmd
So you can always write code like this in a C# Metro app ;)
string newline = Microsoft.VisualBasic.Constants.vbCrLf;
If you build the project using msbuild on the console you will be able to see what exactly is happening. All the .Net references are passed to the compiler as /reference compiler option, so I don't think there is anything special or interesting happening there on the compile time.
It seems that there is some special work done on msbuild to include the references for Windows SDK and .Net, rather than a standard feature that can be used for other purposes. If you open the csproj file you can see that all .Net and Windows references are added automatically.

How do I create and use a .NET metadata-only 'Reference Assembly'?

Since version 3.0, .NET installs a bunch of different 'reference assemblies' under C:\Program Files\Reference Assemblies\Microsoft...., to support different profiles (say .NET 3.5 client profile, Silverlight profile). Each of these is a proper .NET assembly that contains only metadata - no IL code - and each assembly is marked with the ReferenceAssemblyAttribute. The metadata is restricted to those types and member available under the applicable profile - that's how intellisense shows a restricted set of types and members. The reference assemblies are not used at runtime.
I learnt a bit about it from this blog post.
I'd like to create and use such a reference assembly for my library.
How do I create a metadata-only assembly - is there some compiler flag or ildasm post-processor?
Are there attributes that control which types are exported to different 'profiles'?
How does the reference assembly resolution at runtime - if I had the reference assembly present in my application directory instead of the 'real' assembly, and not in the GAC at all, would probing continue and my AssemblyResolve event fire so that I can supply the actual assembly at runtime?
Any ideas or pointers to where I could learn more about this would be greatly appreciated.
Update: Looking around a bit, I see the .NET 3.0 'reference assemblies' do seem to have some code, and the Reference Assembly attribute was only added in .NET 4.0. So the behaviour might have changed a bit with the new runtime.
Why? For my Excel-DNA ( http://exceldna.codeplex.com ) add-in library, I create single-file .xll add-in by packing the referenced assemblies into the .xll file as resources. The packed assemblies include the user's add-in code, as well as the Excel-DNA managed library (which might be referenced by the user's assembly).
It sounds rather complicated, but works wonderfully well most of the time - the add-in is a single small file, so no installation of distribution issues. I run into (not unexpected) problems because of different versions - if there is an old version of the Excel-DNA managed library as a file, the runtime will load that instead of the packed one (I never get a chance to interfere with the loading).
I hope to make a reference assembly for my Excel-DNA managed part that users can point to when compiling their add-ins. But if they mistakenly have a version of this assembly at runtime, the runtime should fail to load it, and give me a chance to load the real assembly from resources.
To create a reference assembly, you would add this line to your AssemblyInfo.cs file:
[assembly: ReferenceAssembly]
To load others, you can reference them as usual from your VisualStudio project references, or dynamically at runtime using:
Assembly.ReflectionOnlyLoad()
or
Assembly.ReflectionOnlyLoadFrom()
If you have added a reference to a metadata/reference assembly using VisualStudio, then intellisense and building your project will work just fine, however if you try to execute your application against one, you will get an error:
System.BadImageFormatException: Cannot load a reference assembly for execution.
So the expectation is that at runtime you would substitute in a real assembly that has the same metadata signature.
If you have loaded an assembly dynamically with Assembly.ReflectionOnlyLoad() then you can only do all the reflection operations against it (read the types, methods, properties, attributes, etc, but can not dynamically invoke any of them).
I am curious as to what your use case is for creating a metadata-only assembly. I've never had to do that before, and would love to know if you have found some interesting use for them...
If you are still interested in this possibility, I've made a fork of the il-repack project based on Mono.Cecil which accepts a "/meta" command line argument to generate a metadata only assembly for the public and protected types.
https://github.com/KarimLUCCIN/il-repack/tree/xna
(I tried it on the full XNA Framework and its working afaik ...)
Yes, this is new for .NET 4.0. I'm fairly sure this was done to avoid the nasty versioning problems in the .NET 2.0 service packs. Best example is the WaitHandle.WaitOne(int) overload, added and documented in SP2. A popular overload because it avoids having to guess at the proper value for *exitContext" in the WaitOne(int, bool) overload. Problem is, the program bombs when it is run on a version of 2.0 that's older than SP2. Not a happy diagnostic either. Isolating the reference assemblies ensures that this can't happen again.
I think those reference assemblies were created by starting from a copy of the compiled assemblies (like it was done in previous versions) and running them through a tool that strips the IL from the assembly. That tool is however not available to us, nothing in the bin/netfx 4.0 tools Windows 7.1 SDK subdirectory that could do this. Not exactly a tool that gets used often so it is probably not production quality :)
You might have luck with the Cecil Library (from Mono); I think the implementation allows ILMerge functionality, it might just as well write metadata only assemblies.
I have scanned the code base (documentation is sparse), but haven't found any obvious clues yet...
YYMV

Categories

Resources