Results 1 to 5 of 5

Thread: Opening documents from Windows Explorer

  1. #1

    Thread Starter
    I'm about to be a PowerPoster! Joacim Andersson's Avatar
    Join Date
    Jan 1999
    Location
    Sweden
    Posts
    14,649

    Opening documents from Windows Explorer

    Hi all,

    I have a bit of a problem with the following scenario:

    I'm trying to get my MDI application to open documents from Windows Explorer.
    This isn't actually any problems but when ever I double click on a document a new instance of the application is started.

    So what I'm trying to do is to let the old instance (if any) open the new document.
    This is how I'm trying to do this:
    The start-up object is set to Sub Main().
    The first thing the Main sub does is to check if App.PrevInstance is True.
    If not it loads the frmMDI form that saves its hWnd to the registry (and other startup stuff in the Load event).
    If there is a previous instance loaded Sub Main reads the hWnd value from the registry.
    Then it calls the Command function to get the file name (if any).
    The file name is saved to a string called sFile.
    After that it sends a user defined message (WM_USER + &HFC) to the previous instance with wParam set to the length of the string (sFile) and lParam to the actual string value.

    I've subclassed the frmMDI form and it gets the message allright.
    But when I try to retrieve the original string it fails.
    I use CopyMemory in my WinProc to copy wParam back into a string but I only get garbage.

    Here's the code I use:
    Code:
    'In module1:
    Private Declare Function SendMessageString _
     Lib "user32" Alias "SendMessageA" ( _
     ByVal hwnd As Long, _
     ByVal wMsg As Long, _
     ByVal wParam As Long, _
     ByVal lParam As String) As Long
    
    Public Const = UM_OPENFILE = &H4FC&
    
    Public Sub Main()
        Dim sFile As String
        Dim hWnd As Long
    
        If App.PrevInstance Then
            sFile = Command
            If Len(sFile) Then
                hWnd = CLng(GetSetting(App.EXEName, "Instance", "hWnd", "0")
                If hWnd Then
                    SendMessageString hWnd, UM_OPENFILE, LenB(sFile), sFile
                    End
                End If
            End If
        End If
        frmMDI.Show
    End Sub
    
    '**********************************
    'in frmMDI
    Private Sub MDIForm_Load()
        SaveSetting App.EXEName, "Instance", "hWnd", Me.hwnd
        HookForm Me.hwnd 'set up the sub-classing
        'other init stuff goes here
    End Sub
    
    '**********************************
    'in Module2 (sub-classing module)
    Private Declare Sub CopyMemory _
     Lib "kernel32" Alias "RtlMoveMemory" ( _
     Destination As Any, _
     Source As Any, _
     ByVal Length As Long)
    
    Private Declare Function SetWindowLong _
     Lib "user32" Alias "SetWindowLongA" ( _
     ByVal hwnd As Long, _
     ByVal nIndex As Long, _
     ByVal dwNewLong As Long) As Long
    
    Private Declare Function CallWindowProc _
     Lib "user32" Alias "CallWindowProcA" ( _
     ByVal lpPrevWndFunc As Long, _
     ByVal hwnd As Long, _
     ByVal Msg As Long, _
     ByVal wParam As Long, _
     ByVal lParam As Long) As Long
    
    Private Const GWL_WNDPROC = (-4)
    Private Const WM_DESTROY = &H2&
    
    Private lngHwnd As Long
    Private lngPrevWndProc As Long
    
    Public Sub HookForm(frmHandle As Long)
        lngHwnd = frmHandle
        lngPrevWndProc = SetWindowLong(lngHwnd, GWL_WNDPROC, AddressOf WinProc)
    End Sub
    
    Public Sub UnhookForm()
        SetWindowLong lngHwnd, GWL_WNDPROC, lngPrevWndProc
    End Sub
    
    Public Function WinProc(ByVal hw As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
        Dim sFile As String
        
        Select Case uMsg
            Case UM_OPENFILE
                If wParam > 0 Then
                    sFile = String$(wParam, vbNullChar)
                    CopyMemory ByVal sFile, ByVal lParam, wParam
                End If
            Case WM_DESTROY
                'the window has been closed
                UnhookForm
        End Select
        WinProc = CallWindowProc(lngPrevWndProc, hw, uMsg, wParam, lParam)
        If Len(sFile) Then
             MsgBox sFile 'here I actually want to call my open file procedure
        End If
    End Function
    Why doesn't the above work??????

    The message is sent and retrieved by my WinProc above but I just can't get the string out correctly.

    Best regards

  2. #2
    jim mcnamara
    Guest
    I've seen this before in another guise.

    You are getting StringA and StringW (Ansi vs Unicode) garbling.
    sfile is being sent as a string which the compiler thinks is a wide string(two bytes per char), but in fact it is an Ansi (one byte per char) string.

    For a start try:

    Code:
                If hWnd Then
                    SendMessageString hWnd, UM_OPENFILE, LenB(sFile), StrConv(sFile,vbUnicode)
                    End

  3. #3
    Fanatic Member crispin's Avatar
    Join Date
    Aug 2000
    Location
    2 clicks west of a Quirkafleeg...Cornwall, England
    Posts
    754
    Joacim,

    Just to let you know I've been bashing the hell out of this all morning, I've tried enough combos of pushing and pulling Unicode and ANSI strings to make your hair turn blue, and I still can't get the string back either, ByVal, ByRef, by lstrLenW, by lStrLenA, and various other slimy memory hacks...

    sorry it's not better news....

    I don't get it.....
    Crispin
    VB6 ENT SP5
    VB.NET
    W2K ADV SVR SP3
    WWW.BLOCKSOFT.CO.UK

    [Microsoft Basic: 1976-2001, RIP]

  4. #4
    Megatron
    Guest
    You could also pass an atom via the GlobalAddAtom(), GlobalGetAtomName() and GlobalDeleteAtom() functions.

    For example, to send it you could use:
    VB Code:
    1. Dim nAtom As Integer
    2. nAtom = GlobalAddAtom("MyString")
    3. SendMessage hwnd, WM_MYMESSAGE, nAtom, 0
    Now in your WinProc, add the following code:
    VB Code:
    1. If wMsg = WM_MYMESSAGE Then
    2.         Dim iLength As String
    3.         Dim sText As String
    4.         sText = Space$(255)
    5.        
    6.         iLength = GlobalGetAtomName(wParam, sText, 255)
    7.         GlobalDeleteAtom (wParam)
    8.         sText = Left$(sText, iLength)
    9.         Debug.Print sText
    10.         Exit Function
    11.     End If

  5. #5

    Thread Starter
    I'm about to be a PowerPoster! Joacim Andersson's Avatar
    Join Date
    Jan 1999
    Location
    Sweden
    Posts
    14,649

    Thumbs up

    Thanks a lot Megatron!
    I never thought about using atoms, it's so easy.

    Just one thing for anyone else that want to try this out:
    Change the declaration in the functions from Integer into Long because they are unsigned and it just didn't work until I changed the declarations.

    Thanks again Megatron!!!!

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