

InterviewSolution
Saved Bookmarks
1. |
Solve : Application with roots in GAC can't find a dll in path.? |
Answer» This is kind of branching out from a preivous thread. Here is the scenario:
I am not sure why this dll would be different from the others. They are older C++ 6 and VB6 dlls as well. Here is the code for my simple class (based on conversations from my previous post with BC_Programmer)... Code: [Select] Public Function ComToBytes(objName As String, obj As Object) As Byte() Dim PropBag As PropertyBag Set PropBag = New PropertyBag PropBag.WriteProperty objName, obj ComToBytes = PropBag.Contents End Function Public Function BytesToCOM(objName As String, obj() As Byte) As Object Dim PropBag As PropertyBag Set PropBag = New PropertyBag PropBag.Contents = obj Set ComFromBytes = PropBag.ReadProperty(objName) End Function Any suggestions as to why the application won't find my dll, no matter where it resides? You do have control over the C# application in question, correct? Why can't you reference the COM library via the IDE? At the very least, adding a reference to a COM component will generate a managed wrapper for the component. I believe you can do this manually using tlbimp.exe which is part of the .NET framework SDK. Basically, what you end up with is the managed code which uses the unmanaged COM component. The managed code can be installed in the GAC, but the unmanaged code cannot. The GAC-installed wrapper accesses that unmanaged code, however. And it needs to stay wherever it was when it was registered (via regsvr32) You need a managed wrapper for the COM DLL.If you mean to the solution or projects for the calling application, no I don't. So basically, I build the ActiveX dll (VB6 code) and reference it from the .NET 2.0 C# project. When I do that it builds the interop but the it can't be added to the GAC because it has no assembly manifest. If i try "tlbexp.exe MyClass.dll" to build a type library it fails with an error (expected to contain an assembly manifest). This is actually the same error I get when I try to install it to the GAC. I am KINDA baffled. I don't understand why it won't see the dll and use it unless it is in the GAC. If I could this method working I would gladly accept it... It seems crazy to think that I would have to try and implement IPersist and IPersistStream on every class that requires this serialization. Thanks again.I also tried: Code: [Select] tlbimp.exe MySerializer.dll /keyfile:My_KeyFile.snk /machine:X86 to force it into building an assembly-based dll straight from the COM dll. It didn't complain and it built a dll. I registered it, added it to the project, and could add it to the GAC. When I ran the code it made it PAST the previous error and died where it tried to instantiate a class at the line: Code: [Select] MySerialize.SerializerClass serializer = new MySerialize.SerializerClass(); with the error "Retrieving the COM class factory for component with CLSID {95388FE5-87E8-4164-ADA2-E974FA3803FB} failed due to the following error: 80040154."} Not sure if I would call that progress or not... 80040154: Class Not Registered. If the program in question is 64-bit, than it won't be able to instantiate 32-bit components (such as those created with VB). A .NET program/Library will be 64-bit if it is run on a 64-bit system and was built CPU-agnostic (AnyCPU). If the main application is 64-bit, or compiled with AnyCPU, than it will only be able to access 64-bit COM components; which means you won't be able to use the VB6 wrapper method since VB6 cannot compile 64-bit. additionally, if the COM component you want to use is 32-bit, all bets are off and you won't be able to use it at all. only a 32-bit assembly can use a 32-bit COM component, and only a 32-bit Assembly can use another 32-bit assembly, so if you were to change your project to compile to x86, than the main application might not be able to use your library if it is AnyCPU and run on a 64-bit processor. Not sure if this will help:http://blogs.msdn.com/b/junfeng/archive/2007/04/14/genman32-a-tool-to-generate-sxs-manifest-for-managed-assembly-for-registration-free-com-net-interop.aspx Personally I never touch the GAC, or deal with strong named assemblies or any of that, so I'm just sort of groping around in the dark here, myself. It looks like that page is more for creating assemblies that can be used as COM components, and not vice-versa... But it might be that the Interop Assembly needs a Manifest in it to be dependent on the COM assembly. Assuming the problem isn't essentially intractable (getting a 32-bit COM component to be used by a library that is accessed by a AnyCPU compiled assembly) you might have to fall-back on the IPersistStream method. Basically: -VB6 only compiles 32-bit COM components. -A 64-bit Assembly cannot use 32-bit COM components. A 32-bit Assembly can, but... -a 64-bit Assembly cannot use 32-bit Assemblies -VB6 can only use 32-bit COM components; so evidently the COM component in question is 32-bit. Basically you are building a chain- Main Application->Your Library->VB6 Wrapper->COM Component the VB6 wrapper is 32-bit, so Your Library would to be 32-bit, which means that the main application would as well, but you have no control over that, which is where you have issues. Even if you eliminate the wrapper and try to use IPersistStream on the COM component manually, the COM component is 32-bit so you have the same problem. Bit-ness mismatch is really all I can think of to explain this. I really appreciate all of your input on this topic... The primary application is loaded with Interops, so I don't believe it is a 32bit vs. 64bit issue. I believe it is some kind of issue related to things in the GAC needing other things to be in the GAC to function. This morning I wrote a simple WinForm application with a single button. Code: [Select] private VOID btnCut_Click(object sender, EventArgs e) { string str = "Test"; object theObj= Activator.CreateInstance(Type.GetTypeFromProgID("TheObjectData.TheObject")); MySerializer.SerializerClass myClass = new MySerializer.SerializerClass(); Array arr = myClass.ComToBytes(ref str, ref theObj); } All I did here was make sure the VB6 dll was registered and added a reference to it. When the button is pushed, the VB6 class gets instantiated and a method is called returning a proper array. With the other application, I had some components that would break the code during runtime. Then, it was always a FileNotFoundException. If I added the dlls to the GAC those exceptions would go away. So if I could just get this dll into the GAC properly I think it would work. The problem is I don't know what else to try to get the thing in there. Even though the command: Code: [Select] tlbimp.exe MySerializer.dll /keyfile:My_KeyFile.snk /machine:X86 seems to build a GAC-compatible dll straight from the VB6 dll (instead of a type library), I don't think it is really valid. I've never heard of building an assembly dll like this, I just thought I would try it. Gotta be missing something... I found this: http://www.hanselman.com/blog/GotchasAroundPrimaryInteropAssembliesAndTheGAC.aspx Quote Of course the COM Object that you're referring to has to be registered, but the PIA has to be as well. You'll need to call RegASM.exe to create a key in the registry under HKEY_CLASSES_ROOT\TypeLib\{yourclassid}\PrimaryInteropAssemblyName. The value of this key should be the fully qualified Assembly name like: MYDLL, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a. Some folks call RegASM, others ship a .REG file or create this key during the installation procedure.OK. We can close this one out. I have built an assembly from the VB6 and stuck it into the GAC. I can instantiate the VB6 class and call one of the two functions from C#. I am going to open another thread for the problem I am having with the second function. In a nutshell, the problem was related to not properly building the assembly. This is basically how this had to go down.
Thanks again. what you end up with is the managed code which uses the unmanaged COM component. |
|