VSTO File Not Found - vsto

I am putting together a VSTO addin for MS Outlook. The addin is designed to utilize a unmanaged C++ library. Access to the library is via a C++/CLI (CLR) project. I am receiving a
File Not Found
error when running the ADDIN directly. It appears that the addin has difficulty with the associated unmanaged C++ library. The library is completely packed within the C++/CLI project and nothing using it requires knowledge of the unmanaged C++ library. The strangest aspect of this situation is that If I launch the ADDIN from Visual Studio all is loaded properly. I've validated that all libraries being used are where they are suppose to. It is unclear to me why the addin would fail to launch (when not being launched from Visual Studio).
Note: I validated this by running a test where I created a C++ library with one class and a C++/CLI library with one class that instantiates the class from the first library. I attempt to connect to the C++/CLI library from a VSTO project. I get the file not found error. I felt this was the simplest test to validate / determine what was happening.
Peter
Peter

The issue dealt with my making assumptions based on where things were placed. I had an installer that deployed the addin to the target deploy location. All files went into this folder. MY thinking was that if all the libraries are located within the same location they should all be found. This was based on the my thinking that an app runs and looks locally first for files. My mistake was that the app being run was Office Outlook - and it runs in a specific folder location. When I got the file not found I was thinking this can't be because the files are all together. BUT Office products when loading ADD Ins do not look in the location that the Add In is identified to be in (at leat for un managed DLLs - managed -- maybe different).
The end result was that the unmanaged DLL was not locatable because it did not show up in any of the seath locations of Windows. So the correct was to update the path to have the location of that add in. Which solved the issue of not found. What is annoying is that Visual Studio debugger -- looks to be working on the aspect of identifying DLLs where the application is being launched from. Which in general is fine -- except with VSTO the app being run is somewhere else -- but VS still looked in the project folder location to find the files. Making it somewhat unclear. This should not be occurring. VS debug should try or at least be configurable to operate in the context of the real world scenario. If it does -- I certainly was not able to find that configuration.
Peter

Related

Adding a reference to a DLL, while keeping it a native DLL instead of an ActiveX Control

