Calling a Module and a Class within a Form - vb6

I have an Employee class where I call my database connection Module to make a query.
I am getting "Compile Error: Expected function or variable", which I'm not understanding, because I have the empObj set at the top of the form.
I would like to return the value from the Employee.getEmployee method. Can someone please show me how to call the Employee class from my form? Do I have to import the class first? I don't believe VB6 supports the Imports keyword.
This is my form:
Option Explicit
Private empObj As New Employee
Private Sub Form_Load()
'For testing only
MsgBox (empObj.getEmployee)
End Sub
This is my class:
Public Sub getEmployee()
'ConnectSQL is a database connection
return ConnectSQL
End Sub
And this is the module:
Public Function ConnectSQL()
Set SQLMyconn = New ADODB.Connection
Set SQLRecset = New ADODB.Recordset
SQLMyconn.Open "Driver={MySQL ODBC Client Interface};ServerName=localhost;dbq=#testdb"
End Function

The basic shell of what you want to do is like this:
Option Explicit
Private empObj As Employee
Private Sub Form_Load()
Set empObj = New Employee
MsgBox empObj.getEmployee
End Sub
Public Function getEmployee() As String
getEmployee = ConnectSQL
End Function
Public Function ConnectSQL() As String
Set SQLMyconn = New ADODB.Connection
Set SQLRecset = New ADODB.Recordset
SQLMyconn.Open "Driver={MySQL ODBC Client Interface};ServerName=localhost;dbq=#testdb"
ConnectSQL = "data from your DB lookup"
End Function
Almost every line is different than what you posted, so carefully look at the code.
EDIT:
Based on a comment, here's how to modify the code to return a connection object:
Option Explicit
Private empObj As Employee
Private Sub Form_Load()
Set empObj = New Employee
MsgBox empObj.getEmployee
Dim MyConnection As ADODB.Connection
Set MyConnection = ConnectSQL()
'you can grab and use the connection in your form, too.
End Sub
Public Function getEmployee() As String
Dim MyConnection As ADODB.Connection
Set MyConnection = ConnectSQL()
'use the connection to grab data
getEmployee = "data from your DB lookup"
End Function
Public Function ConnectSQL() As ADODB.Connection
Set ConnectSQL = New ADODB.Connection
ConnectSQL.Open "Driver={MySQL ODBC Client Interface};ServerName=localhost;dbq=#testdb"
End Function
Don't forget to close your connection after you are done with it. To sum up the changes:
empObj - you should declare and instantiate your objects separately.
MsgBox - no need for the ().
Functions vs Subs - the first returns data, the second does not. Make sure you declare the return type of a function.
return - this statement is obsolete and doesn't do what you want. Instead, assign a value to the name of the function.

Related

The object does not support the property or method EOF

