Page 3 of 3 FirstFirst 123
Results 81 to 100 of 100

Thread: Compatibility of 32-bit VB6 Applications with 64-bit SAPI

  1. #81

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2017
    Posts
    761

    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&amp;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?

  2. #82
    PowerPoster VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    2,619

    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).

  3. #83

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2017
    Posts
    761

    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)
    Last edited by tmighty2; Oct 13th, 2024 at 08:48 PM.

  4. #84
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    6,167

    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>

  5. #85
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    7,653

    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).

  6. #86

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2017
    Posts
    761

    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.
    Last edited by tmighty2; Oct 14th, 2024 at 02:30 PM.

  7. #87

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2017
    Posts
    761

    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.
    Last edited by tmighty2; Oct 14th, 2024 at 02:47 PM.

  8. #88
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    6,167

    Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI

    Quote Originally Posted by tmighty2 View Post
    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>

  9. #89

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2017
    Posts
    761

    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.
    Last edited by tmighty2; Oct 14th, 2024 at 03:09 PM.

  10. #90
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    6,167

    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>

  11. #91

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2017
    Posts
    761

    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.

  12. #92

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2017
    Posts
    761

    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.

  13. #93

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2017
    Posts
    761

    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
    Last edited by tmighty2; Oct 14th, 2024 at 09:16 PM.

  14. #94

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2017
    Posts
    761

    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.

  15. #95
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    6,167

    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>

  16. #96

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2017
    Posts
    761

    Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI

    fafalone, thank you so much again for pointing me to TB!!!!!!

  17. #97
    PowerPoster
    Join Date
    Jan 2020
    Posts
    5,538

    Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI

    Quote Originally Posted by wqweto View Post
    > 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

  18. #98
    PowerPoster
    Join Date
    Jan 2020
    Posts
    5,538

    Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI

    Quote Originally Posted by VanGoghGaming View Post
    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?

  19. #99
    PowerPoster
    Join Date
    Jan 2020
    Posts
    5,538

    Re: Compatibility of 32-bit VB6 Applications with 64-bit SAPI

    Quote Originally Posted by wqweto View Post
    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

  20. #100

Page 3 of 3 FirstFirst 123

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width