powered by simpleCommunicator - 2.0.38     © 2025 Programmizd 02
Форумы / Microsoft Office [игнор отключен] [закрыт для гостей] / API: Как в hook-процедуре для GetOpenFileName получить OPENFILENAME?
8 сообщений из 8, страница 1 из 1
API: Как в hook-процедуре для GetOpenFileName получить OPENFILENAME?
    #39554776
Фотография Сын вождя
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Здравствуйте.

Не получается в hook-процедуре для GetOpenFileName считать структуру OPENFILENAME.
Пытаюсь делать все по феншую. То бишь, в соответствии с официальной документацией.
Но Word схлопывается на CopyMemory (пометил в коде):

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
Option Explicit: Option Base 0: Option Compare Binary
    
Private Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr
Private Declare PtrSafe Sub CopyMemory Lib "KERNEL32" Alias "RtlMoveMemory" (lpDest As Any, lpSource As Any, ByVal cBytes As Long)
Private Declare PtrSafe Function GetOpenFileName Lib "comdlg32" Alias "GetOpenFileNameA" (pOpenFileName As OPENFILENAME) As Boolean

Private Type OPENFILENAME
    lStructSize As Long
    hwndOwner As LongPtr
    hInstance As LongPtr
    lpstrFilter As String
    lpstrCustomFilter As String
    nMaxCustFilter As Long
    nFilterIndex As Long
    lpstrFile As String
    nMaxFile As Long
    lpstrFileTitle As String
    nMaxFileTitle As Long
    lpstrInitialDir As String
    lpstrTitle As String
    flags As Long
    nFileOffset As Integer
    nFileExtension As Integer
    lpstrDefExt As String
    lCustData As LongPtr
    lpfnHook As LongPtr
    lpTemplateName As String
    pvReserved As LongPtr
    dwReserved As Long
    FlagsEx As Long
End Type

Private Type NMHDR
    hwndFrom As LongPtr
    idfrom As LongPtr
    code As Long
End Type

Private Type OFNOTIFY
    hdr As NMHDR
    lpOFN As OPENFILENAME
    pszFile As String
End Type

Const WM_NOTIFY = &H4E
Const CDN_FIRST = -601&
Const CDN_TYPECHANGE = (CDN_FIRST - 6&)

Const OFN_ENABLEHOOK = &H20
Const OFN_ENABLESIZING = &H800000
Const OFN_EXPLORER = &H80000
Const OFN_HIDEREADONLY = &H4
Const OFN_LONGNAMES = &H200000
Const OFN_NOVALIDATE = &H100
Const OFN_OVERWRITEPROMPT = &H2
Const OFN_PATHMUSTEXIST = &H800

Private Function GetAddressOfFunction(ByVal Adr As LongPtr) As LongPtr
    GetAddressOfFunction = Adr
End Function

Private Function MyHookProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As Long
Dim oHead As NMHDR
Dim oNotify As OFNOTIFY
    If uMsg = WM_NOTIFY Then
        ' заголовок события
        CopyMemory oHead, ByVal lParam, LenB(oHead)
        ' изменили тип файлов
        If oHead.code = CDN_TYPECHANGE Then
            ' параметры события
            CopyMemory oNotify, ByVal lParam, LenB(oNotify) ' тут Word схлопывается сразу !!!
        End If
    End If
End Function

Function API_SelectFolderDlg() As Long
Dim OFN As OPENFILENAME
    OFN.hwndOwner = GetActiveWindow()
    OFN.hInstance = 0
    OFN.flags = OFN_EXPLORER _
             Or OFN_ENABLESIZING _
             Or OFN_LONGNAMES _
             Or OFN_HIDEREADONLY _
             Or OFN_PATHMUSTEXIST _
             Or OFN_NOVALIDATE _
             Or OFN_ENABLEHOOK
    OFN.lpfnHook = GetAddressOfFunction(AddressOf MyHookProc)
    OFN.lpstrFilter = "Все файлы" & vbNullChar & "*.*" & vbNullChar & _
                      "Документы Word" & vbNullChar & "*.DOCX;*.DOCM;*.DOC;*.RTF" & vbNullChar & _
                      vbNullChar
    OFN.nFilterIndex = 1
    OFN.lpstrInitialDir = vbNullChar
    OFN.lpstrFile = String$(4096, vbNullChar)
    OFN.nMaxFile = Len(OFN.lpstrFile) - 1
    OFN.lStructSize = LenB(OFN)
    GetOpenFileName OFN
