|
| "Invalid PInvoke metadata format" in OracleClient 1.1 Beta when loaded dynamically from 1.0 code (Advanced question) |
|
|
|
|
| Messages |
|
Related Types |
This message was discovered on microsoft.public.dotnet.framework.clr.
Responses highlighted in red are from those people who are likely to be able to contribute good, authoratitive information to this discussion. They include Microsoft employees, MVP's and others who IMHO contribute well to these kinds of discussions.
| Carlos J. Quintero |
Hi,
I know that the .Net Framework 1.1 is in beta, but I would like to know if an assembly created with .Net Framework 1.0 can load dynamically an assembly created with .Net Framework 1.1 and call its methods or if this scenario is not supported. I ask this because I have found an issue in the OracleClient 1.1 Beta when called dynamically from .Net 1.0 code.
To know what I mean, follow these steps:
1) Install VS.NET 2002 and .Net Framework 1.0 in your machine 2) Install the .Net Framework Data Provider for Oracle that you must download separately (not included in .Net Framework 1.0) 3) Install VS.Net 2003 Final Beta, which includes .Net Framework 1.1 Beta and a .Net Framework Data Provider for Oracle. Now, your machine has 2 .Net Framework Data Providers for Oracle, one for .Net Framework 1.0 and another for .Net Framework 1.1 Beta. 4) Using VS.Net 2002, create a VB.Net application and merge this code in the Form1.vb file:
Option Strict Off
Imports System.Reflection
Friend Class Form1 Inherits System.Windows.Forms.Form .... Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Test() End Sub
Private Sub Test()
Dim objAssembly As System.Reflection.Assembly Dim objType As Type Dim objObject As Object
' This loads explicitly the version of the .Net Framework 1.0 and it works fine 'objAssembly = System.Reflection.Assembly.Load("System.Data.OracleClient, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
' This loads implicitly the version of the .Net Framework 1.1 Beta (1.0.5000) and it gives "Invalid PInvoke metadata format." objAssembly = System.Reflection.Assembly.LoadWithPartialName("System.Data.OracleClient")
If Not objAssembly Is Nothing Then
MessageBox.Show(objAssembly.FullName) ' This should show "System.Data.OracleClient, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
Try objType = objAssembly.GetType("System.Data.OracleClient.OracleConnection", True)
objObject = System.Activator.CreateInstance(objType)
' Assume Option Strict Off for Late Binding objObject.ConnectionString = "Data Source=MyOracleServiceName;Integrated Security=yes" objObject.Open() objObject.Close()
MessageBox.Show("Test OK")
Catch objException As Exception MessageBox.Show(objException.ToString) End Try
End If
End Sub
End Class
5) Run the project from the VS.Net 2002 IDE.
I get a "Invalid PInvoke metadata format" in system.data.oracleclient.dll when the Open method is called.
Explanation:
- The code loads the assembly of the OracleClient by partial name. It seems that given two versions of that assembly, the most new assembly is loaded; in this case, the one of the .Net Framework 1.1 Beta (1.0.5000.0 instead of 1.0.3300.0).
- The Open method causes an exception "Invalid PInvoke metadata format" in system.data.oracleclient.dll. This exception is thrown in a call System.Data.OracleClient.SafeNativeMethods.LoadLibraryExA(String lpFileName, IntPtr hfile, Int32 dwFlags) that the OracleClient does to load the OCI client library.
- The code is correct because loading the OracleClient 1.0 explicitly using objAssembly = System.Reflection.Assembly.Load("System.Data.OracleClient, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089") it works fine.
- Also, when this project is run from the VS.Net 2003 Final Beta, using the ..Net 1.1 code instead of .Net 1.0 code, it works fine too.
So, it seems that the problem is calling .Net 1.1 code from .Net 1.0 code.
Comments?
Thanks in advance,
Carlos Quintero
|
|
|
| |
|
| |
| |
| Angel Saenz-Badillos[MS] (VIP) |
Carlos, awesome post! you certainly have done a lot of research into this area and Everet has not been out that long. Side by Side is going to be a major issue with people as we roll out Everet and it is important that people understand a little of what we are trying to do here. Your post does a great job of describing the behavior, let me go over a few of the major points we are dealing with here:
First of all, our goal when releasing Everet is to make it Side by Side compatible with all other versions of the URT. Side-by-side execution does not mean that a managed component is compatible with other versions of the runtime.. What it means is that a managed application can choose what runtime it executes with, and that multiple versions of the runtime, applications, and components can coexist on the same computer. The choice of which runtime version an application uses is set by the application using configuration files.
Ideally we want to see the code that compiled under a specific version of the urt running against that version, there are two big exceptions. ASP.NET and COM loading automatically default to the latest version of the urt installed in your machine unless you configure them to do otherwise, and the second exception is forward compatiblity between RTM and Everet. You will be able to run most RTM applications on Everet without any configuration if RTM is not present in your computer. I say most because there are some breaking changes between the two versions, most of these changes are related to security issues, these are fairly obscure issues like if you try to PermitOnly before opening an Oledb connection we used to allow you to open the connection, on Everet it will fail since we are now demanding Full Trust.
So what about your example? Well when you do the System.Reflection.Assembly.Load you are running into the COM loading exception to the rule. When you try to execute both 1.0 and 1.1 components in the same process you can get unexpected behavior, in this case there has been a change in the Open method that throws the Pinvoke method.
Looking forward to hearing any comments, suggestions and questions about side by side, Hope this helped, -- Angel Saenz-Badillos [MS] Managed Providers This posting is provided "AS IS", with no warranties, and confers no rights. Please do not send email directly to this alias. This alias is for newsgroup purposes only.
"Carlos J. Quintero" <Click here to reveal e-mail address> wrote in message news:u0DpI7BqCHA.2008@TK2MSFTNGP12... [Original message clipped]
|
|
|
| |
|
|
| |
| |
| Carlos J. Quintero |
Hi Angel,
[Original message clipped]
Yes, I have came to that conclussion too. Say that you want to load dynamically the OracleClient 1.0 from .Net 1.0 code and OracleClient 1.1 from .Net 1.1 code. Which is the best approach to do this? I mean:
a) I can use fully qualified assembly names:
In .Net 1.0 code: objAssembly = Assembly.Load("System.Data.OracleClient, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
In .Net 1.1 code: objAssembly = Assembly.Load("System.Data.OracleClient, Version=1.0.5500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
But that uses hard-coded data which maybe is not the best idea, because a future service pack for a given .Net framework can change the version numbers.
b) I think that I can use the full filename and the method Assembly.LoadFrom(assemblyFilename) but this requires to guess the full filenames for the assembly files, which maybe also tricky.
Is there a way to load dynamically an assembly given only the name (such "System.Data.OracleClient") and major and minor version (such "1.0" or "1.1") but not the build number?
Thanks in advance,
Carlos Quintero
|
|
|
| |
|
|
| |
| |
| Angel Saenz-Badillos[MS] (VIP) |
Carlos,
As far as I know you want to use the fully qualified assembly names, 1.0.5000.0 is the v1.1 library. v1.0 is 1.0.3300.0 and future service packs will not change this. I am not sure about the PublicKeyToken, but I use fully qualified assembly loads very often and have not had any trouble.
You mention that you want to load this dynamically, is there any reason for this? The normal scenario for most users here is to rely on side by side behavior and config files for what they want to tweak. Are you using a reflection based program or are you trying to mix both 1.0 and 1.1 for some reason?
Here are some common scenarios:
install RTM then install Everet app compiled with rtm will run with rtm. app compiled with everet will run with everet asp.net app compiled on the fly will use Everett regardless of what it was developed under.
Everet only installed app compiled with rtm will run with Everet,
Rtm only installed app compiled with Everet requires config file to run with RTM.
-- Angel Saenz-Badillos [MS] Managed Providers This posting is provided "AS IS", with no warranties, and confers no rights. Please do not send email directly to this alias. This alias is for newsgroup purposes only.
"Carlos J. Quintero" <Click here to reveal e-mail address> wrote in message news:uGb5YtHqCHA.2064@TK2MSFTNGP12... [Original message clipped]
|
|
|
| |
|
|
| |
| |
| Carlos J. Quintero |
Hi,
[Original message clipped]
I will use fully qualified assembly names then.
> You mention that you want to load this dynamically, is there any reason for [Original message clipped]
Yes, there is one reason. The code is on an add-in (DLL) hosted on the IDE that must load dynamically that .Net Data Provider. Although the add-in could be coded in .Net code 1.0 and used both in VS.Net 2002 and VS.Net 2003 IDEs, it seems that it will be better to code separate versions for each IDE sharing the same source code and using conditional compilation to load one data provider or the other depending on the target IDE.
Thanks for all the info,
Carlos
|
|
|
| |
|
| |
|
|
|
|
|
|
|
|
|
|
|
BootFX
Reliable and powerful .NET application framework. |
|
|
|
|
|
|