Имя класса окна excel

Gives output like this

Order   Level   WindowText  ClassName   HWnd    ParentHWnd  ProcessID   ParentProcessID ThreadID    ModuleNameHWin  EXENameProcess
1   0   «No Window Text 0»  msvb_lib_tooltips   67334   67334   3000    2616    3592    C:Windowssystem32MSCOMCTL.OCX    Ed.exe
2   0   «No Window Text 0»  msvb_lib_tooltips   67332   67334   3000    2616    3592    C:Windowssystem32MSCOMCTL.OCX    Ed.exe
3   0   «No Window Text 0»  msvb_lib_tooltips   67330   67334   3000    2616    3592    C:Windowssystem32MSCOMCTL.OCX    Ed.exe
4   0   «No Window Text 0»  msvb_lib_tooltips   67328   67334   3000    2616    3592    C:Windowssystem32MSCOMCTL.OCX    Ed.exe
5   0   «No Window Text 0»  tooltips_class32    4195002 67334   2616    508 1924    C:WindowsWinSxSx86_microsoft.windows.common-controls_

Level is the number of tabs to see the relationship between parent/child window.

1   0   «No Window Text 0»  msvb_lib_tooltips   
2   1   «No Window Text 0»

means

1   0   «No Window Text 0»  msvb_lib_tooltips   
    2   1   «No Window Text 0»

showing line 2 is a child of line 1

I replaced the insert into a RTF control using TOM with MsgBox.

Public Declare Function GetTopWindow Lib "user32" (ByVal hwnd As Long) As Long
    Public Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
    Public Declare Function GetWindowModuleFileName Lib "user32" Alias "GetWindowModuleFileNameA" (ByVal hwnd As Long, ByVal WinModule As String, StringLength As Long) As Long
    Public Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
    Public Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
    Public Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