End Function


Пробовал и такой вариант:

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
Private Type OFNOTIFY
    hdr As NMHDR
    lpOFN As LongPtr ' OPENFILENAME
    pszFile As String
End Type

Private Function MyHookProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As Long
Dim oNotify As OFNOTIFY
Dim OFN As OPENFILENAME
    If uMsg = WM_NOTIFY Then
        CopyMemory oNotify, ByVal lParam, LenB(oNotify)
        If oNotify.hdr.code = CDN_TYPECHANGE Then
            CopyMemory OFN, ByVal oNotify.lpOFN, LenB(OFN) ' тут Word схлопывается, но не сразу !!!
        End If
    End If
End Function



Подскажите, где дурак?
...
Рейтинг: 0 / 0
API: Как в hook-процедуре для GetOpenFileName получить OPENFILENAME?
    #39554923
234522
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Сын вождя
Код: vbnet
1.
2.
3.
4.
5.
Private Type OFNOTIFY
    hdr As NMHDR
    lpOFN As OPENFILENAME
    pszFile As String
End Type



Подскажите, где дурак?
...
Рейтинг: 0 / 0
API: Как в hook-процедуре для GetOpenFileName получить OPENFILENAME?
    #39554967
Фотография Сын вождя
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
234522Сын вождя
Код: vbnet
1.
2.
3.
4.
5.
Private Type OFNOTIFY
    hdr As NMHDR
    lpOFN As OPENFILENAME
    pszFile As String
End Type



Подскажите, где дурак?
Но этот вариант тоже не работает (см. пример выше):
Код: vbnet
1.
2.
3.
4.
5.
Private Type OFNOTIFY
    hdr As NMHDR
    lpOFN As LongPtr ' OPENFILENAME
    pszFile As String
End Type


Пока, выкинул CopyMemory и читаю данные напрямую из формы, через SendMessage.
Но хотелось бы понять, где ошибка с OPENFILENAME?
...
Рейтинг: 0 / 0
API: Как в hook-процедуре для GetOpenFileName получить OPENFILENAME?
    #39555010
234522
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Сын вождя,

нет VBA7, поэтому без LongPtr. И без String, до кучи (может, паранойя):
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
Option Explicit: Option Base 0: Option Compare Binary
    
Private Declare Function GetActiveWindow Lib "user32" () As Long
Private Declare Sub CopyMemory Lib "KERNEL32" Alias "RtlMoveMemory" (lpDest As Any, lpSource As Any, ByVal cBytes As Long)
Private Declare Function GetOpenFileName Lib "comdlg32" Alias "GetOpenFileNameW" (pOpenFileName As OPENFILENAME) As Long

Private Type OPENFILENAME
    lStructSize As Long
    hwndOwner As Long
    hInstance As Long
    lpstrFilter As Long 'String
    lpstrCustomFilter As Long 'String
    nMaxCustFilter As Long
    nFilterIndex As Long
    lpstrFile As Long 'String
    nMaxFile As Long
    lpstrFileTitle As Long 'String
    nMaxFileTitle As Long
    lpstrInitialDir As Long 'String
    lpstrTitle As Long 'String
    flags As Long
    nFileOffset As Integer
    nFileExtension As Integer
    lpstrDefExt As Long 'String
    lCustData As Long
    lpfnHook As Long
    lpTemplateName As Long 'String
    pvReserved As Long
    dwReserved As Long
    FlagsEx As Long
End Type

Private Type NMHDR
    hwndFrom As Long
    idfrom As Long
    code As Long
End Type

Private Type OFNOTIFY
    hdr As NMHDR
    lpOFN As Long 'OPENFILENAME
    pszFile As Long 'String
End Type

Const WM_NOTIFY = &H4E
Const CDN_FIRST = -601&
Const CDN_TYPECHANGE = (CDN_FIRST - 6&)

Const OFN_ENABLEHOOK = &H20
Const OFN_ENABLESIZING = &H800000
Const OFN_EXPLORER = &H80000
Const OFN_HIDEREADONLY = &H4
Const OFN_LONGNAMES = &H200000
Const OFN_NOVALIDATE = &H100
Const OFN_OVERWRITEPROMPT = &H2
Const OFN_PATHMUSTEXIST = &H800