I have 3 pages:
my DB-class
<!--#include virtual="/res/adovbs.inc"-->
<%
Class classDB
'Declarations
Private SQL
Private RS
Private Conn
'Class Initialization
Private Sub Class_Initialize()
Set Conn = Server.CreateObject("ADODB.Connection")
Conn.ConnectionString = "DSN=x"
Call Conn.Open
End Sub
'Terminate Class
Private Sub Class_Terminate()
If IsObject(RS) Then
If RS.State = 1 Then
RS.Close()
End If
End If
If Conn.State = 1 Then
Conn.Close()
End If
End Sub
Public Function GetRS(SQL)
Set RS = Conn.Execute(SQL)
GetRS = RS
End Function
Public Function ExecuteSQL(SQL)
Conn.Execute(SQL)
End Function
End Class
%>
And my "functions":
<!--#include virtual="/res/classDB.asp"-->
<%
'GET PAGED MEMBERS
Function GetMembers(page)
If Not IsNumeric(page) Or page = "" Then page = 1
Dim db : Set db = new classDB
Set GetMembers = db.GetRS("SELECT * FROM member")
End Function
.....
And in my page:
<%
Dim members : Set members = GetMembers(1)
If Not members.EOF Then
Do Until members.EOF
%>
I get Error:
The object does not support the property or method 'EOF'
What might be wrong here? An Object was returned to the page. But I guess it has no properties or entries.... Impossible to debug.
EDIT:
Function GetMembers(page)
If Not IsNumeric(page) Or page = "" Then page = 1
Dim rs
Dim m : Set m = new classDB
Set rs = m.GetRS("SELECT * FROM member")
Response.Write(rs("email"))
Set GetMembers = rs
End Function
It prints out the email for the "member".... but it doesn't work on the "next" page with the loop.
It's it returning the recordset to the page?
<%
Dim m : Set m = GetMembers(1)
If Not m.EOF Then
Do Until m.EOF
%>
Is not working..... what to do?
EDIT
I changed to:
Public Function GetRS(SQL)
Dim RS : Set RS = m_Conn.Execute(SQL)
Set GetRS = RS
End Function
Now I get error:
"The action is not allowed when the object is closed"
Google translated :)
I have the open in the Class_Initialize.... why?
The first error is due to the lack of Set on the returned object reference in the GetRS() method in the classDB class. The fix for this is to change the return value so it is prefixed with Set like this;
Public Function GetRS(SQL)
Dim RS: Set RS = Conn.Execute(SQL)
'Returning object references from a function requires the "Set" statement.
Set GetRS = RS
End Function
You then reported a "not allowed when closed" error. This comes from the encapsulation of the ADODB.Connection object inside the classDB object instance. Because the connection is scoped to the class returning a recordset causes the connection to be severed, hence the recordset returning as closed.
The fix is to bring the connection outside the class so it lives in the context of the page and then passes it into the class via a parameter. There are varying ways of doing this, you could add a argument to the GetRS() method but this would only affect that single method. The other option is to build a sub procedure that you call after instantiation of the class to set the connection, something like;
Class classDB
'Declarations
Private SQL
Private RS
Private Conn
Public Sub Init(conn)
Set Conn = conn
End Sub
'Terminate Class
Private Sub Class_Terminate()
If IsObject(RS) Then
If RS.State = 1 Then
RS.Close()
End If
End If
If Conn.State = 1 Then
Conn.Close()
End If
End Sub
Public Function GetRS(SQL)
Set RS = Conn.Execute(SQL)
GetRS = RS
End Function
Public Function ExecuteSQL(SQL)
Conn.Execute(SQL)
End Function
End Class
You then make sure to call it before using the class and pass your ADODB.Connection object.
'Key is connection object is declared in the scope of the page
Dim conn: Set conn = Server.CreateObject("ADODB.Connection")
Call conn.Open("DSN=x")
'GET PAGED MEMBERS
Function GetMembers(page)
If Not IsNumeric(page) Or page = "" Then page = 1
Dim db : Set db = new classDB
'Call init() method and pass connection into the class instance.
Call db.Init(conn)
Set GetMembers = db.GetRS("SELECT * FROM member")
End Function

Alternative to CfgPropertyPagesGuidsAddCSharp for Visual Studio 2010

