internal void QueryInterfaceIDBCreateCommand(OleDbConnectionString constr) { if (!constr.HaveQueriedForCreateCommand || (constr.DangerousIDBCreateCommandCreateCommand != null)) { IntPtr zero = IntPtr.Zero; RuntimeHelpers.PrepareConstrainedRegions(); try { UnsafeNativeMethods.IUnknownQueryInterface delegateForFunctionPointer = (UnsafeNativeMethods.IUnknownQueryInterface)Marshal.GetDelegateForFunctionPointer(Marshal.ReadIntPtr(Marshal.ReadIntPtr(base.handle, 0), 0), typeof(UnsafeNativeMethods.IUnknownQueryInterface)); int num = delegateForFunctionPointer(base.handle, ref ODB.IID_IDBCreateCommand, ref zero); if ((0 <= num) && (IntPtr.Zero != zero)) { IntPtr ptr = Marshal.ReadIntPtr(Marshal.ReadIntPtr(zero, 0), 3 * IntPtr.Size); this.DangerousIDBCreateCommandCreateCommand = (UnsafeNativeMethods.IDBCreateCommandCreateCommand)Marshal.GetDelegateForFunctionPointer(ptr, typeof(UnsafeNativeMethods.IDBCreateCommandCreateCommand)); constr.DangerousIDBCreateCommandCreateCommand = this.DangerousIDBCreateCommandCreateCommand; } constr.HaveQueriedForCreateCommand = true; } finally { if (IntPtr.Zero != zero) { IntPtr handle = base.handle; base.handle = zero; Marshal.Release(handle); } } } }
// if OleDbConnectionString.DangerousIDBCreateCommandCreateCommand does not exist // this method will be called to query for IDBCreateCommand (and cache that interface pointer) // or it will be known that IDBCreateCommand is not supported internal unsafe void QueryInterfaceIDBCreateCommand(OleDbConnectionString constr) { // DangerousAddRef/DangerousRelease are not neccessary here in the current implementation // only used from within OleDbConnectionInternal.ctor->DataSourceWrapper.InitializeAndCreateSession // caching the fact if we have queried for IDBCreateCommand or not // the command object is not supported by all providers, they would use IOpenRowset // added extra if condition // If constr.HaveQueriedForCreateCommand is false, this is the first time through this method and we need to set up the cache for sure. // If two threads try to set the cache at the same time, everything should be okay. There can be multiple delegates that point to the same unmanaged function. // If constr.HaveQueriedForCreateCommand is true, we have already tried to query for IDBCreateCommand on a previous call to this method, but based on that alone, // we don't know if another thread set the flag, or if the provider really doesn't support commands. // If constr.HaveQueriedForCreateCommand is true and constr.DangerousIDBCreateCommandCreateCommand is not null, that means that another thread has set it after we // determined we needed to call QueryInterfaceIDBCreateCommand -- otherwise we would have called VerifyIDBCreateCommand instead // In that case, we still need to set our local DangerousIDBCreateCommandCreateCommand, so we want to go through the if block even though the cache has been set on constr already if (!constr.HaveQueriedForCreateCommand || (null != constr.DangerousIDBCreateCommandCreateCommand)) { IntPtr idbCreateCommand = IntPtr.Zero; RuntimeHelpers.PrepareConstrainedRegions(); try { // native COM rules are the QI result is the 'this' pointer // the pointer stored at that location is the vtable // since IUnknown is a public,shipped COM interface, its layout will not change (ever) IntPtr vtable = Marshal.ReadIntPtr(base.handle, 0); IntPtr method = Marshal.ReadIntPtr(vtable, 0); UnsafeNativeMethods.IUnknownQueryInterface QueryInterface = (UnsafeNativeMethods.IUnknownQueryInterface)Marshal.GetDelegateForFunctionPointer(method, typeof(UnsafeNativeMethods.IUnknownQueryInterface)); int hresult; fixed(Guid *riid = &ODB.IID_IDBCreateCommand) { hresult = QueryInterface(base.handle, riid, &idbCreateCommand); } if ((0 <= hresult) && (IntPtr.Zero != idbCreateCommand)) { vtable = Marshal.ReadIntPtr(idbCreateCommand, 0); method = Marshal.ReadIntPtr(vtable, 3 * IntPtr.Size); DangerousIDBCreateCommandCreateCommand = (UnsafeNativeMethods.IDBCreateCommandCreateCommand)Marshal.GetDelegateForFunctionPointer(method, typeof(UnsafeNativeMethods.IDBCreateCommandCreateCommand)); constr.DangerousIDBCreateCommandCreateCommand = DangerousIDBCreateCommandCreateCommand; } // caching the fact that we have queried for IDBCreateCommand constr.HaveQueriedForCreateCommand = true; } finally { if (IntPtr.Zero != idbCreateCommand) { IntPtr ptr = base.handle; base.handle = idbCreateCommand; Marshal.Release(ptr); } } } //else if constr.HaveQueriedForCreateCommand is true and constr.DangerousIDBCreateCommandCreateCommand is still null, it means that this provider doesn't support commands }
internal OleDbHResult InitializeAndCreateSession(OleDbConnectionString constr, ref SessionWrapper sessionWrapper) { OleDbHResult hr; bool mustRelease = false; IntPtr idbCreateSession = IntPtr.Zero; RuntimeHelpers.PrepareConstrainedRegions(); try { DangerousAddRef(ref mustRelease); // native COM rules are the QI result is the 'this' pointer // the pointer stored at that location is the vtable // since IUnknown is a public,shipped COM interface, its layout will not change (ever) IntPtr vtable = Marshal.ReadIntPtr(base.handle, 0); IntPtr method = Marshal.ReadIntPtr(vtable, 0); // we cache the QueryInterface delegate to prevent recreating it on every call UnsafeNativeMethods.IUnknownQueryInterface QueryInterface = constr.DangerousDataSourceIUnknownQueryInterface; // since the delegate lifetime is longer than the original instance used to create it // we double check before each usage to verify the delegates function pointer if ((null == QueryInterface) || (method != Marshal.GetFunctionPointerForDelegate(QueryInterface))) { QueryInterface = (UnsafeNativeMethods.IUnknownQueryInterface)Marshal.GetDelegateForFunctionPointer(method, typeof(UnsafeNativeMethods.IUnknownQueryInterface)); constr.DangerousDataSourceIUnknownQueryInterface = QueryInterface; } // native COM rules are the QI result is the 'this' pointer // the pointer stored at that location is the vtable // since IDBInitialize is a public,shipped COM interface, its layout will not change (ever) vtable = Marshal.ReadIntPtr(base.handle, 0); method = Marshal.ReadIntPtr(vtable, 3 * IntPtr.Size); // Initialize is the 4'th vtable entry // we cache the Initialize delegate to prevent recreating it on every call UnsafeNativeMethods.IDBInitializeInitialize Initialize = constr.DangerousIDBInitializeInitialize; // since the delegate lifetime is longer than the original instance used to create it // we double check before each usage to verify the delegates function pointer if ((null == Initialize) || (method != Marshal.GetFunctionPointerForDelegate(Initialize))) { Initialize = (UnsafeNativeMethods.IDBInitializeInitialize)Marshal.GetDelegateForFunctionPointer(method, typeof(UnsafeNativeMethods.IDBInitializeInitialize)); constr.DangerousIDBInitializeInitialize = Initialize; } // call IDBInitialize::Initialize via the delegate hr = Initialize(base.handle); // we don't ever expect DB_E_ALREADYINITIALIZED, but since we checked in V1.0 - its propagated along if ((0 <= hr) || (OleDbHResult.DB_E_ALREADYINITIALIZED == hr)) { // call IUnknown::QueryInterface via the delegate hr = (OleDbHResult)QueryInterface(base.handle, ref ODB.IID_IDBCreateSession, ref idbCreateSession); if ((0 <= hr) && (IntPtr.Zero != idbCreateSession)) { // native COM rules are the QI result is the 'this' pointer // the pointer stored at that location is the vtable // since IDBCreateSession is a public,shipped COM interface, its layout will not change (ever) vtable = Marshal.ReadIntPtr(idbCreateSession, 0); method = Marshal.ReadIntPtr(vtable, 3 * IntPtr.Size); // CreateSession is the 4'th vtable entry UnsafeNativeMethods.IDBCreateSessionCreateSession CreateSession = constr.DangerousIDBCreateSessionCreateSession; // since the delegate lifetime is longer than the original instance used to create it // we double check before each usage to verify the delegates function pointer if ((null == CreateSession) || (method != Marshal.GetFunctionPointerForDelegate(CreateSession))) { CreateSession = (UnsafeNativeMethods.IDBCreateSessionCreateSession)Marshal.GetDelegateForFunctionPointer(method, typeof(UnsafeNativeMethods.IDBCreateSessionCreateSession)); constr.DangerousIDBCreateSessionCreateSession = CreateSession; } // if I have a delegate for CreateCommand directly ask for IDBCreateCommand if (null != constr.DangerousIDBCreateCommandCreateCommand) { // call IDBCreateSession::CreateSession via the delegate directly for IDBCreateCommand hr = CreateSession(idbCreateSession, IntPtr.Zero, ref ODB.IID_IDBCreateCommand, ref sessionWrapper); if ((0 <= hr) && !sessionWrapper.IsInvalid) { // double check the cached delegate is correct sessionWrapper.VerifyIDBCreateCommand(constr); } } else { // otherwise ask for IUnknown (it may be first time usage or IDBCreateCommand not supported) hr = CreateSession(idbCreateSession, IntPtr.Zero, ref ODB.IID_IUnknown, ref sessionWrapper); if ((0 <= hr) && !sessionWrapper.IsInvalid) { // and check support for IDBCreateCommand and create delegate for CreateCommand sessionWrapper.QueryInterfaceIDBCreateCommand(constr); } } } } } finally { if (IntPtr.Zero != idbCreateSession) { // release the QI for IDBCreateSession Marshal.Release(idbCreateSession); } if (mustRelease) { // release the AddRef on DataLinks DangerousRelease(); } } return(hr); }
internal OleDbHResult InitializeAndCreateSession(OleDbConnectionString constr, ref SessionWrapper sessionWrapper) { OleDbHResult result; bool success = false; IntPtr zero = IntPtr.Zero; RuntimeHelpers.PrepareConstrainedRegions(); try { base.DangerousAddRef(ref success); IntPtr ptr = Marshal.ReadIntPtr(Marshal.ReadIntPtr(base.handle, 0), 0); UnsafeNativeMethods.IUnknownQueryInterface dangerousDataSourceIUnknownQueryInterface = constr.DangerousDataSourceIUnknownQueryInterface; if ((dangerousDataSourceIUnknownQueryInterface == null) || (ptr != Marshal.GetFunctionPointerForDelegate(dangerousDataSourceIUnknownQueryInterface))) { dangerousDataSourceIUnknownQueryInterface = (UnsafeNativeMethods.IUnknownQueryInterface)Marshal.GetDelegateForFunctionPointer(ptr, typeof(UnsafeNativeMethods.IUnknownQueryInterface)); constr.DangerousDataSourceIUnknownQueryInterface = dangerousDataSourceIUnknownQueryInterface; } ptr = Marshal.ReadIntPtr(Marshal.ReadIntPtr(base.handle, 0), 3 * IntPtr.Size); UnsafeNativeMethods.IDBInitializeInitialize dangerousIDBInitializeInitialize = constr.DangerousIDBInitializeInitialize; if ((dangerousIDBInitializeInitialize == null) || (ptr != Marshal.GetFunctionPointerForDelegate(dangerousIDBInitializeInitialize))) { dangerousIDBInitializeInitialize = (UnsafeNativeMethods.IDBInitializeInitialize)Marshal.GetDelegateForFunctionPointer(ptr, typeof(UnsafeNativeMethods.IDBInitializeInitialize)); constr.DangerousIDBInitializeInitialize = dangerousIDBInitializeInitialize; } result = dangerousIDBInitializeInitialize(base.handle); if ((OleDbHResult.S_OK > result) && (OleDbHResult.DB_E_ALREADYINITIALIZED != result)) { return(result); } result = (OleDbHResult)dangerousDataSourceIUnknownQueryInterface(base.handle, ref ODB.IID_IDBCreateSession, ref zero); if ((OleDbHResult.S_OK > result) || !(IntPtr.Zero != zero)) { return(result); } ptr = Marshal.ReadIntPtr(Marshal.ReadIntPtr(zero, 0), 3 * IntPtr.Size); UnsafeNativeMethods.IDBCreateSessionCreateSession dangerousIDBCreateSessionCreateSession = constr.DangerousIDBCreateSessionCreateSession; if ((dangerousIDBCreateSessionCreateSession == null) || (ptr != Marshal.GetFunctionPointerForDelegate(dangerousIDBCreateSessionCreateSession))) { dangerousIDBCreateSessionCreateSession = (UnsafeNativeMethods.IDBCreateSessionCreateSession)Marshal.GetDelegateForFunctionPointer(ptr, typeof(UnsafeNativeMethods.IDBCreateSessionCreateSession)); constr.DangerousIDBCreateSessionCreateSession = dangerousIDBCreateSessionCreateSession; } if (constr.DangerousIDBCreateCommandCreateCommand != null) { result = dangerousIDBCreateSessionCreateSession(zero, IntPtr.Zero, ref ODB.IID_IDBCreateCommand, ref sessionWrapper); if ((OleDbHResult.S_OK <= result) && !sessionWrapper.IsInvalid) { sessionWrapper.VerifyIDBCreateCommand(constr); } return(result); } result = dangerousIDBCreateSessionCreateSession(zero, IntPtr.Zero, ref ODB.IID_IUnknown, ref sessionWrapper); if ((OleDbHResult.S_OK <= result) && !sessionWrapper.IsInvalid) { sessionWrapper.QueryInterfaceIDBCreateCommand(constr); } } finally { if (IntPtr.Zero != zero) { Marshal.Release(zero); } if (success) { base.DangerousRelease(); } } return(result); }