'    Public Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
          Private Declare Function Process32Next Lib "kernel32" (ByVal hSnapshot As Long, lppe As PROCESSENTRY32) As Long
          Private Declare Function CloseHandle Lib "Kernel32.dll" (ByVal Handle As Long) As Long
          Private Declare Function Process32First Lib "kernel32" (ByVal hSnapshot As Long, lppe As PROCESSENTRY32) As Long
         Private Declare Function CreateToolhelp32Snapshot Lib "kernel32" (ByVal dwFlags As Long, ByVal th32ProcessID As Long) As Long
         Private Type PROCESSENTRY32
             dwSize As Long
             cntUsage As Long
             th32ProcessID As Long           ' This process
             th32DefaultHeapID As Long
             th32ModuleID As Long            ' Associated exe
             cntThreads As Long
             th32ParentProcessID As Long     ' This process's parent process
             pcPriClassBase As Long          ' Base priority of process threads
             dwFlags As Long
             szExeFile As String * 260 ' MAX_PATH
          End Type

          Private Type OSVERSIONINFO
             dwOSVersionInfoSize As Long
             dwMajorVersion As Long
             dwMinorVersion As Long
             dwBuildNumber As Long
             dwPlatformId As Long           '1 = Windows 95 2 = Windows NT
             szCSDVersion As String * 128
          End Type

           Private Const PROCESS_QUERY_INFORMATION = 1024
           Private Const PROCESS_VM_READ = 16
           Private Const MAX_PATH = 260
           Private Const STANDARD_RIGHTS_REQUIRED = &HF0000
           Private Const SYNCHRONIZE = &H100000
          'STANDARD_RIGHTS_REQUIRED Or SYNCHRONIZE Or &HFFF
           Private Const PROCESS_ALL_ACCESS = &H1F0FFF
           Private Const TH32CS_SNAPPROCESS = &H2&
           Private Const hNull = 0
           Private Const GW_CHILD = 5
           Private Const GW_HWNDNEXT = 2





    Sub Main()
    '    WindowChain = 0
        Dim hwnd As Long
            hwnd = GetTopWindow(0)
            If hwnd <> 0 Then
                AddChildWindows hwnd, 0
            End If
    End Sub

    Private Function AddChildWindows(ByVal hwndParent As Long, ByVal Level As Long) As String
          Dim gwfnhwnd As Long, X As Long, WT As String, CN As String, Length As Long, hwnd As Long, TID As Long, PID As Long, MN As String, Ret As Long, Parenthwnd As Long
            Static Order As Long
            Static FirstTime As Long
            Parenthwnd = hwndParent
            If Level = 0 Then
                            hwnd = hwndParent
            Else
                hwnd = GetWindow(hwndParent, GW_CHILD)
            End If
            Do While hwnd <> 0
                     WT = Space(512)
                      Length = GetWindowText(hwnd, WT, 508)
                      WT = Left$(WT, Length)
                      If WT = "" Then WT = Chr(171) & "No Window Text " & Err.LastDllError & Chr(187)
                      CN = Space(512)
                      Length = GetClassName(hwnd, CN, 508)
                      CN = Left$(CN, Length)
                      If CN = "" Then CN = "Error=" & Err.LastDllError


                      TID = GetWindowThreadProcessId(hwnd, PID)

                      MN = Space(512)
                      Length = GetWindowModuleFileName(hwnd, MN, 508)
                      If Length = 0 Then
                        MN = Chr(171) & "Not Available Error=" & Err.LastDllError & Chr(187)
                      Else
                        MN = Left$(MN, Length)
                      End If


                     Dim f As Long, sname As String, PList As String, PPID As Long
                     Dim hSnap As Long, proc As PROCESSENTRY32, Temp As String
                     hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
                     If hSnap = hNull Then Exit Function
                     proc.dwSize = LenB(proc)
                     ' Iterate through the processes
                     f = Process32First(hSnap, proc)
                     Do
                            If PID = proc.th32ProcessID Then
                                sname = StrZToStr(proc.szExeFile)
                                PPID = proc.th32ParentProcessID
                            End If
                            f = Process32Next(hSnap, proc)
                     Loop While f = 1
                      Order = Order + 1
    '                  CStr(Order) & " HWnd=" & FormatNumber$(hwnd, 0, vbFalse, vbFalse, vbFalse) & " Parent HWnd=" & FormatNumber$(Parenthwnd, 0, vbFalse, vbFalse, vbFalse) & " Level=" & CStr(Level) & WT & " (" & CN & ")" & " PID=" & FormatNumber$(PID, 0, vbFalse, vbFalse, vbFalse) & " TID=" & FormatNumber$(TID, 0, vbFalse, vbFalse, vbFalse) & " Module Name:" & MN & " ExeName:" & sname & vbCrLf
                    If FirstTime = 0 Then
                        MsgBox vbCrLf & "Order" & vbTab & "Level" & vbTab & "WindowText" & vbTab & "ClassName" & vbTab & "HWnd" & vbTab & "ParentHWnd" & vbTab & "ProcessID" & vbTab & "ParentProcessID" & vbTab & "ThreadID" & vbTab & "ModuleNameHWin" & vbTab & "EXENameProcess"
                        FirstTime = 1
                    End If
                    MsgBox vbCrLf & CStr(Order) & vbTab & CStr(Level) & vbTab & WT & vbTab & CN & vbTab & CStr(hwnd) & vbTab & CStr(Parenthwnd) & vbTab & CStr(PID) & vbTab & CStr(PPID) & vbTab & CStr(TID) & vbTab & MN & vbTab & sname

                      AddChildWindows hwnd, Level + 1
                      hwnd = GetWindow(hwnd, GW_HWNDNEXT)
            Loop
          End Function



     Function StrZToStr(S As String) As String
         StrZToStr = Left$(S, Len(S) - 1)
      End Function

  • Remove From My Forums
  • Question

  • Hi,

        When I enumerate through an excel window for all the child windows, I get various class names. One such class name is Excel7 which I guess if for a workbook. Is this class name same for all versions of Excel I am using? The reason is that when I ran the code for Excel 2000 and 2003, I got the same class name for the workbook. Please help me understand this.

    Regards,

    Asim.

