Weird problem with Visual Studio 2008 website reference - vb.net

I'm trying to add a reference to the GAC version of System.Xml in a Visual Studio 2008 web site project. I right-click the project icon in the Solution Explorer, and click Property Pages. Under the References tree option, I click the 'Add' button on the right. I navigate to System.Xml in the .NET tab, and double click it (the Path it lists for System.Xml, C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.XML.dll, DOES exist). The dialog disappears, but... System.Xml does not get added as a reference! The list just stays the same.
I tried adding another .NET reference just to make sure others could be added OK, I added System.Web.RegularExpressions and it added fine. What on earth could be causing it not to add System.Xml?

Try to edit your vbproj file, and add
<Reference Include="System.Xml" />

I just created a ASP.NET Website with default language C# & .NET 2.0 as the target. I also observed that even if you try to add a reference to System.XML, you will not find one in the project proprieties page.
As far it goes for me, its as designed.
By default you can access all the default .NET namespaces (in your target version) by just adding "using NAMESPACE_NAME;" in you code behind.(System (& the sub namespaces like XML etc). ASP, Microsoft & MS) Only when you reference a third party .NET dll or something that's not default for an ASP.NET Website project (could not find the list of defaults on the net), then a new folder called bin is created & a copy of that dll is stored in it if it is not in GAC.
EDIT: Regarding not able to add a cs file to vb file, I just did that, & I could access System.Xml namespace in the vb file.

Well it looks like it might have had something to do with my trying to add a .cs file to a project where the rest of the files were in vb.net. Hmph, I thought one of the major benefits of .NET was you could easily mix languages. Oh well, I removed that and added these lines into my web.config file:
<add namespace="System.Xml"/>
and
<add assembly="System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
and now it compiles OK. I can access System.Xml from within VB code, so it looks like I'll have to translate the class I had from C# to VB.net. Hmph.

Related

How do I expose a .netstandard2.0 library with COM for use in VB6?