I'm forced to use a third-party COM component in an application, and I'm having issues adding the reference to my project.
I've added this DLL as a reference to a project before, but in the past it would link directly to the DLL, such that the "Path" in the reference's properties would be filesystem path where the DLL was installed (i.e. not relative to my solution's directory). However, now, when I add the reference, the "Path" is to my project's obj directory, "Embed Interop Types" is set to True, and it's listed as an ActiveX component (which is not correct).
Then, I stumbled upon this MSDN article, which says:
If you want to add a reference to a registered COM DLL that contains an internal manifest, unregister the DLL first. Otherwise, Visual Studio adds the assembly reference as an ActiveX Control instead of as a native DLL.
Well, there you have it. That's my exact problem. I need the native DLL, but I'm getting an ActiveX Control instead. So, I did as it suggested and unregistered the DLL. However, when I then try to add the reference, I get an error saying:
A reference to ... could not be added. Please make sure that the file is accessible, and that it is a valid assembly or COM component.
If I register the DLL again, I'm able to add it as a reference, but again, it's added as an ActiveX control. At this point, I don't know what else to do. Microsoft is very clear that I must unregister it before adding it as a reference, but then Visual Studio 2013 apparently won't let me add an unregistered DLL. Any one have any idea how to work around this?
UPDATE
So, apparently a recent update to this app made COM the only option (no directly using the DLL). The fact that it was added as ActiveX didn't mean anything. The problem turned out to be that this was a 32-bit library trying to run in 64-bits. I knew that was a potential problem, but switching the platform target to x86, still resulted in an error so I ended up chasing a red herring. Turns out IIS Express 8 runs natively as 64-bits even if the platform target of the site you're debugging is 32-bit. I had to go into Visual Studio options and uncheck the flag that tells IIS Express to run 64-bit (under "Web Projects") and then everything ran fine.
So, since adding the registered DLL was pretty much a no-go, I focused instead on trying to figure out why Visual Studio wouldn't let me add it when it was unregistered. I mean, sure, I might get an error about it being an unregistered DLL once I tried to run the project, but it should at least let me add it as a reference, regardless.
I eventually stumbled upon tlbimp.exe, which according to Microsoft:
The Type Library Importer converts the type definitions found within a COM type library into equivalent definitions in a common language runtime assembly. The output of Tlbimp.exe is a binary file (an assembly) that contains runtime metadata for the types defined within the original type library.
Okay. Well anyways, I opened a Visual Studio Developer Prompt (regular cmd doesn't have tlbimp.exe on the path), and ran my DLL through it. It created a new DLL, which I was able to add as a reference, and it satisfied my project dependencies. However, I haven't tested it just yet to make sure everything still works as it should once this thing is running, so I'll update with what I find there.
UPDATE
Yeah, so this doesn't work either. I get the same error once it's running saying that the class is not registered. Only now, I can't register this DLL because tlbimp.exe removes the entry-point.

VB6 compile against side-by-side assembly

I have a DLL written in C# and set for COM visibility. I have it setup as a side-by-side assembly and can successfully deploy the application to client PCs registration free. My question is related to the development PC. Is it possible to compile against the DLL in a similar registration-free manner or is registration required on the development machine? I have tried adding the DLL directly though the Project -> References menu and get an error stating "Can't add a reference to the specific file." The DLL is sitting in the same directory as the .vbp file and I have tried adding the DLL both with and without the client app manifest being present.
I have tried adding the DLL directly though the Project -> References menu
That adds a reference to a type library. A type library is a language-independent description of the types in a COM component, VB6 uses it to know how generate efficient code and to provide type checking and auto-completion. A type library is the exact equivalent of metadata in a .NET assembly.
Traditionally, and the way VB6 did it, the type library was embedded as a resource in a DLL. So you are probably used to picking a DLL in the dialog. That however doesn't work so well when the DLL is generated by C#, the type library can only be generated after the C# code is compiled. You have to pick the .tlb file in the VB6 dialog. The traditional way starts with the COM component being described in the IDL language, the type library can be generated before the code is compiled so can easily be embedded in the final DLL. It is technically possible to do it in C# as well, but the build steps are very laborious and painful, you essentially have to build the DLL twice with different build commands.
The type library for a C# library is normally generated in one of three ways:
Using Project + Properties, Build tab, "Register for COM interop" option. This requires VS to run elevated so it can write to the registry. You start VS elevated by right-clicking its shortcut and picking "Run as Administrator"
By running Regasm.exe, using the /tlb:filename option. An alternative for the 1st bullet and necessary if you don't want to run VS elevated for some reason. Using the /codebase option on your dev machine is also wise to make it work exactly like the 1st bullet and not require putting the DLL into the GAC with gacutil.exe
By running the Tlbexp.exe utility, the type library exporter for .NET assemblies. No registration is done, it only generates the .tlb file.
The first bullet is the normal choice and very desirable because you can never forget to update the type library this way. It is perfectly fine on a dev machine since you only really care about reg-free deployment on the user's machine. You probably got into trouble by not doing this anymore.
Using the 3rd choice is okay and more compatible with your goals, run Tlbexp from the Visual Studio Command Prompt. Just keep in mind that you have to do it again when you make changes to your C# code. Forgetting this once and losing clumps of head-hair trying to figure out why your C# changes don't seem to be effective or getting hard-to-diagnose error codes gives you lots of reasons to consider the 1st bullet again :) You can emulate the reg-free scenario by running Regasm.exe with the /uninstall option.

Deploying an application on a non-dev machine, having issue with a dll

I'm not very experienced with deploying applications and i'm having an issue with my very small screen scrape application.
I use a project that handles all screen scrapes and i just call the functions from the dll(on dev machines at least). When i reference that dll from the directory, it works fine on my machine but installing and launching on another machine without the project crashes it immediately when it tries to access the class to instantiate the screen scrape object.
Perhaps my assumption of dll is incorrect but doesn't having the dll mean it incapsulates all the classes/references/etc in that project so it can be used elswhere without having to lug the whole project with it?
What could be going on with this dll?
The dll assembly encapsulates the project, but not its references. Anything that the project needs to reference must be available in the new environment as well, whether in the GAC (global assembly cache), the local directory, in a reference path, or wherever.
If you are using Visual Studio 2010 or earlier, you can use Setup Projects to nicely gather all necessary references and package them into an install package for you. There may still be complications that you will need to troubleshoot sometimes, but it simplifies your deployment effort. In Visual Studio 2012 and later, Setup Projects were dropped, but there are other options, like WIX and Install Shield. And that is a whole other topic with plenty of Q&A on this site.

How to force creation of manifest file in release folder?

This is driving me crazy. I have developed a .NET COM DLL that is used by a VB6 DLL wrapper in order to update and replace some legacy functions in an application.
I am now trying to remove the requirement to use regasm on client machines so have worked out how to do that on a test DLL which all works fine.
I branched the DLL just in case and added an app.manifest file. Everything else worked out fine and I got it all working. The manifest is embedded and Visual Studio 2012 generates a mydll.dll.manifest file in the release folder.
Then I went back to the original trunk and added an app.manifest file (no point in merging as there were no code changes). I copied the contents of the branch into the app.manifest file and built the release version. The manifest is embedded in the DLL but no mydll.dll.manifest file is generated.
I know that it's not strictly necessary to have the mydll.dll.manifest file but I'd like things to be consistent (and for some reason the test process doesn't produce the same results with the trunk version) so how can I force it to be created?
This is a VB.NET DLL project so it doesn't have (or I can't find) the 'Generate Manifest' property drop down mentioned in the first answer here. How can I set this? Or is there a way to set it by editing the project file directly?
References:
Original walkthrough article and some corrections.
Overview by Junfeng Zhang in two articles plus a useful tool
You are making a fairly common mistake. A reg-free COM manifest helps an application find a COM server without looking in the registry to locate the DLL. Embedding the manifest in the DLL is like trying to solve the chicken and egg problem, Windows cannot possibly find that manifest if it cannot locate the DLL first.
The manifest needs to be part of the client app. Which is tricky since it is VB6, it doesn't support embedding manifests in its executables.
You could tinker with the mt.exe tool, an SDK utility that supports embedding manifests in an executable. You'd have to run it by hand after building the VB6 binaries. That's unfun and very likely to cause trouble when you forget. It is in general not a joyful tool to use, documentation is meager, incomplete and unhelpful, a chronic problem with manifests.
The fall back is a separate app.exe.manifest file, what Windows will look for next when it cannot find a manifest embedded in the executable. Where "app.exe" must be renamed to the name of the VB6 program. The EXE, not the DLL. This now also gives you a chance to avoid having to register the VB6 DLL, presumably what you really want if you truly want to make your program run reg-free. The disadvantage is that it will not work when you debug your VB6 program, wrong EXE. You'd also need a vb6.exe.manifest, located in the VB6 install directory.
Needless to say perhaps, very hard to get ahead with VB6 here. It just wasn't made to help you do this, they didn't have a time machine in 1998.
I have to admit that I don't know VB at all, but in the case of C++ and C# Visual Studio projects I previously had to resort to calling mt.exe in a post-build step in order to get the DLL manifest I wanted. Maybe that workaround would work in your case as well?

Invoking .Net COM assembly from Powerbuilder application (without registration)

We have a Powerbuilder 10 application that is using .Net COM assemblies. We are trying to embed the manifest in the PB application (to invoke COM assemblies without registration). The merged manifest file has added sections for dependecies on the .Net COM assemblies. We have tries various tools to inject the new manifest with different results
- using GenMan32 to inject truncates the application from 6MB to 45KB.
- using ResourceTuner, the file size looks okay, but trying to launch application gives "Fatal Disk Error".
Any suggestions on invoked .Net ComEnabled assembly from PB without registration?
Have you tried it with an external manifest and ensured that works? If an external manifest doesn't work, then the manifest information isn't correct.
Once you have a valid external manifest, you might try the Manifest Tool (MT.EXE) from the .Net SDK. It works well with true EXE files. As Terry noted though, the PB generated executable contains additional information that tools that manipulate the EXE need to respect or they will break it.
http://blogs.msdn.com/patricka/archive/2009/12/09/answers-to-several-application-manifest-mysteries-and-questions.aspx
This is more a redirection than an answer. One thing you need to be aware of is that PowerBuilder produces executables that do not follow standards for Windows executable files. Essentially they are a bootstrap routine to load the PowerBuilder virtual machine, plus a collection of class definitions (objects). The cases you've brought up are not the first I've heard of where utilities meant to modify executables don't work on PowerBuilder executables.
As for a positive contribution on what other directions to follow, I don't really know enough to give qualified advice. If it were me, I'd try to register the COM object if ConnectToNewObject() fails, but I've got no idea if that possible or if that route is a dead end.
Good luck,
Terry.