Private Function GetAddressOfFunction(ByVal Adr As Long) As Long
    GetAddressOfFunction = Adr
End Function

Private Function MyHookProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
 Dim oHead As NMHDR
 Dim oNotify As OFNOTIFY
 If uMsg = WM_NOTIFY Then
     ' заголовок события
     CopyMemory oHead, ByVal lParam, LenB(oHead)
     ' изменили тип файлов
     If oHead.code = CDN_TYPECHANGE Then
         ' параметры события
         CopyMemory oNotify, ByVal lParam, LenB(oNotify) ' тут Word схлопывается сразу !!!
         Dim oOFN As OPENFILENAME
         CopyMemory oOFN.lStructSize, ByVal oNotify.lpOFN, LenB(oOFN.lStructSize)
         CopyMemory oOFN, ByVal oNotify.lpOFN, oOFN.lStructSize
     End If
 End If
End Function

Function API_SelectFolderDlg() As Long
 Dim OFN As OPENFILENAME
 OFN.hwndOwner = GetActiveWindow()
 OFN.hInstance = 0
 OFN.flags = OFN_EXPLORER _
          Or OFN_ENABLESIZING _
          Or OFN_LONGNAMES _
          Or OFN_HIDEREADONLY _
          Or OFN_PATHMUSTEXIST _
          Or OFN_NOVALIDATE _
          Or OFN_ENABLEHOOK
 OFN.lpfnHook = GetAddressOfFunction(AddressOf MyHookProc)
 OFN.lpstrFilter = StrPtr("Все файлы" & vbNullChar & "*.*" & vbNullChar & _
                   "Документы Word" & vbNullChar & "*.DOCX;*.DOCM;*.DOC;*.RTF" & vbNullChar & _
                   vbNullChar)
 OFN.nFilterIndex = 1
 OFN.lpstrInitialDir = 0 'vbNullChar
 Dim strFile As String
 strFile = String$(4096, vbNullChar)
 OFN.lpstrFile = StrPtr(strFile)
 OFN.nMaxFile = 4096
 OFN.lStructSize = LenB(OFN)
 GetOpenFileName OFN
End Function

Не падает, в Locals значения правдоподобные.
Может, не мучиться, и взять готовое 20756996 ?
...
Рейтинг: 0 / 0
API: Как в hook-процедуре для GetOpenFileName получить OPENFILENAME?
    #39555165
Фотография Сын вождя
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
234522нет VBA7, поэтому без LongPtr. И без String, до кучи (может, паранойя)
Без String неудобно, когда надо получать, а не только отправлять. Как раз мой случай.

Переход на GetOpenFileNameW (вместо GetOpenFileNameA) поддерживаю, хотя он и влечет применение StrConv.

234522Не падает, в Locals значения правдоподобные.
Да, разобрался! Благодарю! Понял ошибку с размером.

234522Может, не мучиться, и взять готовое 20756996 ?
Так нигде нет примера, в том числе по ссылке, где читается что-то из OPENFILENAME.

К сожалению, при отладке функций API, Word часто схлопывается на точках останова, хотя код рабочий.
Все-таки склоняюсь к GetDlgItem и SendMessage, вместо CopyMemory
...
Рейтинг: 0 / 0
API: Как в hook-процедуре для GetOpenFileName получить OPENFILENAME?
    #39555319
234522
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Сын вождяБез String неудобно, когда надо получать, а не только отправлять. Как раз мой случай.Со String "за сценой" происходят строковые преобразования, в некоторых случаях совсем лишние. Как по мне, в таких случаях можно написать класс-оболочку для структуры, и пользоваться явным преобразованием:
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
Private Declare Function CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
   Dest As Any, Src As Any, ByVal cb As Long) As Long
Private Declare Function lstrlenW Lib "kernel32" ( _
   ByVal psString As Any) As Long

Public Function LPWSTR2String(ByVal lpWStr As Long) As String
 Dim nStrLen As Long
 If lpWStr Then
    nStrLen = lstrlenW(lpWStr)
    LPWSTR2String = String$(nStrLen, vbNullChar)
    CopyMemory ByVal StrPtr(LPWSTR2String), ByVal lpWStr, nStrLen * 2
 Else
    LPWSTR2String = vbNullString
 End If
