vb6 using variables as DLL paths - vb6

I can't get this to work. It says string constant expected...
Dim const path As String = "\Windows\System32\user32"
Private Declare Function CallWindowProcW Lib path...
Any suggestions?

As was said, you can't do that. If you use a path to a library it must be hard-coded.
However, if you don't use a hard-coded path there's a defined order in which Windows will look for for the library. It will search the app directory, the current dir, the Windows and System dirs, and along the current Path. If you put your DLL in any of those places, and omit the hard-coded path in the reference, it will be found (what order they're searched in varies by Windows version and by where it's documented).
There's one other possibility. If a DLL is already loaded in memory, Windows will reuse the loaded copy. So you can omit the path if you first load the DLL yourself, and for that you can use a string variable. Check out the docs for LoadLibrary. You do have to keep a handle and free the library yourself using FreeLibrary.

Private Declare Function CallWindowProcW Lib "User32" ...
Test it
Declare Statement
Example
The following example declares an external reference to a Function procedure that returns the current user name. It then calls the external procedure GetUserNameA as part of the getUser procedure.
Declare Function getUserName Lib "advapi32.dll" Alias "GetUserNameA" (
ByVal lpBuffer As String, ByRef nSize As Integer) As Integer
Sub getUser()
Dim buffer As String = New String(CChar(" "), 25)
Dim retVal As Integer = getUserName(buffer, 25)
Dim userName As String = Strings.Left(buffer, InStr(buffer, Chr(0)) - 1)
MsgBox(userName)
End Sub

Related

How to access Speech Recognition via Win32 API?

I'm trying to update a very old VB6 program to provide Speech Recognition.
I'm thinking the best way to do this is by accessing the Win32 API for Speech Recognition.
Looked for this on MS documentation. Looks like previously this would be done via the SAPI 5.3 per this question which has been deprecated and replaced by MS Agent, which itself is deprecated.
http://msdn.microsoft.com/en-us/library/ms720589(VS.85).aspx
The above link is old (because I used it 10 years ago), but is valid. You basically create the appropriate objects, possibly create a grammar in their format, and then create events on the RC object, below:
The below method "works", but it wasn't very impressive. Also, it led us to have to create our own MsgBox function, since we needed to automate everything... And, since you can't just tell Windows to "click" the OK button of a standard message box (unless you want to muck around even more APIs), you have to control even more aspects of your software.
It did work, but I'm not sure anyone ever used it.
Public WithEvents RC As SpSharedRecoContext
Public myGrammar, b As ISpeechRecoGrammar
Private Sub Form_Load()
On Error GoTo EH
Set RC = New SpSharedRecoContext
Set myGrammar = RC.CreateGrammar
myGrammar.CmdLoadFromFile "sol.xml", SLODynamic
myGrammar.CmdSetRuleIdState 0, SGDSActive
EH:
If Err.Number Then ShowErrMsg
End Sub
Private Sub RC_FalseRecognition(ByVal StreamNumber As Long, ByVal StreamPosition As Variant, ByVal Result As SpeechLib.ISpeechRecoResult)
'Label1.Caption = "(no recognition)"
End Sub
Private Sub RC_Recognition(ByVal StreamNumber As Long, ByVal StreamPosition As Variant, ByVal RecognitionType As SpeechLib.SpeechRecognitionType, ByVal Result As SpeechLib.ISpeechRecoResult)
'Label1.Caption = Result.PhraseInfo.GetText
End Sub
Private Sub RC_StartStream(ByVal StreamNumber As Long, ByVal StreamPosition As Variant)
'Label2.Caption = Val(StreamNumber)
End Sub

Stringify a method call in VBScript

I'm currently working every day with QuickTest Professional 11, which uses VBScript behind the scenes. Lately, I've started developing some of my own functions to handle common situations. I'm pretty new to VBscript, most of my programming experience is in C and Python.
I'm trying to implement Python's Try/Except in VBScript, mostly to wrap around actions like clicking links or selecting values from dropdown boxes. Here's what I have so far:
Class cls_ErrorHandler
Private bWasError
Private Sub Class_Initialize()
bWasError = False
End Sub
Private Sub IsErr
If Err.Number <> 0 Then
bWasError = True
Else
bWasError = False
End If
Err.Clear
End Sub
' If the command fails, set bWasError
Public Sub Try(strCommandToTry)
On Error Resume Next
Execute(strCommandToTry)
me.IsErr
On Error Goto 0
End Sub
Public Sub Except(strCommandInCaseOfError)
If bWasError Then
Execute(strCommandInCaseOfError)
End If
bWasError = False
End Sub
End Class
I'd like to be able to write things like this:
Set oErrorHandler = New cls_ErrorHandler
oErrorHandler.Try(Stringify(Browser("Browser Name").Page("Page Name").WebCheckBox("Checkbox Name").Set "ON"
oErrorHander.Except(Stringify(Browser("Browser Name").Page("Page Name").WebButton("Save").Click))
As far as I can tell, there really isn't any nice way to pass a function as an argument to another function in VBScript. The best way seems to be to pass a string containing the name of a function, and then feed that string into Execute() or Eval(). Objects in QuickTest Professional tend to have lots of quotation marks, so escaping them all by hand would make the code unreadable.
In C, I'd use something like this:
#define Stringify(obj) #obj
and it would be done... but nothing like that seems to exist in VBScript. Is there any way to implement this? Is there anything in VBScript that takes an object as its input and returns a string representation of that object's name? Would it be possible to write a DLL in C/C# that would provide this kind of functionality?
You can use GetRef to obtain a function/sub pointer, and call the function/sub using that pointer. See online help, it shows an example for an event handler, but you can refer to any global function or sub with GetRef, and use the variable holding the GetRef return value just like an alias for the sub/function.
Be aware, however, that there are cases you won't be able to cover with this:
You cannot use a GetRef function pointer if the current calling stack contains a
method call that is a function registered to a test object via
RegisterUserFunc.
You cannot call such a test object method from within a routine call
that was adressed via a GetRef function pointer.
Also consider using ExecuteGlobal instead of Execute so the code you pass can set global variables that the ExecuteGlobal caller can access afterwards.

VBA - User-defined type not defined

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

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.

InternetCheckConnection in VB6 returning false

I'm trying to come up with a VB6 test app that calls InternetCheckConnection.
In my test app, InternetCheckConnection always returns false regardless of the URL I use. I copied and pasted this code from a larger spaghetti-code app, but in the spaghetti-code, InternetCheckConnection seems to work fine, returns true.
Is there some other function I have to call first in order for InternetCheckConnection to work?
I was able to get InternetCheckConnection to work correctly by including the full address for a website, including "http://". For example, using "www.google.com" returned False, but "http://www.google.com" returned true.
Try using the InternetGetConnectedState function.
Private Declare Function InternetGetConnectedState Lib "wininet.dll" (ByRef lpSFlags As Long, ByVal dwReserved As Long) As Long
Dim blnInternetConnected as Boolean
Dim Flags as long
blnInternetConnected = InternetGetConnectedState(Flags, 0&)
Perhaps, in the "spaghetti-code" app, InternetCheckConnection is relying on the state of some global variable you are not aware of. Is that possible?

Resources