Answers

  • Hi Asim,

    Yes, Excel7 is the current window class name for the workbook window and it has been fairly static for some time.  We do recognize that there are solutions out there that depend on these window class names, so we don’t tend to change them unless doing so is absolutely necessary.  However, we also don’t document them precisely because we do have to change them on occassion and we really don’t want people relying on them.  So if you are asking whether you can assume this class name to remain the same in future versions of Excel, the answer is no.  Nor will this class name work for all existing versions of Excel.  Presumably, Excel95 is the earliest version with this class name.

    Sincerely,

    Geoff Darst

    Microsoft VSTO Team

  • Hi Asim,

    Yes, Excel7 is still the window class name for workbooks in Excel 2007.  So you can safely use it for all versions you have mentioned.  What I can’t guarantee is that this won’t change for the next version of Office (after 2007).  It *probably* will remain the same, but you never know.

    Sincerely,

    Geoff Darst

    Microsoft VSTO Team

Придется немного изучить API для моего проекта VBA, поэтому я экспериментирую. Интернет предполагает, что этот код должен работать в подпрограмме, чтобы найти дескриптор окна.

Private Declare PtrSafe Function FindWindowA Lib "user32" (ByVal lpClassName    As String, ByVal lpWindowName As String) As LongPtr

Public Sub Test()
Dim P As String
P = Windows(1).Caption
MsgBox P
MsgBox FindWindowA("", P)
End Sub

Когда лист открыт с заголовком «Book1.xlsm», когда я запускаю этот код, я получаю «Book1.xlsm», но затем «0».

Что я делаю неправильно? Если я попробую «EXCEL7» в качестве имени класса вместо нулевой строки, я получу то же самое.

Спасибо тем, кто старше и мудрее

Добавлено позже после обсуждения ниже …. На самом деле это не ответ на мой вопрос, поскольку на первый взгляд неясно, почему окна не могут быть найдены через FindWindowA (это то, что он утверждает, когда я читал) но дальнейшие исследования показывают, что я не могу получить дескрипторы окон напрямую через FindWindowA, но должен учитывать, что они могут быть дочерними окнами. Итак, этот код, по крайней мере, находит мой дескриптор окна:

Private Declare Function FindWindow _
Lib "user32" _
    Alias "FindWindowA" ( _
        ByVal lpClassName As String, _
        ByVal lpWindowName As String) _
As Long

Private Declare Function FindWindowEx _
Lib "user32" _
    Alias "FindWindowExA" ( _
        ByVal hWnd1 As Long, _
        ByVal hWnd2 As Long, _
        ByVal lpsz1 As String, _
        ByVal lpsz2 As String) _
 As Long
Dim hWndParent As Long, hWndDskTop As Long, hWndChild As Long, hWndMine As        Long
Sub Test()
hWndParent = FindWindow("XLMAIN", vbNullString)
hWndDskTop = FindWindowEx(hWndParent, 0&, "XLDESK", vbNullString)
hWndMine = FindWindowEx(hWndDskTop, 0&, "EXCEL7", vbNullString)
MsgBox hWndMine

Это поиск дескриптора окна Book1.xlsm, как я изначально хотел.

3 ответа

Проблема в том, что если вы собираетесь опустить lpClassName при вызове FindWindowA, вам нужно передать ему нулевой указатель. Попробуй это:

Public Sub Test()
    Dim P As String
    P = Windows(1).Caption
    MsgBox P
    MsgBox FindWindowA(vbNullString, P)
End Sub

На самом деле это прекрасный пример того, почему вы должны использовать vbNullString вместо «» для обозначения пустой строки. Когда вы используете «», компилятор фактически создает строку нулевой длины и присваивает ей указатель. Когда вы используете vbNullString, вы получаете универсальный указатель null String. Этот код демонстрирует:

Public Sub StringAddresses()

    MsgBox StrPtr("")
    MsgBox StrPtr(vbNullString)

End Sub

Редактировать: это беспокоило меня, поэтому я немного покопался и нашел имя класса для окон MDI, которые использует Excel. Этот код должен вернуть первое окно, зарегистрированное в этом классе. Обратите внимание, что если открыто более одного окна, это может не дать вам то, которое вам нужно:

Public Sub Test()

    MsgBox FindWindowA("MS-SDIb", vbNullString)

End Sub

Редактировать 2: Не знаю, почему мне потребовалось так много времени, чтобы это пришло мне в голову — если он не находит вашу подпись, установите ее на ваш поисковый запрос (:facepalm:).

Private Sub Test()

    Dim hWnd As Long, cache As String

    cache = Windows(1).Caption
    Windows(1).Caption = "FindME!"
    hWnd = FindWindowA(vbNullString, "FindME!")
    Windows(1).Caption = cache
    Debug.Print hWnd

End Sub


2

Comintern
20 Апр 2015 в 06:38

Не следует использовать 64-разрядную версию PtrSafe FindWindowA с 32-разрядной версией Office. Используйте 32-разрядную версию или используйте директивы компилятора, чтобы книга и проект VBA работали как в 32-разрядных, так и в 64-разрядных установках Office.