I am trying to develop a VSIX package that adds a tab to the project designer for a couple of custom project properties. I have the package working in VS 2013 using CfgPropertyPagesGuidsAddCSharp as described in this post. However, after porting the VSIX project to VS 2010, the custom property page is not loaded.
This question from 2011 doesn't have an answer. The answer to another question suggests creating a custom project subtype, but that seems like an awful amount of work just to be able to edit some additional project properties from the GUI. This is my first time working on a VSIX package, so I'm trying to keep things as simple as possible.
I've tried browsing through the source for the .NET project system, but I'm not sure exactly what I'd be looking for to properly register the page; any guidance would be much appreciated.
Thanks.
Sometime ago I wrote a blog post describing how to add a custom property page using the CfgPropertyPagesGuidsAddCSharp property. Perhaps you can find it useful.
I ended up creating a project sub-type for the package, which was easier than I expected. The bigger challenge was figuring out a way to share the application code between the VS2013 and VS2010 packages, since they reference different SDK versions. I ended up creating two separate project files, and including the shared code as a link reference in each project.
I created my own IPropertyPage implementation modeled on PropPageBase and PropPageUserControlBase. I have included a portion of that code for reference, since the Microsoft-provided code is more complicated.
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Diagnostics
Imports System.Diagnostics.CodeAnalysis
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Imports Microsoft.VisualStudio
Imports Microsoft.VisualStudio.OLE.Interop
Imports Microsoft.VisualStudio.Shell.Interop
Imports ControlPosition = System.Drawing.Point
Imports ControlSize = System.Drawing.Size
<ComVisible(True)>
Public MustInherit Class PropertyPageProviderBase
Implements IPropertyPage, IDisposable
Private ReadOnly _dirtyProperties As New Dictionary(Of String, String)()
Private _control As Control
Private _defaultSize As System.Drawing.Size?
Private _hostedInNative As Boolean
Private _objects As Object()
Private _pageSite As IPropertyPageSite
<SuppressMessage( _
"Microsoft.Reliability", _
"CA2006:UseSafeHandleToEncapsulateNativeResources", _
Justification:="Handle is not owned by us, we are just tracking a reference")>
Private _previousParent As IntPtr
Protected Sub New()
End Sub
' ...
Protected Property [Property](propertyName As String) As String
Get
If String.IsNullOrEmpty(propertyName) Then
If propertyName Is Nothing Then
Throw New ArgumentNullException("propertyName")
End If
Throw New ArgumentException( _
"Empty property name is invalid", _
"propertyName")
End If
Dim dirtyValue As String = Nothing
If _dirtyProperties.TryGetValue(propertyName, dirtyValue) Then
Return dirtyValue
End If
Return ReadProperty(propertyName)
End Get
Set(value As String)
If String.IsNullOrEmpty(propertyName) Then
If propertyName Is Nothing Then
Throw New ArgumentNullException("propertyName")
End If
Throw New ArgumentException( _
"Empty property name is invalid", _
"propertyName")
End If
If _objects IsNot Nothing Then
_dirtyProperties.Item(propertyName) = value
If _pageSite IsNot Nothing Then
_pageSite.OnStatusChange(PROPPAGESTATUS.DIRTY)
End If
Else
Debug.Fail("Accessing property while not bound to project")
End If
End Set
End Property
' ...
Protected Overridable Sub Apply()
If _objects Is Nothing Then
If _dirtyProperties.Count <> 0 Then
Debug.Fail("Cannot save changes. Not bound to project")
End If
Exit Sub
End If
For Each dirtyProperty As KeyValuePair(Of String, String) In _dirtyProperties
WriteProperty(dirtyProperty.Key, dirtyProperty.Value)
Next
_dirtyProperties.Clear()
If _pageSite IsNot Nothing Then
_pageSite.OnStatusChange(PROPPAGESTATUS.CLEAN)
End If
End Sub
' ...
Private Shared Function ContainsMultipleProjects(vsObjects As Object()) As Boolean
Debug.Assert(vsObjects IsNot Nothing)
If vsObjects IsNot Nothing AndAlso vsObjects.Length > 1 Then
Dim first As IVsHierarchy = GetProjectHierarchy(vsObjects(0))
For i As Integer = 1 To vsObjects.Length - 1
Dim current As IVsHierarchy = GetProjectHierarchy(vsObjects(i))
If current IsNot first Then
Return True
End If
Next
End If
Return False
End Function
' ...
Private Shared Function GetProjectHierarchy(vsObject As Object) As IVsHierarchy
Dim hierarchy As IVsHierarchy = Nothing
Dim itemId As UInteger
Dim vsCfgBrowsable As IVsCfgBrowseObject = TryCast(vsObject, IVsCfgBrowseObject)
If vsCfgBrowsable IsNot Nothing Then
ErrorHandler.ThrowOnFailure(vsCfgBrowsable.GetProjectItem(hierarchy, itemId))
Return hierarchy
End If
Dim vsBrowsable As IVsBrowseObject = TryCast(vsObject, IVsBrowseObject)
If vsBrowsable IsNot Nothing Then
ErrorHandler.ThrowOnFailure(vsBrowsable.GetProjectItem(hierarchy, itemId))
Return hierarchy
End If
Throw New NotSupportedException("Unsupported VS object type")
End Function
' ...
Private Shared Sub WriteProperty(vsObject As Object, propertyName As String, propertyValue As String)
Dim hierarchy As IVsHierarchy = GetProjectHierarchy(vsObject)
Dim buildStorage As IVsBuildPropertyStorage = TryCast(hierarchy, IVsBuildPropertyStorage)
If buildStorage Is Nothing Then
Debug.Fail("Unsupported VS object")
Exit Sub
End If
ErrorHandler.ThrowOnFailure(buildStorage.SetPropertyValue( _
propertyName, _
String.Empty, _
STORAGETYPE.PROJECT_FILE, _
propertyValue))
End Sub
' ...
Private Sub _SetObjects(cObjects As UInteger, ppunk() As Object) Implements IPropertyPage.SetObjects
If cObjects = 0 OrElse ppunk Is Nothing OrElse ppunk.Length = 0 Then
SetObjects(Nothing)
Exit Sub
End If
If ContainsMultipleProjects(ppunk) Then
SetObjects(Nothing)
Exit Sub
End If
Debug.Assert(cObjects = CUInt(ppunk.Length), "Huh?")
SetObjects(ppunk)
End Sub
' ...
Private Sub SetObjects(vsObjects As Object())
_dirtyProperties.Clear()
_objects = vsObjects
OnObjectsChanged(EventArgs.Empty)
End Sub
' ...
Private Sub WriteProperty(propertyName As String, propertyValue As String)
If _objects Is Nothing Then
Debug.Fail("Accessing property while not bound to project")
Exit Sub
End If
Debug.Assert(_objects.Length <> 0, "Should never have zero objects if collection is non-null")
For i As Integer = 0 To _objects.Length - 1
WriteProperty(_objects(i), propertyName, propertyValue)
Next
End Sub
End Class
Creating the package was fairly straightforward; just remember to call RegisterProjectFactory during the initialization step.
Imports System
Imports System.Diagnostics
Imports System.Runtime.InteropServices
Imports Microsoft.VisualStudio.Modeling.Shell
Imports Microsoft.VisualStudio.Shell
Imports Microsoft.VisualStudio.Shell.Interop
<ComVisible(True)>
<ProvideBindingPath()>
<Guid(Guids.MyCustomPackage)>
<PackageRegistration( _
UseManagedResourcesOnly:=True)>
<ProvideAutoLoad(UIContextGuids.SolutionExists)>
<ProvideProjectFactory( _
GetType(MyCustomProjectFactory), _
Nothing, _
Nothing, _
Nothing, _
Nothing, _
Nothing)>
<ProvideObject( _
GetType(MyCustomPropertyPageProvider))>
Public Class MyCustomPackage
Inherits Package
Protected Overrides Sub Initialize()
MyBase.Initialize()
Dim factory As New MyCustomProjectFactory(Me)
Try
Me.RegisterProjectFactory(factory)
Catch ex As ArgumentException
Debug.Fail(ex.Message, ex.ToString())
End Try
End Sub
End Class
I didn't use the MPF ProjectFactory class, since the MPF isn't designed for project sub-types. Instead, I inherited directly from FlavoredProjectFactoryBase.
Imports System
Imports System.Diagnostics.CodeAnalysis
Imports System.Runtime.InteropServices
Imports Microsoft.VisualStudio.Shell.Flavor
<SuppressMessage( _
"Microsoft.Interoperability", _
"CA1405:ComVisibleTypeBaseTypesShouldBeComVisible", _
Justification:="Blame Microsoft? No other way around this")>
<ComVisible(True)>
<Guid(Guids.MyCustomProjectFactory)>
Public Class MyCustomProjectFactory
Inherits FlavoredProjectFactoryBase
Private ReadOnly _package As MyCustomPackage
Public Sub New()
Me.New(Nothing)
End Sub
Public Sub New(package As MyCustomPackage)
If package Is Nothing Then
Throw New ArgumentNullException("package")
End If
_package = package
End Sub
Protected Overrides Function PreCreateForOuter(outerProjectIUnknown As IntPtr) As Object
Return New MyCustomProject(_package)
End Function
End Class
The project class then needs to add the GUID for the custom property page to the list of property page GUIDs.
Imports System
Imports System.Collections.Generic
Imports System.Diagnostics.CodeAnalysis
Imports System.Runtime.InteropServices
Imports Microsoft.VisualStudio
Imports Microsoft.VisualStudio.Shell.Flavor
Imports Microsoft.VisualStudio.Shell.Interop
<SuppressMessage( _
"Microsoft.Interoperability", _
"CA1405:ComVisibleTypeBaseTypesShouldBeComVisible", _
Justification:="Blame Microsoft? No other way around this")>
<ComVisible(True)>
<Guid(Guids.MyCustomProject)>
Public Class MyCustomProject
Inherits FlavoredProjectBase
Private Const GuidFormat As String = "B"
Private Shared ReadOnly PageSeparators As String() = {";"}
Private ReadOnly _package As MyCustomPackage
Public Sub New()
Me.New(Nothing)
End Sub
Public Sub New(package As MyCustomPackage)
If package Is Nothing Then
Throw New ArgumentNullException("package")
End If
_package = package
End Sub
Protected Overrides Function GetProperty(itemId As UInteger, propId As Integer, ByRef [property] As Object) As Integer
If propId = CInt(__VSHPROPID2.VSHPROPID_PropertyPagesCLSIDList) Then
ErrorHandler.ThrowOnFailure(MyBase.GetProperty(itemId, propId, [property]))
Dim pages As New HashSet(Of String)()
If [property] IsNot Nothing Then
For Each page As String In CStr([property]).Split(PageSeparators, StringSplitOptions.RemoveEmptyEntries)
Dim blah As Guid = Nothing
If Guid.TryParseExact(page, GuidFormat, blah) Then
pages.Add(page)
End If
Next
End If
pages.Add(Guids.MyCustomPropertyPageProviderGuid.ToString(GuidFormat))
[property] = String.Join(PageSeparators(0), pages)
Return VSConstants.S_OK
End If
Return MyBase.GetProperty(itemId, propId, [property])
End Function
Protected Overrides Sub SetInnerProject(innerIUnknown As IntPtr)
If MyBase.serviceProvider Is Nothing Then
MyBase.serviceProvider = _package
End If
MyBase.SetInnerProject(innerIUnknown)
End Sub
End Class
One last hint for anybody who's having trouble getting things to work: you have to open your project file in an XML editor and adjust some of the build properties manually. At a minimum you'll need to set GeneratePkgDefFile and IncludeAssemblyInVSIXContainer to true.