End Function

Сын вождяПереход на GetOpenFileNameW (вместо GetOpenFileNameA) поддерживаю,Windows 95 уже кончилась, да. Хотя и там был Unicode layer.Сын вождяхотя он и влечет применение StrConv.Где, зачем (с учётом вышеприведённой процедуры)?Сын вождя234522Не падает, в Locals значения правдоподобные.
Да, разобрался! Благодарю! Понял ошибку с размером.Код
Код: vbnet
1.
2.
3.
         Dim oOFN As OPENFILENAME
         CopyMemory oOFN.lStructSize, ByVal oNotify.lpOFN, LenB(oOFN.lStructSize)
         CopyMemory oOFN, ByVal oNotify.lpOFN, oOFN.lStructSize

как раз-таки быстрый-грязный и совсем не образец для подражания, поскольку теоретически потенциально приводит к buffer overrun. После чтения размера структуры надо выделять либо буфер нужного размера и копировать туда, либо, если мы решили обойтись Dim oOFN As OPENFILENAME, писать в oOFN Минимум(LenB(oOFN), oOFN.lStructSize) байт.Сын вождя234522Может, не мучиться, и взять готовое 20756996 ?
Так нигде нет примера, в том числе по ссылке, где читается что-то из OPENFILENAME.По ссылке есть, в том числе пример (Example_GetFileName).
...
Рейтинг: 0 / 0
API: Как в hook-процедуре для GetOpenFileName получить OPENFILENAME?
    #39555340
Фотография Сын вождя
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
234522Со String "за сценой" происходят строковые преобразования, в некоторых случаях совсем лишние. Как по мне, в таких случаях можно написать класс-оболочку для структуры, и пользоваться явным преобразованием
Если еще и за сценой конвертер стоит, то конечно. Сейчас, для string, везде приходится делать StrConv, как на выходе, так и на входе.

234522
Код: vbnet
1.
2.
3.
Dim oOFN As OPENFILENAME
CopyMemory oOFN.lStructSize, ByVal oNotify.lpOFN, LenB(oOFN.lStructSize)
CopyMemory oOFN, ByVal oNotify.lpOFN, oOFN.lStructSize


как раз-таки быстрый-грязный и совсем не образец для подражания, поскольку теоретически потенциально приводит к buffer overrun. После чтения размера структуры надо выделять либо буфер нужного размера и копировать туда, либо, если мы решили обойтись Dim oOFN As OPENFILENAME, писать в oOFN Минимум(LenB(oOFN), oOFN.lStructSize) байт.
Хм. Значит, между двумя CopyMemory не хватает строки, подгоняющей размер oOFN.
...
Рейтинг: 0 / 0
API: Как в hook-процедуре для GetOpenFileName получить OPENFILENAME?
    #39555393
Фотография Сын вождя
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сын вождя234522как раз-таки быстрый-грязный и совсем не образец для подражания, поскольку теоретически потенциально приводит к buffer overrun. После чтения размера структуры надо выделять либо буфер нужного размера и копировать туда, либо, если мы решили обойтись Dim oOFN As OPENFILENAME, писать в oOFN Минимум(LenB(oOFN), oOFN.lStructSize) байт.
Хм. Значит, между двумя CopyMemory не хватает строки, подгоняющей размер oOFN.
Выше написано что-то не то. Ведь размер структуры не меняется, откуда переполнение? Правильнее будет прервать обработку, если LenB(oOFN) отличается от размера oOFN.lStructSize, считанного здесь CopyMemory oOFN.lStructSize, ByVal oNotify.lpOFN, LenB(oOFN.lStructSize). То есть, когда функция вернула непонятно что. В свете этого, кстати, даже при совпадении размеров не факт что структуры объектов совпадают. Это выходит вообще беда :(

Тему ветки можно свести в вопросу: "Как по указателю на объект, получить объект". Есть какая-то универсальная схема? Как-то можно определить, что структура объекта по указателю, совпадает с объявленной нами? Если в документации по API одно, а функции API возвращают другое, то как работать? Или это я не дочитал? :)
...
Рейтинг: 0 / 0
8 сообщений из 8, страница 1 из 1
Форумы / Microsoft Office [игнор отключен] [закрыт для гостей] / API: Как в hook-процедуре для GetOpenFileName получить OPENFILENAME?
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]