#If VBA7 Then
  Private Declare PtrSafe Function FindWindow Lib "USER32" Alias "FindWindowA" ( _
    ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
#Else
  Private Declare Function FindWindow Lib "USER32" Alias "FindWindowA" ( _
    ByVal lpClassName As String, ByVal lpWindowName As String) As Long
#End If

Это компилируется, но я не проверял операцию.

Приложение:

Только что протестировано, и это работает как на 32-битных, так и на 64-битных системах:

Debug.Print FindWindow("Notepad", vbNullString)   ' works OK when Notepad is open

Дает такой вывод

Order   Level   WindowText  ClassName   HWnd    ParentHWnd  ProcessID   ParentProcessID ThreadID    ModuleNameHWin  EXENameProcess
1   0   «No Window Text 0»  msvb_lib_tooltips   67334   67334   3000    2616    3592    C:Windowssystem32MSCOMCTL.OCX    Ed.exe
2   0   «No Window Text 0»  msvb_lib_tooltips   67332   67334   3000    2616    3592    C:Windowssystem32MSCOMCTL.OCX    Ed.exe
3   0   «No Window Text 0»  msvb_lib_tooltips   67330   67334   3000    2616    3592    C:Windowssystem32MSCOMCTL.OCX    Ed.exe
4   0   «No Window Text 0»  msvb_lib_tooltips   67328   67334   3000    2616    3592    C:Windowssystem32MSCOMCTL.OCX    Ed.exe
5   0   «No Window Text 0»  tooltips_class32    4195002 67334   2616    508 1924    C:WindowsWinSxSx86_microsoft.windows.common-controls_

Уровень — это количество вкладок, на которых можно увидеть взаимосвязь между родительским и дочерним окном.

1   0   «No Window Text 0»  msvb_lib_tooltips   
2   1   «No Window Text 0»

Средства

1   0   «No Window Text 0»  msvb_lib_tooltips   
    2   1   «No Window Text 0»

Показывая, что строка 2 является потомком строки 1

Я заменил вставку в элемент управления RTF, используя TOM с MsgBox.

Public Declare Function GetTopWindow Lib "user32" (ByVal hwnd As Long) As Long
    Public Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
    Public Declare Function GetWindowModuleFileName Lib "user32" Alias "GetWindowModuleFileNameA" (ByVal hwnd As Long, ByVal WinModule As String, StringLength As Long) As Long
    Public Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
    Public Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
    Public Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
'    Public Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
          Private Declare Function Process32Next Lib "kernel32" (ByVal hSnapshot As Long, lppe As PROCESSENTRY32) As Long
          Private Declare Function CloseHandle Lib "Kernel32.dll" (ByVal Handle As Long) As Long
          Private Declare Function Process32First Lib "kernel32" (ByVal hSnapshot As Long, lppe As PROCESSENTRY32) As Long
         Private Declare Function CreateToolhelp32Snapshot Lib "kernel32" (ByVal dwFlags As Long, ByVal th32ProcessID As Long) As Long
         Private Type PROCESSENTRY32
             dwSize As Long
             cntUsage As Long
             th32ProcessID As Long           ' This process
             th32DefaultHeapID As Long
             th32ModuleID As Long            ' Associated exe
             cntThreads As Long
             th32ParentProcessID As Long     ' This process's parent process
             pcPriClassBase As Long          ' Base priority of process threads
             dwFlags As Long
             szExeFile As String * 260 ' MAX_PATH
          End Type

          Private Type OSVERSIONINFO
             dwOSVersionInfoSize As Long
             dwMajorVersion As Long
             dwMinorVersion As Long
             dwBuildNumber As Long
             dwPlatformId As Long           '1 = Windows 95 2 = Windows NT
             szCSDVersion As String * 128
          End Type

           Private Const PROCESS_QUERY_INFORMATION = 1024
           Private Const PROCESS_VM_READ = 16
           Private Const MAX_PATH = 260
           Private Const STANDARD_RIGHTS_REQUIRED = &HF0000
           Private Const SYNCHRONIZE = &H100000
          'STANDARD_RIGHTS_REQUIRED Or SYNCHRONIZE Or &HFFF
           Private Const PROCESS_ALL_ACCESS = &H1F0FFF
           Private Const TH32CS_SNAPPROCESS = &H2&
           Private Const hNull = 0
           Private Const GW_CHILD = 5
           Private Const GW_HWNDNEXT = 2





    Sub Main()
    '    WindowChain = 0
        Dim hwnd As Long
            hwnd = GetTopWindow(0)
            If hwnd <> 0 Then
                AddChildWindows hwnd, 0
            End If
    End Sub

    Private Function AddChildWindows(ByVal hwndParent As Long, ByVal Level As Long) As String
          Dim gwfnhwnd As Long, X As Long, WT As String, CN As String, Length As Long, hwnd As Long, TID As Long, PID As Long, MN As String, Ret As Long, Parenthwnd As Long
            Static Order As Long
            Static FirstTime As Long
            Parenthwnd = hwndParent
            If Level = 0 Then
                            hwnd = hwndParent
            Else
                hwnd = GetWindow(hwndParent, GW_CHILD)
            End If
            Do While hwnd <> 0
                     WT = Space(512)
                      Length = GetWindowText(hwnd, WT, 508)
                      WT = Left$(WT, Length)
                      If WT = "" Then WT = Chr(171) & "No Window Text " & Err.LastDllError & Chr(187)
                      CN = Space(512)
                      Length = GetClassName(hwnd, CN, 508)
                      CN = Left$(CN, Length)
                      If CN = "" Then CN = "Error=" & Err.LastDllError


                      TID = GetWindowThreadProcessId(hwnd, PID)

                      MN = Space(512)
                      Length = GetWindowModuleFileName(hwnd, MN, 508)
                      If Length = 0 Then
                        MN = Chr(171) & "Not Available Error=" & Err.LastDllError & Chr(187)
                      Else
                        MN = Left$(MN, Length)
                      End If


                     Dim f As Long, sname As String, PList As String, PPID As Long
                     Dim hSnap As Long, proc As PROCESSENTRY32, Temp As String
                     hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
                     If hSnap = hNull Then Exit Function
                     proc.dwSize = LenB(proc)
                     ' Iterate through the processes
                     f = Process32First(hSnap, proc)
                     Do
                            If PID = proc.th32ProcessID Then
                                sname = StrZToStr(proc.szExeFile)
                                PPID = proc.th32ParentProcessID
                            End If
                            f = Process32Next(hSnap, proc)
                     Loop While f = 1
                      Order = Order + 1
    '                  CStr(Order) & " HWnd=" & FormatNumber$(hwnd, 0, vbFalse, vbFalse, vbFalse) & " Parent HWnd=" & FormatNumber$(Parenthwnd, 0, vbFalse, vbFalse, vbFalse) & " Level=" & CStr(Level) & WT & " (" & CN & ")" & " PID=" & FormatNumber$(PID, 0, vbFalse, vbFalse, vbFalse) & " TID=" & FormatNumber$(TID, 0, vbFalse, vbFalse, vbFalse) & " Module Name:" & MN & " ExeName:" & sname & vbCrLf
                    If FirstTime = 0 Then
                        MsgBox vbCrLf & "Order" & vbTab & "Level" & vbTab & "WindowText" & vbTab & "ClassName" & vbTab & "HWnd" & vbTab & "ParentHWnd" & vbTab & "ProcessID" & vbTab & "ParentProcessID" & vbTab & "ThreadID" & vbTab & "ModuleNameHWin" & vbTab & "EXENameProcess"
                        FirstTime = 1
                    End If
                    MsgBox vbCrLf & CStr(Order) & vbTab & CStr(Level) & vbTab & WT & vbTab & CN & vbTab & CStr(hwnd) & vbTab & CStr(Parenthwnd) & vbTab & CStr(PID) & vbTab & CStr(PPID) & vbTab & CStr(TID) & vbTab & MN & vbTab & sname

                      AddChildWindows hwnd, Level + 1
                      hwnd = GetWindow(hwnd, GW_HWNDNEXT)
            Loop
          End Function



     Function StrZToStr(S As String) As String
         StrZToStr = Left$(S, Len(S) - 1)
      End Function


-1

Trigger
19 Апр 2015 в 07:55

 
Calm
 
(2002-12-26 12:19)
[0]

Например, класс окна Excel называется XLMAIN, а Word — OpusApp

Нужно для настройки проги, которая сворачивает окна в tray (не моя прога).

Заранее спасибо.


 
MBo
 
(2002-12-26 12:33)
[1]

посмотри Winsight-ом (ws32.exe в BIN)


 
Calm
 
(2002-12-26 12:41)
[2]

Спасибо, помогло :)