Passing object to function in VB 6

Dim xyzWkB As Excel.workbook
Set xyzWkB = setGetxyzObj(reportFile.Text)
populateListCombo (xyzWkB)
The function is defined as follows:
Public Function populateListCombo(activeWkB As Excel.workbook)
......
......
End Function
But in execution at the time of calling populateListCombo am getting the error "object does not support this property"
Here setGetxyzObj is defined as follows:
Public Function setGetxyzObj(Optional userInput As String) As Excel.workbook
Static xyz As New Excel.Application
Static xyzWkB As Excel.workbook
Set xyz = New Excel.Application
If Not (userInput = "") Then
Set xyzWkB = xyz.Workbooks.Open(userInput)
End If
Set setGetxyzObj = xyzWkB
End Function
I have also tried with populateListCombo (setGetxyzObj()), but still getting the same error.

LINQ: Dynamic predicate builder issue

I'm trying to create a helper class to easily build dynamic LINQ queries. Code is heavily modified version of this excellent CodeProject article: http://www.codeproject.com/Articles/493917/Dynamic-Querying-with-LINQ-to-Entities-and-Express which uses the PredicateBuilder here: http://www.albahari.com/nutshell/predicatebuilder.aspx
I'm still in the process of cleaning up the code so variables names are rubbish at the moment and there is not one comment in sight.
Usage
Dim conditions As New List(Of Condition)
With conditions
.Add(New Condition With {.Field = "EatsPeople", .Operator = "Equals", .Value = False})
.Add(New Condition With {.Field = "Name", .Operator = "Equals", .Value = "Adric"})
.Add(New Condition With {.Field = "Description", .Operator = "Contains", .Value = "ugly"})
End With
Dim predicate = BuildPredicate(conditions)
Dim tester = data.Monsters.AsExpandable.Where(predicate).ToList
Entity
Public Class Monster
Public Property EatsPeople As Boolean
Public Property Name As String
Public Property Description As String
End Class
Storage for search:
Public Class Condition
Public Property Field As String
Public Property [Operator] As String
Public Property Value As Object
End Class
Methods
Public Function BuildPredicate(conditions As List(Of Condition)) As Expression(Of Func(Of Monster, Boolean))
Dim predicate = PredicateBuilder.True(Of Monster)()
For Each c In conditions
Dim dbFieldName = c.Field
Dim dbType = GetType(Monster)
Dim dbFieldMemberInfo = dbType.GetMember(dbFieldName, BindingFlags.IgnoreCase Or BindingFlags.Public Or BindingFlags.Instance).Single()
predicate = BuildExpression(c, dbType, dbFieldMemberInfo, predicate)
Next
Return predicate
End Function
Private Function CreateLambda(value As Object, method As MethodInfo, ByVal dbType As Type, ByVal dbFieldMemberInfo As MemberInfo) As Expression(Of Func(Of Monster, Boolean))
Dim dbTypeParameter = Expression.Parameter(dbType, "x")
Dim dbFieldMember = Expression.MakeMemberAccess(dbTypeParameter, dbFieldMemberInfo)
Dim criterionConstant = New Expression() {Expression.Constant(value)}
Dim containsCall = Expression.Call(dbFieldMember, method, criterionConstant)
Return TryCast(Expression.Lambda(containsCall, dbTypeParameter), Expression(Of Func(Of Monster, Boolean)))
End Function
And the problematic method
Private Function BuildExpression(condition As Condition, ByVal dbType As Type, ByVal dbFieldMemberInfo As MemberInfo, ByVal predicate As Expression(Of Func(Of Monster, Boolean))) As Expression(Of Func(Of Monster, Boolean))
Dim type = condition.Value.GetType
Dim method As MethodInfo = type.GetMethod(condition.Operator, BindingFlags.Instance Or BindingFlags.Public, Nothing, {type}, Nothing)
If type = GetType(String) Then
If condition.Value.ToString.Contains(",") = True Then
Dim inner = PredicateBuilder.False(Of Product)()
For Each v In condition.Value.ToString.Split(",")
inner = inner.Or(CreateLambda(v, method, dbType, dbFieldMemberInfo))
Next
*****Return predicate.And(inner)*****
End If
End If
Return predicate.And(CreateLambda(condition.Value, method, dbType, dbFieldMemberInfo))
End Function
What is the problem?
The line in the last method surrounded by five asterisks is the issue.
When adding the OR grouped expression to the original predicate builder you get
The parameter 'f' was not bound in the specified LINQ to Entities
query expression.
For some reason, I can't seem to create a nested expression.
If you put the code above where the query is executed in usage sample, it works (after making some mods).
Update with solution:
The line with the asterisks needs to change to
Return predicate.And(inner.Expand)
I'm not a Visual Basic person, but in the C# implementation I think you'd probably need to add AsExpandable() to your query as per albahari.com/nutshell/predicatebuilder.aspx.

