VBA - User-defined type not defined - windows

I am trying to update an VBA module to use the System.Windows.Forms.FolderBrowserDialog class. I declared my object as follows:
Dim MyFolderBrowser As New System.Windows.Forms.FolderBrowserDialog
Running this gave me the error User-defined type not defined. I figured the compiler didn't know about that class so I tried going to Tools > References and adding Systems_Windows_Forms, but I'm still getting the same error. Does anyone know what I'm missing here? Do I need a reference to the library in my code as well?

System.Windows.Forms.FolderBrowserDialog looks like something from .Net to me, not VBA.
You can use Application.FileDialog in Access VBA. This sample uses late binding and allows the user to select a folder from a browse dialog.
Const msoFileDialogFolderPicker As Long = 4
Dim objFileDialog As Object ' FileDialog
Set objFileDialog = Application.FileDialog(msoFileDialogFolderPicker)
With objFileDialog
.AllowMultiSelect = False
If .Show Then
Debug.Print .SelectedItems(1)
End If
End With
If you prefer to use early binding, set a reference to the Microsoft Office [version] Object Library. You could then declare the object like this ...
Dim objFileDialog As FileDialog
And you wouldn't need to define the constant, so discard this line if using early binding ...
Const msoFileDialogFolderPicker As Long = 4

Related

Is there a way for VB6 to throw a type mismatch error when assigning a variable of the same type?

I am trying to figure out the cause of a type mismatch error, but I don't understand the reason it is even being thrown. I am assigning to a variable of the same type that is being assigned from.
Begin bxControls.starTable m_tblClaims 'Defined at the top of the form file
Dim objTable As PVDataTable5.DataTable
Set objTable = m_tblClaims.Table
Begin PVDataTable5.DataTable dtTable 'Defined at the top of the .ctl file
'Property inside of bxControls.starTable
Public Property Get Table() As Object
Attribute Table.VB_MemberFlags = "40"
Set Table = dtTable
End Property
As you can see, the assignment taking place should not be having a type mismatch since they are the same type. Any help would be awesome. TIA
Try this
Dim objTable As PVDataTable5.DataTable
Set objTable = m_tblClaims.Table.Object
Note that this might work in IDE but fail when compiled.
The story of user-controls is mostly of complete lies from the IDE. For instance all user-control properties/methods are called late-bound, even if the IDE intellisense gives look like the callsite is early-bound.
For each user-control type that is currently loaded in the IDE (as part of a project group for instance) the IDE creates surrogate date-type with merged original control properties/methods and some VB supplied ones (like Visible etc.) which are coming from VBControlExtender class.
That is why Dim objTable As PVDataTable5.DataTable sometimes is not declaration of PVDataTable5.DataTable data-type but of the surrogate PVDataTable5.DataTable from an OCA file, that is when the user-control is loaded in the IDE.
The only sane way to pass references to VB6 user-controls that works both if the user-control is loaded and when referenced in compiled OCX is to pass VBControlExtender instead and use its Object property to access the wrapped reference.

How can I detect an unmanaged C++ project in a visual studio extension

In my Visual Studio Extension, I need to detect whether a C++ project is managed or unmanaged code.
Previously, I had a satisfactory method, described in this posting in an MSDN forum.
In that example, it was necessary to get the ManagedExtensions property of the active configuration.
Sub Macro1()
Dim objProject As EnvDTE.Project
Dim objConfiguration As EnvDTE.Configuration
Dim objProperty As EnvDTE.Property
For Each objProject In DTE.Solution.Projects
objConfiguration = objProject.ConfigurationManager.ActiveConfiguration()
objProperty = objConfiguration.Properties.Item("ManagedExtensions")
System.Windows.Forms.MessageBox.Show(objProject.Name & " (" & objConfiguration.ConfigurationName & ") ManagedExtensions: " & objProperty.Value.ToString)
Next
End Sub
Unfortunately, this method is no longer working for me.
For unmanaged projects, I get an exception trying to fetch the ActiveConfiguration.
For managed projects, I can get the ActiveConfiguration, but the ManagedExtensions property is not available. In fact, I think that the properties collection is empty.
Is there a new way to recognize an unmanaged C++ project?
You can get the ManagedExtensions property via the VCConfiguration object, with code something like
Private Enum compileAsManagedOptions
managedNotSet = 0
managedAssembly = 1
managedAssemblyPure = 2
managedAssemblySafe = 3
managedAssemblyOldSyntax = 4
End Enum
Dim VCProj As Object 'VCProject
Dim VCConfig As Object 'VCConfiguration
Dim VCManagedOption As compileAsManagedOptions = compileAsManagedOptions.managedAssemblyPure
VCProj = prj.Object
If VCProj IsNot Nothing Then
VCConfig = VCProj.Configurations.Item(1)
If VCConfig IsNot Nothing Then
VCManagedOption = VCConfig.ManagedExtensions
End If
End If
where prj is the Envdte.Project object.
This code is only executed if I already know that it is a C++ project, based on the project kind.
I defined the variables as object, so that I don't have to add a reference to
Microsoft.VisualStudio.VCProject.dll
to my package, because this DLL will only be present if support for C++ projects has been installed.

referencing WinSCP COM library from VB6