Кто-нибудь знает, как заполучить Excel.Application IDispatch* указатель, связанный с процессом Excel, в который dll был загружен?

Ключевым моментом здесь является то, что процесс excel.exeи указатель мне нужен должен принадлежат к этому процессу. Использование таблицы запущенных объектов не будет работать, поскольку Excel регистрирует только первый экземпляр.

Я надеюсь, что есть некоторые низкоуровневые хитрости COM, но я не эксперт в этой области.

1

Решение

РЕДАКТИРОВАНИЕ II Код находится под WTFPL версия лицензии 2.

РЕДАКТИРОВАНИЕ: Добавьте параметр PID, чтобы разрешить фильтрацию, когда в данный момент запущено несколько процессов Excel, согласно предложению комментария от @EricBrown.

Мне удалось получить работу IDispatch* в объект Excel «Приложение» без использования ROT. Хитрость в том, чтобы использовать MSAA. Мой код работает как отдельное консольное приложение, но я думаю, что если код выполняется в процессе Excel через DLL Injection, он МОЖЕТ работать нормально. Возможно, вам придется быть в отдельной теме. Дайте мне знать, если вы хотите, чтобы я подтолкнул expriment к уровню внедрения DLL.

Протестировано нормально на Window7 64b, со сборками UNICODE (32 бита и 64 бита).
Excel версия 2010 64 бит (версия «14»)