InvalidCOMObjectException: COM object that has been separated from its underlying RCW cannot be used?

I'm getting this exception thrown when I run my tests:
Test method OuvertureClasseur threw exception: System.Runtime.InteropServices.InvalidComObjectException: COM object that has been separated from its underlying RCW cannot be used...
though each of my test passes when ran individually.
Here's my tests code:
<TestClass()> _
Public Class FabriqueExcelTests
Private Shared _xl As ApplicationClass
<ClassInitialize()> _
Public Shared Sub MyClassInitialize(ByVal testContext As TestContext)
_xl = New ApplicationClass()
_xl.Visible = False
_xl.ScreenUpdating = False
_xl.DisplayAlerts = False
End Sub
<ClassCleanup()> _
Public Shared Sub MyClassCleanup()
_xl.Quit()
_xl = Nothing
End Sub
<TestMethod()> _
Public Sub ConstructeurParDefaut()
Dim gestionnaire As GestionnaireExcel = New GestionnaireExcel()
Assert.IsNotNull(gestionnaire)
Assert.IsInstanceOfType(gestionnaire, GetType(GestionnaireExcel))
End Sub
<TestMethod()>
Public Sub CreationDUnFichierExcel()
Dim fichier As String = "C:\Temp\CreationFichierExcel.xls"
Using xl As GestionnaireExcel = New GestionnaireExcel()
Dim classeur As Workbook = xl.CreerClasseur(fichier)
classeur.Close()
classeur = Nothing
End Using
Assert.IsTrue(File.Exists(fichier))
File.Delete(fichier)
End Sub
<TestMethod()> _
Public Sub OuvertureClasseur()
Dim fichier As String = "C:\Temp\OuvertureClasseur.xls"
_xl.Workbooks.Add(XlWBATemplate.xlWBATWorksheet)
_xl.ActiveWorkbook.SaveAs(fichier)
_xl.ActiveWorkbook.Saved = True
_xl.Workbooks.Close()
Using xl As GestionnaireExcel = New GestionnaireExcel()
Dim classeur As Workbook = xl.OuvrirClasseur(fichier)
Assert.AreEqual(fichier, classeur.FullName)
classeur.Close()
classeur = Nothing
End Using
File.Delete(fichier)
End Sub
End Class
And my GestionnaireExcel class:
Public Class GestionnaireExcel
Implements IDisposable
Private _cultureOriginale As CultureInfo
Private _disposedValue As Boolean = False '' To detect redundant calls
Private _excel As ApplicationClass
Public Sub New()
InitialiserExcel()
End Sub
'' IDisposable
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not Me._disposedValue Then
If disposing Then
'' TODO: free other state (managed objects).
If (_excel IsNot Nothing) Then
_excel.Quit()
_excel = Nothing
System.Threading.Thread.CurrentThread.CurrentCulture = _cultureOriginale
End If
End If
'' TODO: free your own state (unmanaged objects).
'' TODO: set large fields to null.
End If
Me._disposedValue = True
End Sub
'' This code added by Visual Basic to correctly implement the disposable pattern.
Public Sub Dispose() Implements IDisposable.Dispose
'' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above.
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
Public Function CreerClasseur(ByVal classeur As String) As Workbook
_excel.Workbooks.Add(XlWBATemplate.xlWBATWorksheet)
_excel.ActiveWorkbook.SaveAs(classeur)
Return _excel.ActiveWorkbook
End Function
Private Sub InitialiserExcel()
_cultureOriginale = System.Threading.Thread.CurrentThread.CurrentCulture
System.Threading.Thread.CurrentThread.CurrentCulture = New CultureInfo("en-US")
_excel = New ApplicationClass()
_excel.DisplayAlerts = False
_excel.ScreenUpdating = False
_excel.Visible = False
End Sub
Public Function OuvrirClasseur(ByVal fichier As String) As Workbook
Dim classeur As Workbook = _excel.Workbooks.Open(fichier _
, False, False _
, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing _
, False _
, Type.Missing, Type.Missing _
, False _
, Type.Missing, Type.Missing)
Return classeur
End Function
End Class
Related questions found
Though I have read and understand these questions and answers, I don't seem to find what causes my OuvertureClasseur() test to fail when I run all my tests together, and it works just fine when I run it individually.
COM object that has been separated from its underlying RCW cannot be used.
WMI Exception: “COM object that has been separated from its underlying RCW cannot be used”
COM object that has been separated from its underlying RCW cannot be used.
COM object that has been separated from its underlying RCW can not be used - why does it happen?
WPF Thread: “COM object that has been separated from its underlying RCW cannot be used.”
I have been running around for few hours now, and any help will gladly be appreciated.
Thanks in advance! =)
Excel's executing as another process. It's possible that what's happening in classeur.Close() is asynchronous, and that some of it is taking place after the GestionnaireExcel instance is disposed.
Try commenting out the using block and see what happens.

Resources