tags:

views:

33

answers:

1

I'm writing a VBA Macro in MS Outlook that needs to find the active window in a particular process. The goal of this is to get the name of the active window/document, even if its parent application has a multiple document interface.

To get the active process, I'm using GetGUIThreadInfo along with GetCurrentThreadId from user32.dll. Here's the pertinent code:

Private Type RECT
        Left As LongPtr
        Top As LongPtr
        Right As LongPtr
        Bottom As LongPtr
End Type

Private Type GUITHREADINFO

    cbSize As LongPtr
    flags As LongPtr
    hwndActive As LongPtr
    hwndFocus As LongPtr
    hwndCapture As LongPtr
    hwndMenuOwner As LongPtr
    hwndMoveSize As LongPtr
    hwndCaret As LongPtr
    rcCaret As RECT

End Type

Private Declare PtrSafe Function GetWindowThreadProcessId Lib "user32" ( _
    ByVal hWnd As LongPtr) As LongPtr

Private Declare PtrSafe Function GetGUIThreadInfo Lib "user32" _
    (ByVal dwthreadid As LongPtr, _
    lpguithreadinfo As GUITHREADINFO) As LongPtr

Sub MyFunction()

    Dim strWindowTitle As String
    strWindowTitle = Space(30)

    Dim GUIInfo As GUITHREADINFO
    GUIInfo.cbSize = LenB(GUIInfo)

    Call GetGUIThreadInfo(GetCurrentThreadId, GUIInfo)
    Call GetWindowText(GUIInfo.hwndActive, strWindowTitle, 30)

    Debug.Print strWindowTitle

End Sub

No matter what I do (changing types around, using different methods to get the active thread ID) the output is blank. Printing GUIInfo.hwndActive also gives me 0. The current thread ID is being found fine, but I'm doing something wrong in the GetGUIThreadInfo function. I suspect it has to do with calling this from VBA, rather than VB.net (as those were most of the examples I was able to find)

I've also tried enumerating through the child windows, but it's difficult for me to tell which one of those is active (if there's a function to do this that I've missed, that would probably work as well!)

I'm running Outlook 2010 x64 on a 64-bit machine, hence my use of LongPtr.

Any assistance would be much appreciated.

A: 

I think you're jumping the gun with some of the LongPtrs. For example the first parameter to GetGUIThreadInfo is a DWORD for the thread id, even on 64bit windows DWORD is still 32 bits.

    c:\Users\logan>type foop.c
    #include <windows.h>
    #include <stdio.h>

    int main()
    {
    int n = sizeof(DWORD);
    printf("%d\n", n);
    n = sizeof(DWORD_PTR);
    printf("%d\n", n);
    return 0;
    }


    c:\Users\logan>cl foop.c
    Microsoft (R) C/C++ Optimizing Compiler Version 14.00.50727.762 for x64
    Copyright (C) Microsoft Corporation.  All rights reserved.

    foop.c
    Microsoft (R) Incremental Linker Version 8.00.50727.762
    Copyright (C) Microsoft Corporation.  All rights reserved.

    /out:foop.exe
    foop.obj

    c:\Users\logan>foop.exe
    4
    8

Likewise, LONG is actually still 32bits, so your RECT definition is wrong.

It's also been a very long time since I've done VB, but I don't remember if ByVal or ByRef is the default. If the former you problem need to specify ByRef on the struct parameter to GetGUIThreadInfo.

Logan Capaldo
Thanks, but I had originally used regular Long types (and I tried your suggested substitutions; no dice). Specifying ByRef also didn't make a difference. I actually thought that LongPtrs were interchangeable with Long where 32 bit pointers are concerned - is that the case? I could be wrong.
Andrew
LongPtr's size depend on on whether or not you're a 64bit process, so for your case LongPtr is 64bits.
Logan Capaldo
Oh, I see. Thanks for your help!
Andrew