Я получаю IDispatch через свойство application из объекта «Worksheet». Следствие: должен быть открытый рабочий лист. Чтобы найти хорошее окно MSSA, мне нужно имя класса окна фрейма Excel верхнего уровня. В Excel 2010 это «XLMAIN». Имя класса для рабочих листов — «EXCEL7», и это кажется «стандартным».

Я не смог напрямую устроиться на работу IDispatch* из главного окна Excel, но не очень старался. Это может включать в себя #import с DLL автоматизации из Excel, чтобы QueryInterface IDispatch, который MSAA дает для главного окна (этот IDispatch НЕ для объекта Application)

#include <atlbase.h>

#pragma comment( lib, "Oleacc.lib" )

HRESULT GetExcelAppDispatch( CComPtr<IDispatch> & spIDispatchExcelApp, DWORD dwExcelPID ) {

struct ew {
struct ep {
_TCHAR* pszClassName;
DWORD dwPID;
HWND hWnd;
};
static BOOL CALLBACK ewp( HWND hWnd, LPARAM lParam ) {
TCHAR szClassName[ 64 ];
if ( GetClassName( hWnd, szClassName, 64 ) ) {
ep* pep = reinterpret_cast<ep*>( lParam );
if ( _tcscmp( szClassName, pep->pszClassName ) == 0 ) {
if ( pep->dwPID == 0 ) {
pep->hWnd = hWnd;
return FALSE;
} else {
DWORD dwPID;
if ( GetWindowThreadProcessId( hWnd, &dwPID ) ) {
if ( dwPID == pep->dwPID ) {
pep->hWnd = hWnd;
return FALSE;
}
}
}
}
}
return TRUE;
}
};

ew::ep ep;

ep.pszClassName = _TEXT( "XLMAIN" );
ep.dwPID = dwExcelPID;
ep.hWnd = NULL;
EnumWindows( ew::ewp, reinterpret_cast<LPARAM>( &ep ) );
HWND hWndExcel = ep.hWnd;
if ( ep.hWnd == NULL ) {
printf( "Can't Find Main Excel Window with EnumWindowsn" );
return -1;
}

ep.pszClassName = _TEXT( "EXCEL7" );
ep.dwPID = 0;
ep.hWnd = NULL;
EnumChildWindows( hWndExcel, ew::ewp, reinterpret_cast<LPARAM>( &ep ) );
HWND hWndWorkSheet = ep.hWnd;
if ( hWndWorkSheet == NULL ) {
printf( "Can't Find a WorkSheet with EnumChildWindowsn" );
return -1;
}

CComPtr<IDispatch> spIDispatchWorkSheet;
HRESULT hr = AccessibleObjectFromWindow( hWndWorkSheet, OBJID_NATIVEOM, IID_IDispatch,
reinterpret_cast<void**>( &spIDispatchWorkSheet ) );
if ( FAILED( hr ) || ( spIDispatchWorkSheet == 0 ) ) {
printf( "AccessibleObjectFromWindow Failedn" );
return hr;
}
CComVariant vExcelApp;
hr = spIDispatchWorkSheet.GetPropertyByName( CComBSTR( "Application" ), &vExcelApp );
if ( SUCCEEDED( hr ) && ( vExcelApp.vt == VT_DISPATCH ) ) {
spIDispatchExcelApp = vExcelApp.pdispVal;
return S_OK;
}
return hr;

}
int _tmain(int argc, _TCHAR* argv[])
{

DWORD dwExcelPID = 0;
if ( argc > 1 ) dwExcelPID = _ttol( argv[ 1 ] );

HRESULT hr = CoInitialize( NULL );
bool bCoUnInitializeTodo = false;
if ( SUCCEEDED( hr ) ) {
bCoUnInitializeTodo = true;
CComPtr<IDispatch> spDispatchExcelApp;
hr = GetExcelAppDispatch( spDispatchExcelApp, dwExcelPID );
if ( SUCCEEDED( hr ) && spDispatchExcelApp ) {
CComVariant vExcelVer;
hr = spDispatchExcelApp.GetPropertyByName( CComBSTR( "Version" ), &vExcelVer );
if ( SUCCEEDED( hr ) && ( vExcelVer.vt == VT_BSTR ) ) {
wprintf( L"Excel Version is %sn", vExcelVer.bstrVal );
}
}
}
if ( bCoUnInitializeTodo ) CoUninitialize();
return 0;
}