I have a dotnet core library, a framework 4.7.2 library and a vb6 application.
I want to write a common library for them all to access and so choose .netstandard2.0
I tried a the 4.7.2 framework wrapper library between .netstandard2.0 library and vb6.
However I ran into assembly binding problems
Looking at the docs I see
In .NET Core, the process for exposing your .NET objects to COM has been significantly streamlined in comparison to .NET Framework.
However no mention .netstandard2.0
I decided to try following the docs anyway even though my project is using .netstandard2.0
I got up to the instructions on Generating the COM Host in which case the output files ProjectName.dll, ProjectName.deps.json, ProjectName.runtimeconfig.json and ProjectName.comhost.dll should build.
However the ProjectName.comhost.dll and ProjectName.runtimeconfig.json do not create.
I see in this dotnet standard issue that Microsoft plans on having tooling support in "Preview 4"
I am running VS 16.4.5
[Update]
I decided to try making a .net core wrapper library and enabling it for com.
I was able to add my .netstandard to the wrapper library via a nuget package (I build the .netstandard library using azure devops)
When I build my wrapper library the .dll, .deps.json, .pdb, .runtimeconfig.dev.json and .runtimeconfig.json files are created in a bin\Debug\netcoreapp3.1 folder.
However none of the .netstandard library files appear in the bin\debug folder.
I copied the .netstandard library and the .netcore wrapper libraries to the same folder and ran
regsvr32 MyCoreComWrapper.comhost.dll
However no .tlb file is created which I need to be able to use from VB6
I note the following in the docs
Unlike in .NET Framework, there is no support in .NET Core for
generating a COM Type Library (TLB) from a .NET Core assembly. The
guidance is to either manually write an IDL file or a C/C++ header for
the native declarations of the COM interfaces.
I found some information on github but would love a step by step guide to making the .tlb
I thought about using latebinding instead but am unsure of how to use it with a com library.
[Update]
I put a sample project on GitHub including some VB6 files.
With VB6 referencing the .tlb referenced with the framework library.
When I try to run that I get
Could not load file or assembly 'Microsoft.EntityFrameworkCore, Version=3.1.2.0,
Culture=neutral, PublicKeyToken=adb9793829ddae60' or one of its dependencies. The system cannot find the file specified.
So I copied all the files from my framework test project to my vb6 folder, rebuilt and ran.
Then I got the error
Could not load file or assembly 'Microsoft.Extensions.DependencyInjection.Abstractions, Version=3.1.0.0,
Culture=neutral, PublicKeyToken=adb9793829ddae60' or one of its dependencies. The system cannot find the file specified.
I see the file Microsoft.Extensions.DependencyInjection.dll is present with File version 3.100.220.6706
Regarding the .NET standard, I may be wrong but I think this is not applicable here because the COM interop stuff are at a higher level than the one .NET standard is targeting; we can only talk about either .NET Core or .NET Framework for COM interop.
If you want to generate a type library, you have few options.
By far, the easiest method is just to use .NET Framework. The fact that you are wanting to create a type library negates the advantages of .NET Core already because several COM, especially the "Automation" features are Windows-only. Using framework will be fine at least until .NET Core 5 comes out.
That said, if you have a business reason for using .NET Core but still need COM support, including the type library, then based on this GitHub comment, you should be able to compile your own IDL. Note that requires you to install C++ build tools because the MIDL compiler is not really a standalone thing that you can get without the rest of the C++ build tools.
It is strongly suggested to have had read the documentation on how .NET Core handles COM activation.
Assuming having the C++ build tools is not a barrier for you, the steps would be the following:
1) Create a .idl file that defines all your COM interfaces in the IDL format. That requires some translation between the .NET interface and the COM interface. Here's a partial example of how you'd need to translate between your C# interface and COM interface as defined in IDL:
[
Guid("<some gooey>"),
InterfaceType(ComInterfaceType.InterfaceIsDual)
]
public interface IFoo
{
string Bar { get; }
string Baz(int Fizz);
}
Would be translated into IDL:
[
uuid(<assembly gooey>),
version(1.0)
]
library myFoo
{
[
uuid(<some gooey>),
object,
dual
]
interface IFoo : IDispatch {
[propget] HRESULT Bar([out, retval] BSTR* retVal);
HRESULT Baz([in] long Fizz, [out, retval] BSTR* retVal);
}
}
Once you've defined the .idl file and it is an accurate representation, you can then use MIDL to compile the .idl file into a .tlb file. Usually something like midl foo.idl /tlb: foo.tlb. You should make use of the MIDL language reference to help you write the .idl file. As a quick way to get started, you could copy your C# interfaces to a .NET framework project, use tlbexp, then use oleview (available via Visual Studio Developer Command Prompt) or olewoo to view the resulting IDL file to get you started.
The next step is to then create registry keys so that your CLSID can reference the type library. You will need to have your assembly's GUID handy and it must be used as the library's uuid in the .idl file as well.
Using IFoo interface example, you would need to create the registry similar to below (using .reg format for easy sharing/comprehension and assuming per-user installation, rather than per-machine):
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Classes\Interface\{<some gooey>}]
#="IFoo"
[HKEY_CURRENT_USER\Software\Classes\Interface\{<some gooey>}\ProxyStubClsid32]
#="{00020424-0000-0000-C000-000000000046}"
[HKEY_CURRENT_USER\Software\Classes\Interface\{<some gooey>}\TypeLib]
#="{assembly gooey}"
"Version"="1.0"
You will also need to create the registry in the CLSID, Interface, TypeLib, and Record as needed. This article provides a good overview of all registry keys but keep in mind it's assuming .NET framework, not .NET Core, so not all keys are applicable, especially under the CLSID branch.
Note that when you run the regsvr32, it will normally create the keys in the CLSID and Interface branches but you will need to add the TypeLib keys under the Interface's branch and also an entry to the TypeLib branch. You also will need to create the ProgId keys, too if you want to support CreateObject functionality.
Initially, you can start with just a .reg file that you can manually update & maintain but if you have several objects, then it becomes desirable to automate this. This can be also managed via the DllRegisterServer call so that when you execute regsvr32, it will take care of registering the keys. On the other hand, you're now polluting your codebase with registration code. Some elect to use installers to do the registry keys write instead.
I hope that helps you get started!
The issue is due to assembly binding resolution that fails when ran from VB6 (IDE or compiled .exe file).
Here are the steps to solve it:
Compile the VB project, for example, let's assume the compiled file is Project1.exe.
Copy all .NET assemblies (including x86 and x64 directories, and languages directory if localized version is important) aside the compiled VB6 file
Now run Project1.exe, you will get an error like this:
The error is clearly a mismatch between the version of your assemblies aside the Project1.exe file and the version of referenced assemblies (not references you've created yourself but reference embedded in these assemblies... ). You don't see that when you start a .NET program because resolution is a very complex process that depends on a lot of parameters (and it's not getting any better with .NET Core, Framework, Standard, nugets, etc.).
To futher check it's a mismatch error, you can also use the Fuslogvw.exe (Assembly Binding Log Viewer) tool from the SDK.
Now we know it's an assembly version mismatch issue, what you can do is create a file named Project1.exe.config aside Project1.exe and add assembly binding redirects to it.
The easiest way to configure it is to redirect all possible versions to the ones present in the directory that contains your program, so in your case (and as of today, as all these can evolve...), it would be something like this, possibly for every assembly you reference directly or indirectly:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
...
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.DependencyInjection.Abstractions" publicKeyToken="adb9793829ddae60" />
<!-- 3.1.2.0 is the version of the assembly you ship -->
<bindingRedirect oldVersion="0.0.0.0-65535.65535.65535.65535" newVersion="3.1.2.0" />
</dependentAssembly>
...
</assemblyBinding>
</runtime>
</configuration>
Unfortunately, there are many satellite assemblies, and it's a bit tedious to create all redirects with correct information, so I've created a tool that creates a .config file with the redirects configured automatically for all .NET assemblies in a given directory: https://github.com/smourier/BindingRedirectGenerator.
If you want it to work for the VB6 IDE too, you'll have to use the same procedure in a VB6.exe.config file aside VB6.exe.
A reminder to myself
Use a demo UI to access the original DLL to confirm the call works. ( if you can't get it to work skip to making the App.Config for the unit test project using BindingRedirectGenerator )
Add a unit test in the com visible project to confirm the
call works.
Copy all the dlls created by both projects to the
release folder
For each com visible dll run as Administrator
c:\windows\microsoft.net\framework\v4.0.30319\regasm /verbose /codebase /tlb:MyLibrary.tlb c:\myproject\releasedlls\MyLibrary.dll
Install BindingRedirectGenerator to c:\brg say
At the command prompt change directory to c:\brg
BindingRedirectGenerator c:\myproject\releasedlls App.config
Rename App.config to MyVB6Project.exe.config and copy it to the same folder as MyVB6Project.exe
Remember to set up the files for the vb6.exe folder if you want to run it in the vb6 ide
Put the whole process in a script for future use ( I used a .bat)
Keep an eye on what nuget has put in app.config
Pay attention to the yellow warnings at build time!

Xamarin namespace issues in XAML files when changing startup project in VS

I have issues with Xamarin in Visual studio 2017 15.8.0 Preview 4 (And all previous builds)
I have a Xamarin forms project with a Android Project and a UWP project, if I change the startup project to UWP and try to compile I get this error
Error Failed to resolve assembly: 'FoosballXamarin.Android,
Version=0.0.0.0, Culture=neutral,
PublicKeyToken=null' FoosballXamarin.UWP ...\Views\LoginPage.xaml
And the XAML itself will give me errors on these lines
xmlns:viewModels="clr-namespace:FoosballXamarin.ViewModels;assembly=FoosballXamarin.Android"
xmlns:helpers="clr-namespace:FoosballXamarin.Helpers;assembly=FoosballXamarin.Android"
And want me to change them to
xmlns:viewModels="clr-namespace:FoosballXamarin.ViewModels;assembly=FoosballXamarin.UWP"
xmlns:helpers="clr-namespace:FoosballXamarin.Helpers;assembly=FoosballXamarin.UWP"
Is there a way to write it differently so I dont get this error every time?
Based on the errors you're seeing, I'm going to guess you have this configured as a shared project (not PCL/.netstandard). If that's the case, simplify the lines in the XAML file to:
xmlns:viewModels="clr-namespace:FoosballXamarin.ViewModels"
xmlns:helpers="clr-namespace:FoosballXamarin.Helpers"
In other words, just remove the assembly= part. If you don't specify the assembly on the xmlns line, it will assume the namespace is the same assembly as the XAML file. So you only need to include it if it's in a different assembly.
Since shared projects include the XAML file in multiple assemblies (one per platform), you pretty much have to omit the assembly= on the xmlns declaration for namespaces/types in the same assembly.

Import XSD targetNameSpace From another Visual Studio project

I have a VB solution with many VB projects in it. One of them, the "Core" project, has a .xsd file in it with a targetNameSpace of urn:CustomNamespace.
In the Core project, I am able to import the xsd namespace by doing the following:
Imports <xmlns="urn:CustomNamespace"/>
How can I get this Imports statement to work in a project that references the Core project? In the Core, the xsd's namespace shows up with Intellisense. This is not the case in the referring project.
I know this can be done somehow, as we are consuming a nuget package that has an xsd that we are importing.
******** UPDATE ********
It looks like the namespace Intellisense from the DLL in the nuget package is coming from a Configuration Section Designer xsd file, which is a .csd.xsd file. There are other related files to this, but I essentially want the same functionality that comes with referencing a package that has a .csd.xsd file.
It looks this is a VS add in located at https://csd.codeplex.com/. I'll likely pull down the project to try to find out how they're doing it, but I'd appreciate an answer if someone knows how it's done.
Nuget is likely adding the schema file to the project referencing your "Core" project. You can reference the same xsd file by adding it as a link to the referring project.
Right-click the (non-core) project, select Add>Existing item. Browse to the xsd file - and this bit is key - instead of clicking 'Add', click the little arrow next to "Add" and select "Add as link".

EPPlus library and SharePoint 2010

I'm using the EPPlus library in a Visual Studio 2012 SharePoint 2010 project and get the following 'file not found' exception from an Application Page when I add "ExcelPackage pck = new ExcelPackage();" as the starting point of creating an excel file:
Could not load file or assembly 'EPPlus, Version=3.1.3.0, Culture=neutral, PublicKeyToken=ea159fdaa78159a1' or one of its dependencies. The system cannot find the file specified.
The library registers without a problem and the project builds and runs until the function containing the EPPLus code is called.
The same code works fine on the same machine in a standard asp.net web application.
Any suggestions appreciated, thanks.
You need to deploy the Assembly in the GAC.
You can add it using something like GacUtil or include the assembly in your solution by adding it to the solution package.
In solution explorer, double click on Package.
In the Package properties select the Advanced tab
Add the assembly in Additional Assemblies
If you are trying to access this library inside inline code in an ASPX page (e.g. between <% and %> tags), then you'll need to add a reference to the assembly in the web.config so when the page is compiled on demand, the compiler will reference it.
<compilation debug="true">
<assemblies>
<add assembly="EPPlus, Version=3.1.3.0, Culture=neutral, ..." />

How do I properly register the Type Library of A VB.NET COM+ Component?

I am looking to upgrade legacy VB6 COM+ components to VB.NET components. I have seemingly upgraded one already, called EventPackage, which has one class, IEventListener. Another, TradeOrders, Implements EventPackage.IEventListener. When attempting to build TradeOrders, I get the following Errors/Warnings;
Cannot load type library for reference "EventPackage". Library not registered. (Exception from HRESULT: 0x8002801D (TYPE_E_LIBNOTREGISTERED))
The referenced component 'EventPackage' could not be found.
Type 'EventPackage.IEventListener' is not defined.
In the .vbproj, I notice this reference
<COMReference Include="EventPackage">
<Guid>{0D76C094-21A6-4E04-802B-6E539F7102D7}</Guid>
<Lcid>0</Lcid>
<VersionMajor>2</VersionMajor>
<VersionMinor>0</VersionMinor>
<WrapperTool>tlbimp</WrapperTool>
</COMReference>
When I search the registry for this Guid, I find nothing. When using GUIDs for similar COM+ objects, I find them in HKEY_CLASSES_ROOT\CLSID\{...}\TypeLib ("..." being the GUID of the other component). When I go to the registry key name corresponding to EventPackage.IEventListener, I find that there is no \TypeLib subkey. As you might suspect, searching the reg for "0D76C094-21A6-4E04-802B-6E539F7102D7" yields no results.
So I know this must be a registry problem, But I have tried seemingly every google result I have found. I have tried Regasm and regsvcs .exe's to no avail. Many pages just tell me that dragging the dll to the COM+ manager should automatically register the component.
So how do I register the Type library?
Details on how I made EventPackage COM+ component
Ran the VB6->VB.NET wizard
Then I added some lines to the assemblyinfo.vb file
added Imports System.EnterpriseServices
added Imports System.EnterpriseServices
Imports System.Data.SqlClient
<Assembly: CLSCompliant(True)>
<Assembly: AssemblyKeyFileAttribute("...")> for a strong name
<Assembly: Guid("...")> (Where "..." is the COM+ CLSID of the old component)
I added the following to the class file IEventListener.VB
Imports System.EnterpriseServices
<ComClass("...")> _ (Where ... is the proper COM+ CLSID, that is the only argument)
Inherits ServicedComponent
changed the ID made by the Conversion wizard to the proper value (from <System.Runtime.InteropServices.ProgId("IEventListener_NET.IEventListener)> to <System.Runtime.InteropServices.ProgId("EventPackage.IEventListener")> _
Then I dragged the DLL into the COM+ manager in the proper COM+ application (although, the "Path" is not specified and only says mscoree.dll)
I had that dam error (0x8002801D (TYPE_E_LIBNOTREGISTERED)) yesterday, it drove me crazy: VSTO Add-ins, COMAddIns and RequestComAddInAutomationService
It might be a red-herring but my answer has similar details about reg keys not existing and etc:
Right click on Visual Studio (2010) > Run As Administrator > Open Project > Compile!
The console command "regsvr32 mydll.dll" will register your COM component. You should be able then to find the guid under HKEY_CLASSES_ROOT\CLASSID then, under which the InprocServer32 folder will have the path to your dll. This is how COM looks up the dll.
I think that the problem here is that you haven't generated a type library for your .NET component. I know you said you used regasm - but did you use the right command line?
Start Menu => Programs => Microsoft .NET Framework SDK vX.Y => SDK Command Prompt.
In this command line line, type: regasm /tlb:Mydll.dll