-
1 Attachment(s)
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
The solution (at least as by suggestion of chatgpt and Google gemini) is to use a Heartbeat which will be sent by the calling VB6 application to the TB app from time to time to indicate that it it still alive.
I have attached my TB to illustrate that just in case somebody requires to see that.
TB is really easy to work with and works fine so far. I really appreciate getting to know it due to this problem that I had. I use it paying regular monthly payment.
Thank you!
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
In your latest demo that you posted here, are you not using CreateObject anymore?
Code:
Public Function CreateObject(sProgID As String) As Object
Set CreateObject = VBA.CreateObject(sProgID)
End Function
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
I suspected that this would be the error that I experience on some customers computer, but the error occurs here:
Code:
Private m_sProxyName_Aka_UUID$
Private m_oProxy64 As Object
I start it like this:
Dim sCmd$
sCmd="D:\Dev\Projects\tws64\TB\Build\twsMoniker64_win64.exe 2e1316f8-a36a-4734-9db6-cc41a7696dd2"
Dim d As Double
d = Shell(sCmd)
Set m_oProxy64 = GetObject(m_sProxyName_Aka_UUID)
And it throws an error in that last line "GetObject" with "Automation error. Invalid syntax" , err.number: -2147221020
Does you have any idea why this might happen?
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
"Invalid syntax" is raised when the moniker name is not recognized. Probably should retry GetObject call (with a timeout) untill Shell completes spawning the worker process and server object is registered in ROT.
> In your latest demo that you posted here, are you not using CreateObject anymore?
This is just a sample cheap and useful method you can use to "spawn" new server objects inside the x64 process. Can't remember if it's there for any other purpose.
cheers,
</wqw>
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
I tried it 10 times with a pause of 1 second between each attempt, so 10 seconds altogether. That should be enough, right?
It works fine on my computer but fails on a clients computer running Windows 11 Home, Version 10.0.22631 Build 22631.
Do you have any recommendation what I should check next?
-
1 Attachment(s)
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
I have attached the Twinbasic project.
Please ignore the childish over-explaining variable names. I had to make some sense of it, and doing that helps me.
Edit: I have now put vb6 and tb into a single folder and attached it as spvoiceproxy2.zip.
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
Quote:
Originally Posted by
qvb6
VB6 could talk to a 64-Bit COM DLL, but not standard 64-Bit DLL. The API version of CreateObject() allows creating out-of-process objects using DLLHOST.exe. You can talk to 32 or 64 Bit COM DLL's that way. The OS takes care of moving data back and forth between VB6 and the 64-Bit COM DLL. Please see CreateObject64() in post #6 in this thread and my subsequent posts.
https://www.vbforums.com/showthread....createobject64
In my case, I made a 64-Bit COM DLL using C++(Not SAPI related), and talked to it from VB6. Windows runs the 64-Bit version of DLLHOST.exe to host the 64-Bit DLL.
Another option for you is to turn your DLL into 64-Bit COM EXE(Same as ActiveX EXE). This doesn't require adding registry entries like the 64-Bit DLL option.
The ActiveX exe also needs to be written to the registry and requires administrator privileges to register. Run.
registeractiveobject,make exe as rot object,This can be called by other processes without administrator privileges.
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
- Edit: I have put all files together in a single zip in my previous post. -
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
I am not familiar with this error at all and currently stuck. Would it help to shrink the project? I am not sure if it's understandable.
My code works fine on my computer, and honestly I got no clue what else to test.
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
One thing I noticed when opening SpVoiceMonikerTest.vbp is that Microsoft Speech Object Library reference is MISSING on my machine.
Apparently you are referencing some incompatible (newer or older) version on the DLL. Once I fixed this the project seems to work in the IDE (while compiled SpVoiceMonikerTest.exe is something old, not sure what to test here).
Could it be your clients PCs have different Microsoft Speech installed? I have no previous experience with this library, first time seeing it, so cannot tell if this is normal or if you should use late-bound calls similar to dealing with MS Office incompatibilities.
Anyway, cannot come up with anything obviously wrong with your code on first glace.
cheers,
</wqw>
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
It is a file that should be present on all Windows machines from Windows 10 upwards as it is used as a standard feature:
Users who can not see and therefore use a computer voice to have the text on the screen spoken to them, use computer voices, and they are controlled via SAPI.
SAPI.dll must exist as both 32 bit and 64 bit version on the computer.
Users can not replace this SAPI.dll easily. It is not a file that users are expected to update themselves.
Do you have any idea how to solve them when you say that on your machine it was missing?
May I ask you where your was located and which version, etc.?
Or is this TwinBasic related?
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
Do I understand it correctly that you say I have to late binding?
If yes then I would not be able to have the SpVoice fire events, correct?
This is my current code in TwinBasic:
Code:
Public WithEvents AnSpVoice As SpeechLib.SpVoice
This would not work if I used "As Object", correct?
-
1 Attachment(s)
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
ps: I posted the reference that I used in TwinBasic to chatgpt, and it said that the library that I'm using, identified by the GUID "C866CA3A-32F7-11D2-9602-00C04F8EE628", is part of Windows' built-in speech capabilities, specifically tied to the Speech API.(SAPI).
This is what I see when I double click the reference in TwinBasic:
Code:
[ LibraryId ("C866CA3A-32F7-11D2-9602-00C04F8EE628") ]
[ Version (5.4) ]
[ Description ("Microsoft Speech Object Library") ]
Library SpeechLib
' Original type library: C:\WINDOWS\System32\Speech\Common\sapi.dll
' NOTE: Offsets and lengths calculated for current Win64 target.
I checked the customer's registry, and it is found:
Code:
[HKEY_CLASSES_ROOT\CLSID\{0655E396-25D0-11D3-9C26-00C04F8EF87C}\TypeLib]
@="{C866CA3A-32F7-11D2-9602-00C04F8EE628}"
Attachment 193110
I see that the version of sapi.dll of the customer's computer is newer than mine, but SAPI exists since many years, and I find it highly unlikely that a change to it was introduced which in turn would cause an incompatibility.
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
Quote:
Originally Posted by
tmighty2
Do I understand it correctly that you say I have to late binding?
If yes then I would not be able to have the SpVoice fire events, correct?
This is my current code in TwinBasic:
Code:
Public WithEvents AnSpVoice As SpeechLib.SpVoice
This would not work if I used "As Object", correct?
It is possible to Raise Events from late-bound Objects.
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
This is the "fixed" reference in SpVoiceMonikerTest.vbp on my machine w/ win11
Code:
Reference=*\G{C866CA3A-32F7-11D2-9602-00C04F8EE628}#5.4#0#C:\WINDOWS\System32\Speech\Common\sapi.dll#Microsoft Speech Object Library
Originally what I found in the ZIP was this:
Code:
Reference=*\G{D3C4A7F2-7D27-4332-B41F-593D71E16DB1}#b.0#0#..\..\..\..\Program Files (x86)\Common Files\Microsoft Shared\Speech\Platform\v11.0\mssps.dll#Microsoft Speech Object Library
cheers,
</wqw>
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
When I import the customers sapi.dll instead of mine and check the TwinBasic References then, apart from the file location, the 2 files match.
I believe it's a TwinBasic problem.
Edit: Oh you are talking about the VB6 project!!
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
I have changed it now, but it doesn't make a difference.
When I use the voice inside the TwinBasic moniker / proxy. It works. It just seems that it is unable to pass it to my VB6 exe.
-
1 Attachment(s)
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
I got it.
In VB6, I can just declare it as
Private m_Voice As Object
The events are fired to the vb6 form, so I don't need them for the voice. :-)
Finally!!!!!!!!!
Full project is attached. I didnt have time to clean it up, but it works now.
Edit:
It's not working any more. Now it can't even get the proxy.
This is so frustrating, really.
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
Bullet dodged, until something else crumbles -- the epitome of "hope programming" :-)) Hope you find some time to cleanup/refactor this code.
cheers,
</wqw>
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
I had used it in a small test app, and it worked.
I use just the same file in my production app, and it can not even get the proxy.
My production app is signed and has a manifest.
When I run my app as an admin, it works.
It will immediately get the proxy without any 2nd or third attempt..
Why????????????? The proxy is in my app's path.
My app is signed and manifested. The proxy is not.
The proxy and my app are in Program Files (x86)\<appname>.
Why does my app need to have admin rights to interact with the proxy?
When I put the small test app (which is not signed and not manifested) into the same Program Files (x86)\<appname> directory, it does NOT require to be admin to be executed.
Edit: Hmmm, I see... since my app has uiAccess manifest, it can interact with the ui which is priviledged. Allowing my app to control a proxy which does not have the same privileges could be seen as bad as the proxy does something in its name, but in fact it's my app which does the possibly bad thing with its privileges. That is why the proxy must also have the manifest, I guess.
Edit2: I have given it the same manifest (except * for processorarchitecture instead of x86) and codesigned the moniker.
Now it can't be started using shell and throws invalid procedure or argument error when I use the usual Shell command to run it.
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
This is so frustrating.
It does not matter where I put the proxy/moniker. Obviously I have to somehow deal with the manifest issue, but I don't see how.
Here is my app's manifest:
Code:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
<assemblyIdentity version="1.0.1.0" processorArchitecture="X86" name="Application" type="win32" />
<description>Theme&Trust </description>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*">
</assemblyIdentity>
</dependentAssembly>
</dependency>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="true" />
</requestedPrivileges>
</security>
</trustInfo>
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>false</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>
Can somebody tell me what I must do about a possible manifest for the proxy / moniker?
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
You don't need another manifest for the proxy, you just need to start it elevated as well (using ShellExecuteW with the "runas" verb).
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
I am not starting my application elevated. It is run just normally. No UAC prompt occurs.
What you propose does trigger a UAC prompt:
Code:
Dim lRet&
lRet = ShellExecuteA(0, "runas", uPath, "", uDir, uWindowStyle)
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
Using uiAccess="true" is such an oddball case.
I think this flag is meant to allow your app to interact/capture logon screen. Do you need this? Do you write another TeamViewer?
Chances are most/your apps never need uiAccess="true" but it got set "just in case" all the time and now makes problems.
cheers,
</wqw>
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
In principle uiAccess allows drag drop between elevated and unelevated. I've never gotten it to work, even after jumping through all the hoops and verifying it was in fact enabled for the token (GetTokenInformation/TokenUIAccess).
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
Yes, I do need uiAccess. It is a virtual keyboard, and it does work for me.
I can confirm that when I set uiAccess=false in my app, then the proxy and everything works fine.
I have not yet figured out how to call the proxy with my app having uiAccess=true.
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
Can somebody tell me how to log what is happening?
What I don't understand:
Even when I add a manifest to the proxy with uiAccess=true and code-sign it, it still does not work.
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
Quote:
Originally Posted by
tmighty2
Can somebody tell me how to log what is happening?
Did you try both x86 and x64 executables marked uiAccess=true?
Btw, I think uiAccess=true assume elevated execution, whether you get UAC dialog or not the process must be running elevated.
cheers,
</wqw>
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
Yes, I did try that: My app (32 bit) and the proxy (64bit) have uiAccess=true.
I was a bit unclear about what exactely happens in this case:
Shell fails with the error message "Invalid procedure call or argument, err.number: 5"
So my 32bit app is not even able to start the 64bit proxy even though it has the same privileges.
ps: I know that I should perhaps convert the entire project to TB, but I don't have the time and this problem affects more projects, not only this one.
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
> So my 32bit app is not even able to start the 64bit proxy even though it has the same privileges.
Can you start your x64 proxy manually, with proper command-line parameters? Does it work then?
cheers,
</wqw>
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
Yes! That works!
Can you suggest what I should do?
Must I start the proxy "externally", meaning NOT by my app and then use it? The problem I see with this is that I can not pass the UUID.
I had tried to start it within my app using CreateProcess, but it failed returning 0, and that was already beyond my understanding, so I did not try that any further.
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
ps: I started the proxy by being a normal user and then opening the commandline and typing
Code:
D:\(...)\twsMoniker64_win64.exe 8b6071b5-c1d3-4a8a-97c8-55f554077f9f
And then I used it in my 32bit VB6 app like this:
Code:
Set m_oProxy64 = GetObject("8b6071b5-c1d3-4a8a-97c8-55f554077f9f")
And the proxy currently has this manifest:
Code:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="true"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
And it is code-signed.
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
I still have not managed to start the proxy from within my app. Thank you for any suggestion how to accomplish that.
This approach fails with error 740 indicating that the app requires elevation:
Code:
Private Declare Function CreateProcess Lib "kernel32" Alias "CreateProcessA" (ByVal lpApplicationName As String, ByVal lpCommandLine As String, lpProcessAttributes As SECURITY_ATTRIBUTES, lpThreadAttributes As SECURITY_ATTRIBUTES, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, lpEnvironment As Long, ByVal lpCurrentDirectory As String, lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long
Private Type SECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As Long
bInheritHandle As Long
End Type
Private Type STARTUPINFO
cb As Long
lpReserved As String
lpDesktop As String
lpTitle As String
dwX As Long
dwY As Long
dwXSize As Long
dwYSize As Long
dwXCountChars As Long
dwYCountChars As Long
dwFillAttribute As Long
dwFlags As Long
wShowWindow As Integer
cbReserved2 As Integer
lpReserved2 As Long
hStdInput As Long
hStdOutput As Long
hStdError As Long
End Type
Private Type PROCESS_INFORMATION
hProcess As Long
hThread As Long
dwProcessId As Long
dwthreadid As Long
End Type
Private Const CREATE_NO_WINDOW = &H8000000 ' Prevents the command window from appearing
Private Sub pStartProxy()
Dim sAppPath As String
sAppPath = "D:\Dev\Projects\tws64\TB\Build\twsMoniker64_win64.exe"
sAppPath = App.Path & "\twsMoniker64_win64.exe"
Dim sArg$
sArg = "8b6071b5-c1d3-4a8a-97c8-55f554077f9f"
Dim sCmdLine As String
sCmdLine = sAppPath & " " & sArg
Dim si As STARTUPINFO
Dim pi As PROCESS_INFORMATION
Dim sa As SECURITY_ATTRIBUTES
Dim ret As Long
' Initialize structures
si.cb = Len(si)
si.dwFlags = CREATE_NO_WINDOW ' Prevents the console window from showing
sa.nLength = Len(sa)
sa.lpSecurityDescriptor = 0
sa.bInheritHandle = 0
Debug.Print sCmdLine
ret = CreateProcess(vbNullString, sCmdLine, sa, sa, 0, CREATE_NO_WINDOW, 0, vbNullString, si, pi)
If ret = 0 Then
Debug.Print "Failed to create process. Error: " & Err.LastDllError
Debug.Assert False
Else
End If
End Sub
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
Edit: You have been really very very helpful. I inspected my manifest again and saw that while I use uiAccess=true in this application, I do not in another application of mine with about the same functionality.
I remember that I fought with it a lot as well. It seems I was indecisive whether I really needed it and kept it in that one app and removing it in the other. I guess I wanted to have a 50/50 chance to see whether it's needed.
I will remove uiAccess=true now and wait for customers complaining.
Thank you in any case. I will report back.
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
What I would personally try to do is make proxy executable a console application (it's just a project option in TB) and implement debug logging directly on the console and then from VB6 I would use this cExec.cls to spawn the console application hidden.
Rarely would the proxy need elevation. If it does then the VB6 driver app should be run elevated in first place (using proper manifest) so that every child process gets elevated automatically without need for declared elevation in manifest.
The best part of the cExec class above is that it prevents proxy processes from getting orphaned when the driver app crashes or is terminated from Task Manager. It groups both processes in a group so that the OS terminates all child processes when driver is exiting.
Keep in mind that lifetime of cExec instances matches lifetime of spawned processes i.e. when you set the instance to Nothing the process is terminated (process cannot outlive the cExec instance) so the usage pattern is to keep a reference in a module/global variable for the duration you need your proxy process to be accessible.
It's a different topic altogether but implementing worker processes as a console applications allows communication through console I/O i.e. driver can send commands to console and worker can asynchronously perform the task and respond to console when done. This pattern is used when handling chess engines like Stockfish from client applications.
cheers,
</wqw>
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
fafalone, thank you so much again for pointing me to TB!!!!!!
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
Quote:
Originally Posted by
wqweto
> I would appreciate help with the events very much.
There is no reason for events not to work with this proxy setup per se. Here is my test VB6 code
Code:
'--- Form1
Option Explicit
Private Declare Function GetCurrentThreadId Lib "kernel32" () As Long
Private m_oProxy64 As Object
Private WithEvents m_Voice As SpeechLib.SpVoice
Private WithEvents m_oFont As StdFont
Private Sub Command1_Click()
On Error GoTo EH
If m_oProxy64 Is Nothing Then
Set m_oProxy64 = GetObject("MyApp.MyProxy")
End If
If m_oFont Is Nothing Then
Set m_oFont = m_oProxy64.CreateObject("StdFont")
End If
m_oFont.Size = m_oFont.Size + 2
Print "m_oFont.Size " & m_oFont.Size, GetCurrentThreadId
Exit Sub
EH:
MsgBox Err.Description, vbCritical
Set m_oFont = Nothing
Set m_oProxy64 = Nothing
End Sub
Private Sub m_oFont_FontChanged(ByVal PropertyName As String)
Print "m_oFont_FontChanged " & PropertyName, GetCurrentThreadId
End Sub
This works for
StdFont instances and
FontChanged event is received from x64 instance.
You don't have to use
New to receive events i.e.
CreateObject works fine as long as your variables is declared
WithEvents ... As Strong.Type for early-bound access.
FYI, this is early-bound:
Dim oFont As StdFont
Set oFont = CreateObject("StdFont")
This is late-bound:
Dim oFont As Object
Set oFont = New StdFont
This is early-bound too:
Dim oFont As StdFont
Set oFont = New StdFont
. . . so it does not matter if instance is created with
New or
CreateObject, it only matter how the variable is dimensioned i.e.
As Strong.Type vs
As Object. This is has always been the case, it is not something in connection with x64 vs x86 instancing we are discussing here.
Anyway, obviously there is some incompatibility with
SAPI.SpVoice in the way events are fired. Probably connected with threading/async implementation which boggles cross-process bridge OS is providing.
Just tested x86 build of the proxy project -- events don't fire cross-process too.
About
Private WithEvents m_Voices() As SpVoice syntax -- obviously arrays are not supported in VB6 like this so this is a nice extension to the language in TB which is not completely implemented i.e. events are not massaged to have index property. Apparently ETA on this feature getting fixed can only be shared by Wayne.
One way going forward from here is to implement event stubs in TB and forward these as function calls to a callback object in VB6, something like this
Code:
Private WithEvents m_oVoice As SpeechLib.SpVoice
Private m_oCallback As Object
Public Function CreateSpVoice(oCallback As Object) As Object
Set m_oVoice = New SpeechLib.SpVoice
Set m_oCallback = oCallback
Set CreateSpVoice = m_oVoice '--- fixed: setting retval was missing
End Function
Private Sub m_oVoice_StartStream(ByVal StreamNumber As Long, ByVal StreamPosition As Variant)
If Not m_oCallback Is Nothing Then
m_oCallback.SpVoice_StartStream StreamNumber, StreamPosition
End If
End Sub
Private Sub m_oVoice_Word(ByVal StreamNumber As Long, ByVal StreamPosition As Variant, ByVal CharacterPosition As Long, ByVal Length As Long)
If Not m_oCallback Is Nothing Then
m_oCallback.SpVoice_Word StreamNumber, StreamPosition, CharacterPosition, Length
End If
End Sub
cheers,
</wqw>
m_oCallback.SpVoice_StartStream StreamNumber, StreamPosition
when i use on vba x64,it say error:can't put private object .
only put object args like ?createobject("adodb.recordset") by regedit
can't send vba class1.cls :dim c1 as new class1
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
Quote:
Originally Posted by
VanGoghGaming
Yeah usually you would be right, a form is indeed a class, but for the purpose of inter-process communication using the RunningObjectTable you can only use forms. Apparently there are some subtle differences between a form and a class in this regard. I remember there was a discussion about this in an older thread (can't be bothered to search right now) and there was someone who figured out the nitty-gritty details and came up with a dirty hack that allowed classes to be used in this manner as well.
how to use class1 args to x64 host exe?
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
Quote:
Originally Posted by
wqweto
The discussion was about VB6 forms and private VB6 classes not being able to be placed in ROT for no apparent reason (needed a "cure" in current VBProject structs). There is no such restriction in TB so regular classes get put in ROT too.
Here is a somewhat full sample using TB and VB6:
Moniker2.zip
Just make sure to build x64 target of Moniker.twinproj before running the VB6 project. It will search and auto-start (hidden) Moniker_win64.exe in exact location. It will make sure to shutdown (hidden) proxy process on form unload.
Here is the complete VB6 source code
Code:
Option Explicit
Private m_oProxy As Object
Private m_oWrapper As Object
Private Function GetMyProxy() As Object
Const MONIKER_WIN64_EXE As String = "..\TB\Build\Moniker_win64.exe"
On Error GoTo EH
If m_oProxy Is Nothing Then
Set m_oProxy = GetObject("MyApp.MyProxy")
End If
Set GetMyProxy = m_oProxy
Exit Function
EH:
Shell App.Path & "\" & MONIKER_WIN64_EXE & " /hidden"
Set m_oProxy = GetObject("MyApp.MyProxy")
Set GetMyProxy = m_oProxy
End Function
Private Sub Form_Click()
On Error GoTo EH
If m_oWrapper Is Nothing Then
Set m_oWrapper = GetMyProxy.CreateSpVoice(Me)
End If
m_oWrapper.SpVoice.Speak "this is a test", 1
Exit Sub
EH:
MsgBox Err.Description, vbCritical
Set m_oWrapper = Nothing
Set m_oProxy = Nothing
End Sub
Private Sub Form_Unload(Cancel As Integer)
If Not m_oProxy Is Nothing Then
m_oProxy.Shutdown
End If
End Sub
Public Sub SpVoice_StartStream(ByVal StreamNumber As Long, ByVal StreamPosition As Variant)
Print "StartStream, StreamNumber=" & StreamNumber & ", StreamPosition=" & StreamPosition
End Sub
Public Sub SpVoice_Word(ByVal StreamNumber As Long, ByVal StreamPosition As Variant, ByVal CharacterPosition As Long, ByVal Length As Long)
Print "StartStream, Word=" & StreamNumber & ", StreamPosition=" & StreamPosition & ", CharacterPosition=" & CharacterPosition & ", Length=" & Length
End Sub
Another better approach would be to pass "MyApp.MyProxy" moniker filename on command-line so that a UUID can be generated by client code and used as "communication channel name". If you look at chome.exe processes' command-lines these are littered with such on-the-fly generated UUIDs.
Edit: Just updated Moniker2.zip above with this idea about random UUID and included x64 TB executable.
cheers,
</wqw>
can't down Moniker2.zip
-
Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI
Quote:
Originally Posted by
xiaoyao
can't down Moniker2.zip
https://www.vbforums.com/images/ieimages/2025/09/2.png
cheers,
</wqw>