2

Другие решения

Вы должны быть в состоянии узнать, как это сделать, просмотрев код в ExcelDNA. Этот проект содержит код, который возвращается в Excel из библиотеки расширений. Код, вероятно, будет более сложным, чем вам нужно, но будет реализовывать необходимую ссылку.

1

Вот как я это делаю: (подтвердите @manuell). dispatch_wrapper это класс, вот конструктор, чтобы установить m_disp_application:

dispatch_wrapper(void)
{
DWORD target_process_id = ::GetProcessId(::GetCurrentProcess());

if (getProcessName() == "excel.exe"){
HWND hwnd = ::FindWindowEx(0, 0, "XLMAIN", NULL);
while (hwnd){
DWORD process_id;
::GetWindowThreadProcessId(hwnd, &process_id);
if (process_id == target_process_id){
HWND hwnd_desk = ::FindWindowEx(hwnd, 0, "XLDESK", NULL);
HWND hwnd_7 = ::FindWindowEx(hwnd_desk, 0, "EXCEL7", NULL);
IDispatch* p = nullptr;
if (SUCCEEDED(::AccessibleObjectFromWindow(hwnd_7, OBJID_NATIVEOM, IID_IDispatch, (void**)&p))){
LPOLESTR name[1] = {L"Application"};
DISPID dispid;
if (SUCCEEDED(p->GetIDsOfNames(IID_NULL, name, 1U, LOCALE_SYSTEM_DEFAULT, &dispid))){
CComVariant v;
DISPPARAMS dp;
::memset(&dp, NULL, sizeof(DISPPARAMS));
EXCEPINFO ei;
::memset(&ei, NULL, sizeof(EXCEPINFO));
if (SUCCEEDED(p->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dp, &v, &ei, NULL))){
if (v.vt == VT_DISPATCH){
m_disp_application = v.pdispVal;
m_disp_application->AddRef();
return;
}
}
}
}
}
hwnd = ::FindWindowEx(0, hwnd, "XLMAIN", NULL);
}
}
m_disp_application = nullptr;
}

getProcessName() возвращает нижний регистр

1

Поскольку приложения Office регистрируют свои документы в ROT, вы можете прикрепить к экземплярам рядом с первым (который уже находится в ROT) с помощью получение IDispatch для документов в ROT, тогда вы можете использовать document.Application.hwnd (это VBA, вам нужно перевести на IDispatch :: GetIDsOfNames и IDispatch :: Вызвать с помощью DISPATCH_PROPERTYGET) чтобы получить дескрипторы окна всех экземпляров Excel.

Теперь у вас есть сопоставление между дескрипторами IDispatch и Windows всех экземпляров Excel, пришло время найти свой собственный экземпляр Excel. Вы можете вызвать GetWindowThreadProcessId для дескрипторов окна, чтобы получить идентификаторы процесса, затем сравнить с вашим собственным идентификатором процесса, возвращенным GetCurrentProcessId, чтобы увидеть, какое окно Excel принадлежит вашему текущему процессу, и посмотреть в сопоставлении HWND и IDispatch, чтобы найти текущие приложения Excel. Интерфейс IDispatch.

0

Понравилась статья? Поделить с друзьями:
  • Имя имеет неправильный синтаксис excel
  • Имя документа в ms word отображается
  • Имя документа word по умолчанию
  • Имя документа word имеет расширение
  • Имя документа excel по умолчанию