I am trying to use the WinSCP COM library on a old VB6 project I have (it's a legacy application that generates an OCX file, I think we have to use VB6 for it but not 100% sure).
Anyway we want to implement SFTP, and WinSCP can do that readily.
I registered the COM object, and can see the WinSCPNet type library when I go to add the reference. However I can't see the properties/methods of the classes when I look at the library in the object browser. Further, this code fails, it does not get to the 3rd MsgBox ("In SendWinSCP4"), it returns from the function at that point, I think because the property UserName is not exposed.
MsgBox ("in SendWinSCP")
Dim session As WinSCPnet.session
Dim sessionOptions As WinSCPnet.sessionOptions
Dim transferOptions As WinSCPnet.transferOptions
Set session = New WinSCPnet.session
Set sessionOptions = New WinSCPnet.sessionOptions
Set transferOptions = New WinSCPnet.transferOptions
MsgBox ("in SendWinSCP3")
sessionOptions.Protocol = Protocol_Sftp
sessionOptions.HostName = "example.com"
sessionOptions.UserName = "user"
sessionOptions.Password = "example.com"
sessionOptions.SshHostKeyFingerprint = "ssh-rsa 2048 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx"
MsgBox ("in SendWinSCP4 " & sessionOptions.HostName & "!")
See above, using On Error Resume Next got me past the error.

"Method or Data Member Not Found" When Trying to Execute Database Code

I have a test project I'm using to familiarise myself with VB6. Just a listbox, a button to get info, and a button to clear info:
Code:
Option Explicit
Private Sub btnGet_Click()
lstResults.DataSource = GetMenuItems
End Sub
Private Sub btnClear_Click()
lstResults.Clear
End Sub
Public Function GetMenuItems() As ADODB.Recordset
Dim rs As ADODB.Recordset
Dim conn As New ADODB.Connection
conn.ConnectionString = "File Name=C:\connString.udl"
Dim cmd As New ADODB.Command
Set cmd.ActiveConnection = conn
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "dbo.GetMenuItems"
Set rs = cmd.Execute()
GetMenuItems = rs
End Function
The following error appears when I click the Get Items button (btnGet):
Compile Error: Method or Data Member Not Found
At first I thought it might be something to do with the event/button, that some sort of binding between them wasn't present. But just putting in something like "MsgBox("Hello")" works fine. Yet it doesn't even seems to get to the line where the GetMenuItems function is called before throwing the error.
This being my first whirl with VB, I'm a little stumped.
EDIT - I've had a look at the UDL file I was using too. Tested that and its connecting ok on its own.
In Sub btnGet_Click, use
Set lstResults.DataSource = GetMenuItems
Assigning object references without using Set is hardly ever the right thing to do. For what it's worth, omitting Set references the left-hand side's default property; this was part of VB6 (OK, VB4, when classes were introduced) as a help to VB3 programmers, before there were such things as objects. Whatever kind of object lstResults.DataSource returns likely does not have a default property, leading to the "Method or data member not found" error.
You've got a private sub btnGet_Click() calling a public function GetMenuItems(), which may cause problems.
Also I'm not sure you can use a udl as the connection string. Instead, open the UDL (you may need to change the file extension to .txt temporarily), take the connection string out, and use that in place of the file name.
Also, check the stored procedure exists dbo.GetMenuItems

Legacy VB6 app throwing type mismatch error during ActiveX create object

I've been tasked with making a change to a legacy VB6 Winform app. What I found is that this app was unnecessarily split up into multiple DLLs (some of the DLL were simply a couple of classes). So, I'm working on consolidating some of the DLLs into the main program but I've run into a problem that I could use some help on.
One of the dlls contained a class called CTest(Test.cls). The main program used it in the following lines of code. strProgId is a string naming another DLL.
Dim objTest As CTest
Set objTest = CreateTestObject(strProgId)
Public Function CreateTestObject(strProgId As String) As Object
10 On Error GoTo ErrorHandler
20 Set CreateTestObject = CreateObject(strProgId)
30 Exit Function
ErrorHandler:
40 UpdateErrorInfo "CreateTestObject", "Globals", strProgId
50 HandleError
End Function
Here are the contents of CTest
Option Explicit
Private m_strName As String
Private m_strDescription As String
Private m_cnnADO As ADODB.Connection
Public Property Get Name() As String
10 Name = m_strName
End Property
Public Property Let Name(strNewName As String)
10 m_strName = strNewName
End Property
Public Property Get Connection() As ADODB.Connection
10 Set Connection = m_cnnADO
End Property
Public Property Set Connection(cnnADO As ADODB.Connection)
10 Set m_cnnADO = cnnADO
End Property
Public Property Get Description() As String
10 Description = m_strDescription
End Property
Public Property Let Description(strNewDescription As String)
10 m_strDescription = strNewDescription
End Property
Public Function Run(ByVal strSTMType As String, _
instInstruments As CInstruments, objResults As CTestResults) As Boolean
End Function
If CTest is still part of a DLL and I have a reference to it in the Main Program, it gets through the CreateTestObject line without an error. If I bring in the class into the main program it throws a type mismatch error.
Any help is appreciated, thank you in advance.
CreateObject will only work with publicly visible COM classes. Therefore, because you've brought CTest into your main program, CreateObject will no longer work and will raise errors just like you describe.
Either
Create the object via Set obj = New CTest
Or just leave the class in a separate DLL? Are you sure there's no other side effects of it being in a separate DLL? No other app using it?
I just solved this one after a day and a half. In my case I invoke the dll twice. The first time it worked and the second time it threw the error above. I have several projects open and each has its' own compatibility setting. For some unexplained reason the second reference to the common dll had compatibility set off. By setting the correct path in the version compatability and setting it to binary compatibility the problem cleared up.
If you're bringing CTest into your main program directly, then you don't need the CreateObject call - just instantiate it the normal way, now that it's part of your program, and it should work fine.

Resources