1

Тема: Microsoft Outlook View Control

Коллеги, кто-нибудь работал с этим АктивИксом от Офиса.
Моя цель - получить хотя бы какую-нить инфу, какое сообщение стало активным.

Немного доп. инфы:
У меня этот АктивИкс отлично работает в 1С:Предприятии 7.7, но там он лежит просто на форме. В событии SelectionChange, можно получить объект - письмо, которое  выделено (свойство Selection).
Хотел использовать его в 1С:Предприятии 8.2, но что-то не сростается. На обычной форме он просто не отображается (косяк 1С?).
Решил зайти со стороры Браузера, но тут непонятки со свойством Selection - его, как-будто не существует.

<html>
    <head>
        <script type=""text/javascript"">
            var Obj1C;

            window.onresize = resize;
            window.onload    = resize;

            function resize()
            {
                var Obj = document.getElementById('Outlook');

                Obj.width     = document.body.clientWidth  - 20;
                Obj.height     = document.body.clientHeight - 20;
            }

            function initObject1C(Obj)
            {
                Obj1C = Obj;
            }


        </script>
    </head>
<body>
    <object id=Outlook classid=clsid:261B8CA9-3BAF-4BD0-B0C2-BF04286785C6></object>

    <script FOR=Outlook EVENT=SelectionChange LANGUAGE=JavaScript>
        {
//            alert(document.body.all.Outlook.Selection);
//            alert(1);
            
        }

    </script>

</body>
</html>

2

Re: Microsoft Outlook View Control

Проблему решил, изучая АктивИкс под Идой.

3 (изменено: chessman, 2012-05-11 16:06:20)

Re: Microsoft Outlook View Control

Вдруг кому-то будет полезно.
Причина, по которой активИкс не хочет работать, как надо, заключается в том, что он запрашивает у контейнера, в котором находится, поддержку интерфейса IHTMLDocument2, если он поддерживается, то требует поддержки IObjectModelAccess. Последний не поддерживается, поэтому мы получаем недоступное свойство 'Selection'. (Сам интерфейс IObjectModelAccess поддерживается самим активИксом, не знаю, зачем он требует его поддержки от контейнера....может быть планировалось его же и возвращать, в общем это не суть). Если контейнер не поддерживает IHTMLDocument2, то все ОК - это объясняет, почему свойство 'Selection' заполняется, когда мы размещаем активИкс на обычной 1С-й форме.

Я решил исправить этот досадный для меня косяк, путем перехвата 2-х функций из 2-х интерфейсов.
В 1С-ке все получилось, с IE нет (об этом ниже), но тут я приведу скрипт для HTA (хотя я и не знаю толком, что это за зверь).

Что я сделал: при открытии страницы, запускается скрипт, в котором: вызываем DllGetClassObject из OUTLCTL.DLL, создаем фабрику классов, создаем объект ViewControl'а, запрашиваем у последнего интерфейс IOleObject, перехватываем IOleObject::SetClientSite.
Далее, при инициализации страницы, управление заведомо попадет, в перехваченную функцию, где мы получаем интерфейс IOleClientSite. Запрашиваем у него контейнер, через IOleClientSite::GetContainer и устанавливаем 2-й перехват на IOleContainer::QueryInterface. Именно через последний приходит запрос на поддержку IHTMLDocument2 - мы претворимся, что не поддерживаем этот интерфейс, тогда все заработает. При закрытии страницы, удаляем перехваты.
В следующем посте сам скрипт, если он вдруг не взлетит, то нужно поменять в 2-х местах CLSID для Outlook View Controlа - у меня установлен 2010 офис.

Из доп. требований - DynamicWrapperX

4 (изменено: chessman, 2012-05-11 14:42:59)

Re: Microsoft Outlook View Control

<html>
    <head>
        <script language="vbscript">
            //{Public Const==============================================
            Public Const HEAP_ZERO_MEMORY             = &h00000008
            Public Const PAGE_EXECUTE_READWRITE        = &h40
            Public Const S_OK                       = &h0    
            Public Const E_NOINTERFACE                 = &h80004002
            
            Public Const IID_IUnknown                = "{00000000-0000-0000-C000-000000000046}"
            Public Const IID_IHTMLDocument2         = "{332C4425-26CB-11D0-B483-00C04FD90119}"
            Public Const IID_IOleObject                 = "{00000112-0000-0000-C000-000000000046}"
            
            Public Const CLSID_Outlook                = "{261B8CA9-3BAF-4BD0-B0C2-BF04286785C6}"
            Public Const IID_IClassFactory            = "{00000001-0000-0000-C000-000000000046}"
            Public Const IID_IViewCtl                = "{00067274-0000-0000-C000-000000000046}"
            
            Public Const HKEY_CLASSES_ROOT              = &h80000000
            //}==========================================================
            
            //{Public Vars==============================================    
            Public Wrap
            Set Wrap = CreateObject("DynamicWrapperX")
            
            Public oServ
            
            Public buf
            Public swIID
            Public pCLSID
            Public pIID
            Public ppv
            Public res
            
            Public pIClassFactory
            Public pOleContainer
            Public pIOleObject
            
            Public Addr1
            Public oldAddr1
            Public Addr2
            Public oldAddr2
            
            Public Ref1
            Public Ref2    
            
            //}==========================================================
            
            //{Class Service==============================================    
            Class Service
                Private hHeap
                //Private Ref1
                //Private Ref2    
                
                //{Class_Initialize
                Private Sub Class_Initialize
                    Wrap.Register "Kernel32",    "VirtualProtect" , "i=lllp", "r=l"
                    Wrap.Register "Kernel32",    "GetProcessHeap", "r=l"
                    Wrap.Register "Kernel32",    "HeapAlloc",    "i=lll",    "r=l"
                    Wrap.Register "Kernel32",    "HeapFree", "i=lll","r=l"
                    Wrap.Register "Ole32"   ,     "StringFromGUID2", "i=ppl", "r=l"
                    Wrap.Register "Ole32"   ,     "IIDFromString", "i=pp", "r=l"
                    Wrap.Register "Advapi32",    "RegOpenKey", "i=hsp","r=l"
                    Wrap.Register "Advapi32",    "RegQueryValue", "i=hlpl","r=l"
            
                    hHeap     = Wrap.GetProcessHeap()
                    res        = Wrap.HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 4)
                    swIID    = Wrap.HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 256)
                    pIID    = Wrap.HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 16)
                    pCLSID    = Wrap.HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 16)
                    ppv        = Wrap.HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 4)
            
                    //'Буфер под вызовы
                    buf        = Wrap.HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 5)
                    Wrap.NumPut    &hE9, buf, 0, "b"                    //'jmp ...Addr
            
                    //'IUnknown
                    Wrap.RegisterAddr buf, "IUnknown_QueryInterface", "i=ppp", "r=l"        //'IUnknown::QueryInterface
                    Wrap.RegisterAddr buf, "IUnknown_AddRef", "i=p", "r=l"                    //'IUnknown::AddRef
                    Wrap.RegisterAddr buf, "IUnknown_Release", "i=p", "r=l"                    //'IUnknown::Release
            
                    //'IOleClientSite
                    Wrap.RegisterAddr buf, "IOleClientSite_GetContainer", "i=pp", "r=l"        //'IOleClientSite::GetContainer
            
                    //'IClassFactory
                    Wrap.RegisterAddr buf, "IClassFactory_CreateInstance", "i=pppp", "r=l"    //'IClassFactory::CreateInstance
            
                    //'IOleObject
                    Wrap.RegisterAddr buf, "IOleObject_SetClientSite", "i=pp", "r=l"        //'IOleObject::SetClientSite
            
                    Set Ref1     = GetRef("IUnknown_QueryInterface")
                    Addr1        = Wrap.RegisterCallback(Ref1, "i=ppp", "r=l")
            
                    Set Ref2     = GetRef("IOleObject_SetClientSite")
                    Addr2        = Wrap.RegisterCallback(Ref2, "i=pp", "r=l")
            
                    pOleContainer = 0
                End Sub
                //}                
            
                //{Class_Terminate
                Private Sub Class_Terminate
                    Wrap.HeapFree hHeap, 0, res
                    Wrap.HeapFree hHeap, 0, swIID
                    Wrap.HeapFree hHeap, 0, pCLSID
                    Wrap.HeapFree hHeap, 0, pIID
                    Wrap.HeapFree hHeap, 0, ppv
                    Wrap.HeapFree hHeap, 0, buf
            
                    Set Ref1 = Nothing
                    Set Ref2 = Nothing
                End Sub
                //}
            End Class    
            
            Set oServ = New Service
            //}==========================================================
            
            //vfunc  .........Универсальная, для вызова функций интерфейса..............
            Public Function vfunc(pObj, offset)    
                Addr = Wrap.NumGet(Wrap.NumGet(pObj), offset)    
                Wrap.NumPut    Addr - (buf + 1 + 4),     buf, 1
            End Function
        
            //IUnknown_QueryInterface    
            Public Function IUnknown_QueryInterface(pObj, riid, ppv1)
                //MsgBox "IUnknown_QueryInterface1"
                Wrap.StringFromGUID2 riid, swIID, 256
                sIID = Wrap.StrGet(swIID)    
            
                If sIID = IID_IHTMLDocument2 Then
                    IUnknown_QueryInterface = E_NOINTERFACE
                    Wrap.NumPut 0, ppv1
                Else
                    Wrap.NumPut oldAddr1 - (buf + 1 + 4), buf, 1
                    IUnknown_QueryInterface = Wrap.IUnknown_QueryInterface(pObj, riid, ppv1) 
                End If
                //MsgBox "IUnknown_QueryInterface2"
            End Function
            
            //IOleObject_SetClientSite
            Public Function IOleObject_SetClientSite(pObj, pClientSite)
                //MsgBox "IOleObject_SetClientSite1"
            
                Wrap.NumPut oldAddr2 - (buf + 1 + 4), buf, 1
                IOleObject_SetClientSite = Wrap.IOleObject_SetClientSite(pObj, pClientSite) 
                    
                Wrap.NumPut 0, ppv    
                vfunc pClientSite, (6 - 1) * 4
                q = Wrap.IOleClientSite_GetContainer(pClientSite, ppv)
                
                //'=====================================================
                //'Перехват IOleContainer::QueryInterface
                pOleContainer = Wrap.NumGet(ppv)
                vtable        = Wrap.NumGet(pOleContainer)
                oldAddr1    = Wrap.NumGet(vtable, (1 - 1) * 4)    
                Wrap.VirtualProtect vtable, 4, PAGE_EXECUTE_READWRITE, res
                Wrap.NumPut    Addr1,     vtable, 0
            
                //'=====================================================
                //'Убираем перехват на IOleObject::SetClientSite
                //vtable        = Wrap.NumGet(pIOleObject)
                //Wrap.NumPut    oldAddr2,     vtable, &h0C
                //Wrap.VirtualProtect vtable + &h0C, 4, Wrap.NumGet(res), res
            
                //MsgBox "IOleObject_SetClientSite2"
            End Function
            //
            
            //Hook
            Public Function Hook()
                sKey     = "CLSID\" & CLSID_Outlook & "\InprocServer32"
                r         = Wrap.RegOpenKey(HKEY_CLASSES_ROOT, sKey, ppv)    
                hk         = Wrap.NumGet(ppv)
            
                Wrap.NumPut 256, ppv
                r          = Wrap.RegQueryValue(hk, 0, swIID, ppv)
                fullPath =  Wrap.StrGet(swIID, "s")
            
                //MsgBox fullPath
            
                r = Wrap.Register(fullPath,     "DllGetClassObject" , "i=ppp", "r=l")
            
                //'=====================================================
                //'Создаем фабрику-классов
                Wrap.NumPut 0, ppv    
                Wrap.IIDFromString CLSID_Outlook, pCLSID
                Wrap.IIDFromString IID_IClassFactory, pIID
                q = Wrap.DllGetClassObject(pCLSID, pIID, ppv)
            
                //'=====================================================
                //'Создаем объект IViewCtl
                pIClassFactory = Wrap.NumGet(ppv)
                Wrap.NumPut 0, ppv    
                Wrap.IIDFromString IID_IViewCtl, pIID
                vfunc pIClassFactory, &h0C    
                q = Wrap.IClassFactory_CreateInstance(pIClassFactory, 0, pIID, ppv)
            
                //'=====================================================
                //'Запрашиваем интерфейс IOleObject    
                pIViewCtl = Wrap.NumGet(ppv)
                Wrap.NumPut 0, ppv    
                Wrap.IIDFromString IID_IOleObject, pIID
                vfunc pIViewCtl, (1 - 1 ) * 4
                q = Wrap.IUnknown_QueryInterface(pIViewCtl, pIID, ppv)
            
                //'=====================================================
                //'Перехватываем IOleObject::SetClientSite
                pIOleObject = Wrap.NumGet(ppv)
                vtable        = Wrap.NumGet(pIOleObject)
                oldAddr2    = Wrap.NumGet(vtable, (4 - 1) * 4)    
                Wrap.VirtualProtect vtable + &h0C, 4, PAGE_EXECUTE_READWRITE, res
                Wrap.NumPut    Addr2,     vtable, &h0C
            End Function

            //DelHook
            Public Function DelHook()
                MsgBox "DelHook"
                //'Убираем перехват на IOleObject::SetClientSite
                vtable        = Wrap.NumGet(pIOleObject)
                Wrap.NumPut    oldAddr2,     vtable, &h0C
                Wrap.VirtualProtect vtable + &h0C, 4, Wrap.NumGet(res), res
                
                //'Снимаем перехват    
                If pOleContainer <> 0 Then
                    vtable        = Wrap.NumGet(pOleContainer)
                    Wrap.NumPut    oldAddr1,     vtable, 0
                    Wrap.VirtualProtect vtable, 4, Wrap.NumGet(res), res
                End If
            
                vfunc pIClassFactory, (3 - 1) * 4
                q = Wrap.IUnknown_Release(pIClassFactory)
            
                Set oServ     = Nothing
                Set Wrap     = Nothing
            End Function
            
            Hook()
            
            Function Window_Onresize()    
                Set Obj = document.getElementById("Outlook")

                Obj.width     = document.body.clientWidth  - 20
                Obj.height     = document.body.clientHeight - 20
            End Function    
                
            Function Window_Onload()
                //MsgBox "Window_Onload"
                Window_Onresize()    
            End Function
                
            Function Window_OnUnload()
                //MsgBox "Window_OnUnload"
                DelHook()
            End Function
        </script>
    </head>
<body>
    <object id=Outlook classid=clsid:261B8CA9-3BAF-4BD0-B0C2-BF04286785C6></object>

    <script FOR=Outlook EVENT=SelectionChange language=vbscript>
        Set Selection = Outlook.Selection
        If Selection.Count() >0 Then
            Set mes   = Selection.Item(1)
            MsgBox mes.EntryID
        End If
    </script>

</body>
</html>

5

Re: Microsoft Outlook View Control

chessman, поскольку желающие высказаться — [не]высказались, в соответствии с:

Вдруг кому-то будет полезно.

прошу Вас добавить, что сочтёте нужным, в Коллекцию.

6

Re: Microsoft Outlook View Control

alexii, а мне в Коллекции нужно новую тему создать или как-то ветку перетащить?

7

Re: Microsoft Outlook View Control

Новую тему.

8 (изменено: chessman, 2012-05-14 17:58:39)

Re: Microsoft Outlook View Control

Сегодня удалось запустить и под IE. Завтра попробую опубликовать изыскания. Вкратце так - IE создает 2 нити, поэтому простой перехват, как это сделано с HTA не работает.
Сначала, я не мог понять, почему не работает вызов перехваченных ф-й из скрипта, стал смотреть внутрь DWX, оказалось при вызове диспетчерского интерфейса VBS, в DWX прилетает ошибка RPC_E_WRONG_THREAD. Пытался пробраться отладкой через дебри ole32-нереально. Зашел со стороны msdn, оказалось, что активИкс и скрипт работают в разных нитях, поэтому и получаем соответствующую ошибку.

В итоге, кроме самого перехвата, добавились еше вызовы CoMarshalInterThreadInterfaceInStream/CoGetInterfaceAndReleaseStream + бинарные правки налету самого DWX.
Но, завелось!

9 (изменено: chessman, 2012-05-16 11:34:07)

Re: Microsoft Outlook View Control

Код для IE в следующем посте.

С какими особенностями столкнулся?
1. Как я уже написал выше, для успешного перехвата на скрипт, объекты скрипта необходимо завернуть  с помощью CoMarshalInterThreadInterfaceInStream.
2. Вызов IOleClientSite::GetContainer внутри перехваченной IOleObject::SetClientSite, возвращает E_UNEXPECTED. Причина - в IOleClientSite::GetContainer проверяются ID нитей и если они не совпадают(а это так, если вызывать через скрипт), то получаем ошибку. Поэтому, пришлось подготавливать участок кода, и устанавливать перехват на него и в этом коде вызывать IOleClientSite::GetContainer.
3. После получения контейнера, передаем управление DWX, но для того, что бы он смог вызвать CallBack-ф-и из скрипта, нужно поменять параметры для него, а именно Dispatch интерфейсы объектов vbs-скрипта (в скрипте они получаются через GetRef).  Для этого, мы перехватываем функцию из DWX(я ее назвал main) и до ее выполнения, развернем в этой нити, с помощью CoGetInterfaceAndReleaseStream "правильные" интерфейсы. После этого перехват работает, как обычно.

В самом тексте скрипта, я добавил комментарии, надеюсь, они помогут, если кто-то захочет разобряться.
Возможно, предложенный вариант не оптимален, но он работает.
Еще раз напомню, про CLSID для Outlook View Controlа - в примере используется CLSID от 2010 офиса. (Если у вас другой, то поменять нужно в 2х местах).

10

Re: Microsoft Outlook View Control

<html>
    <head>
        <script language="vbscript">
            //{Public Const==============================================
            Public Const HEAP_ZERO_MEMORY             = &h00000008
            Public Const PAGE_EXECUTE_READWRITE        = &h40
            Public Const S_OK                               = &h0    
            Public Const E_NOINTERFACE                         = &h80004002
            
            Public Const IID_IUnknown                = "{00000000-0000-0000-C000-000000000046}"
            Public Const IID_IHTMLDocument2            = "{332C4425-26CB-11D0-B483-00C04FD90119}"
            Public Const IID_IOleObject                 = "{00000112-0000-0000-C000-000000000046}"
            
            Public Const CLSID_Outlook                = "{261B8CA9-3BAF-4BD0-B0C2-BF04286785C6}"
            Public Const IID_IClassFactory            = "{00000001-0000-0000-C000-000000000046}"
            Public Const IID_IViewCtl                = "{00067274-0000-0000-C000-000000000046}"
            Public Const IID_IDispatch                = "{00020400-0000-0000-C000-000000000046}"
            
            Public Const HKEY_CLASSES_ROOT              = &h80000000
            //}==========================================================
            
            //{Public Vars==============================================    
            Public Wrap
            Set Wrap = CreateObject("DynamicWrapperX")
            
            Public oServ
            
            Public buf
            Public swIID
            Public pCLSID
            Public pIID
            Public ppv
            Public ppOle
            Public res
            
            Public pIClassFactory
            Public pOleContainer
            Public pIOleObject
            
            Public Addr1
            Public oldAddr1
            Public Addr2
            Public oldAddr2
            Public Addr3
            //}==========================================================
            
            //{Class Service==============================================    
            Class Service
                Private hHeap
                Private Ref1
                Private Ref2    
                
                Private dbuf
                Private pIID_Disp
                Private AddrCoGet
                
                //{Class_Initialize
                Private Sub Class_Initialize
                    Wrap.Register "Kernel32",    "VirtualProtect" , "i=lllp", "r=l"
                    Wrap.Register "Kernel32",    "GetProcessHeap", "r=l"
                    Wrap.Register "Kernel32",    "HeapAlloc",    "i=lll",    "r=l"
                    Wrap.Register "Kernel32",    "HeapFree", "i=lll","r=l"
                    Wrap.Register "Advapi32",    "RegOpenKey", "i=hsp","r=l"
                    Wrap.Register "Advapi32",    "RegQueryValue", "i=hlpl","r=l"
                    Wrap.Register "Ole32"   ,     "StringFromGUID2", "i=ppl", "r=l"
                    Wrap.Register "Ole32"   ,     "IIDFromString", "i=pp", "r=l"
                    Wrap.Register "Ole32"   ,     "CoMarshalInterThreadInterfaceInStream", "i=ppp", "r=l"
                    AddrCoGet = Wrap.Register("Ole32"   ,     "CoGetInterfaceAndReleaseStream", "i=ppp", "r=l")
                    AddrCoGet = Wrap.NumGet(AddrCoGet, &h14)    //адрес ф-ии CoGetInterfaceAndReleaseStream
            
                    hHeap     = Wrap.GetProcessHeap()
                    res        = Wrap.HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 4)
                    swIID    = Wrap.HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 256)
                    pIID    = Wrap.HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 16)
                    pCLSID    = Wrap.HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 16)
                    ppv        = Wrap.HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 4)
                    ppOle    = Wrap.HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 4)
                    
                    dbuf    = Wrap.HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 100)
                    Wrap.VirtualProtect dbuf, 100, PAGE_EXECUTE_READWRITE, res
                    
                    pIID_Disp    = Wrap.HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 16)
                    
                    //'Буфер под вызовы
                    buf        = Wrap.HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 5)
                    Wrap.NumPut    &hE9, buf, 0, "b"                    //'jmp ...Addr
            
                    //'IUnknown
                    Wrap.RegisterAddr buf, "IUnknown_QueryInterface", "i=ppp", "r=l"        //'IUnknown::QueryInterface
                    Wrap.RegisterAddr buf, "IUnknown_AddRef", "i=p", "r=l"                    //'IUnknown::AddRef
                    Wrap.RegisterAddr buf, "IUnknown_Release", "i=p", "r=l"                    //'IUnknown::Release
            
                    //'IOleClientSite
                    Wrap.RegisterAddr buf, "IOleClientSite_GetContainer", "i=pp", "r=l"        //'IOleClientSite::GetContainer
            
                    //'IClassFactory
                    Wrap.RegisterAddr buf, "IClassFactory_CreateInstance", "i=pppp", "r=l"    //'IClassFactory::CreateInstance
            
                    //'IOleObject
                    Wrap.RegisterAddr buf, "IOleObject_SetClientSite", "i=pp", "r=l"        //'IOleObject::SetClientSite
            
                    Set Ref1     = GetRef("IUnknown_QueryInterface")
                    Addr1        = Wrap.RegisterCallback(Ref1, "i=ppp", "r=l")
                    
                    Set Ref2     = GetRef("IOleObject_SetClientSite")
                    Addr2        = Wrap.RegisterCallback(Ref2, "i=pp", "r=l")
                    
                    //    Адреса параметров у вспомогательных ф-й DWX                    
                    params1    = Wrap.NumGet(Addr1, 4)
                    params2    = Wrap.NumGet(Addr2, 4)
                    
                    // Адреса IDispatch объектов VBS, через которые вызываются ф-и скрипта 
                    pRef1    = Wrap.NumGet(params1, 0)
                    pRef2    = Wrap.NumGet(params2, 0)
                    
                    Wrap.IIDFromString IID_IDispatch, pIID_Disp
                    
                    // Заворачиваем для передачи в другую нить
                    Wrap.CoMarshalInterThreadInterfaceInStream pIID_Disp, pRef1, ppv
                    pStm1 = Wrap.NumGet(ppv)
                    
                    Wrap.CoMarshalInterThreadInterfaceInStream pIID_Disp, pRef2, ppv
                    pStm2 = Wrap.NumGet(ppv)
                    
                    //    main - я так назвал ф-ю из DWX, через которую проходят Callback-вызовы 
                    Offset         = Wrap.NumGet(Addr2, 8 + 1)        // относительный адрес ф-и 'main'
                    AddrMain     = Addr2 + 8 + 5 + Offset        // абсолютный    адрес ф-и 'main'
                    
                    
                    //========================================================
                    // Этот код будет вызван вместо IOleObject::SetClientSite
                    // Сначала получим контейнер IOleClientSite::GetContainer.
                    // Далее передадим управление CallBack-функции из скрипта.
                    // Почему в скрипте не вызвать IOleClientSite::GetContainer? - 
                    // Через скрипт мы контейнер не получим,
                    // т.к. в IOleClientSite::GetContainer сравниваются id нитей
                    // и если они не равны, возвращается E_UNEXPECTED
                    
                    Wrap.NumPut &h0824448b, dbuf, 0                        // mov eax, [esp+08]    pClientSite
                    Wrap.NumPut &h68,         dbuf, 4, "b"                // push ppOle            сюда должен прилететь IOleContainer
                    Wrap.NumPut ppOle,         dbuf, 5
                    Wrap.NumPut &h50,         dbuf, 9, "b"                // push eax            указатель на объект IOleClientSite
                    Wrap.NumPut &h008b,     dbuf, 10, "n"                // mov eax, [eax]        vtable IOleClientSite
                    Wrap.NumPut &h0408b,     dbuf, 12, "n"                // mov eax, [eax+14]    адрес IOleClientSite::GetContainer
                    Wrap.NumPut &h14,         dbuf, 14, "b"
                    Wrap.NumPut &hD0FF,     dbuf, 15, "n"                // call [eax]            IOleClientSite::GetContainer
                    Wrap.NumPut &hE9,         dbuf, 17, "b"                // jmp Addr2              адрес вспом. ф-и, для вызова IOleObject::SetClientSite
                    Wrap.NumPut (Addr2 - (dbuf + 17 + 5)),     dbuf, 18
                    
                    Addr3 = dbuf
                    //========================================================
                    
                    // Перед вызовом вспомогательной ф-и DWX, которая в свою очередь вызывает 
                    // ф-и VBS, вставим код, который развернет объекты VBS в другой нити.
                    // Подготавливаем код для перехвата (программируем в кодах)
                    // этот участок кода будет вызван 1 раз в другой нити,
                    // в нем разворачиваются дисп-интерфейсы VBS и заменяются в Callback-функциях.
                    //========================================================
                    preCode 22,         pStm1, params1
                    preCode 22 + 30,     pStm2, params2
                    
                    //    вот мы подменяем вызов на участок нового кода 
                    Wrap.NumPut (dbuf + 22) - (Addr2 + 8 + 5), Addr2, 8 + 1 
                    
                    // возвращаем управление ф-и main
                    // при этом, объекты VBS уже изменены
                    Wrap.NumPut &hE9,     dbuf, 82, "b"                    // jmp main
                    Wrap.NumPut (AddrMain - (dbuf + 82 + 5)),     dbuf, 83
                    //========================================================
                    
                    pOleContainer = 0
                End Sub
                //}                
            
                //Prepare code
                Private Function preCode(offset, pStm, params)
                    // это вызов CoGetInterfaceAndReleaseStream
                    // результат помещаем в params
                    Wrap.NumPut &h68,         dbuf, offset, "b"                                //    push ppv
                    Wrap.NumPut ppv,         dbuf, offset + 1
                    Wrap.NumPut &h68,         dbuf, offset + 5, "b"                            //    push IID_Dispatch
                    Wrap.NumPut pIID_Disp,    dbuf, offset + 6
                    Wrap.NumPut &h68,         dbuf, offset + 10, "b"                            //    push pStm
                    Wrap.NumPut pStm,         dbuf, offset + 11                                
                    Wrap.NumPut &hE8,         dbuf, offset + 15, "b"                            //    call CoGetInterfaceAndReleaseStream
                    Wrap.NumPut (AddrCoGet - (dbuf + offset + 20)),     dbuf, offset + 16
                    Wrap.NumPut &hA1,         dbuf, offset + 20, "b"                            // mov eax, [ppv]
                    Wrap.NumPut ppv,         dbuf, offset + 21
                    Wrap.NumPut &hA3,         dbuf, offset + 25, "b"                            // mov [params], eax
                    Wrap.NumPut params,     dbuf, offset + 26            
                End Function     
                
                //{Class_Terminate
                Private Sub Class_Terminate
                    Wrap.HeapFree hHeap, 0, res
                    Wrap.HeapFree hHeap, 0, swIID
                    Wrap.HeapFree hHeap, 0, pCLSID
                    Wrap.HeapFree hHeap, 0, pIID
                    Wrap.HeapFree hHeap, 0, ppv
                    Wrap.HeapFree hHeap, 0, ppOle
                    Wrap.HeapFree hHeap, 0, buf
                    Wrap.HeapFree hHeap, 0, dbuf
                    Wrap.HeapFree hHeap, 0, pIID_Disp
                    
                    Set Ref1 = Nothing
                    Set Ref2 = Nothing
                End Sub
                //}
            End Class    
            
            Set oServ = New Service
            //}==========================================================
            
            //vfunc  .........Универсальная, для вызова функций интерфейса..............
            Public Function vfunc(pObj, offset)    
                Addr = Wrap.NumGet(Wrap.NumGet(pObj), offset)    
                Wrap.NumPut    Addr - (buf + 1 + 4),     buf, 1
            End Function
        
            //IUnknown_QueryInterface    
            Public Function IUnknown_QueryInterface(pObj, riid, ppv1)
                Wrap.StringFromGUID2 riid, swIID, 256
                sIID = Wrap.StrGet(swIID)    
            
                If sIID = IID_IHTMLDocument2 Then
                    IUnknown_QueryInterface = E_NOINTERFACE
                    Wrap.NumPut 0, ppv1
                Else
                    Wrap.NumPut oldAddr1 - (buf + 1 + 4), buf, 1
                    IUnknown_QueryInterface = Wrap.IUnknown_QueryInterface(pObj, riid, ppv1) 
                End If
            End Function
            
            //IOleObject_SetClientSite
            Public Function IOleObject_SetClientSite(pObj, pClientSite)
                Wrap.NumPut oldAddr2 - (buf + 1 + 4), buf, 1
                IOleObject_SetClientSite = Wrap.IOleObject_SetClientSite(pObj, pClientSite) 
                
                //'=====================================================
                //'Перехват IOleContainer::QueryInterface
                pOleContainer     = Wrap.NumGet(ppOle)
                vtable            = Wrap.NumGet(pOleContainer)
                oldAddr1        = Wrap.NumGet(vtable, (1 - 1) * 4)    
                Wrap.VirtualProtect vtable, 4, PAGE_EXECUTE_READWRITE, res
                Wrap.NumPut    Addr1,     vtable, 0
            End Function
            //
            
            //Hook
            Public Function Hook()
                sKey     = "CLSID\" & CLSID_Outlook & "\InprocServer32"
                r         = Wrap.RegOpenKey(HKEY_CLASSES_ROOT, sKey, ppv)    
                hk         = Wrap.NumGet(ppv)
            
                Wrap.NumPut 256, ppv
                r          = Wrap.RegQueryValue(hk, 0, swIID, ppv)
                fullPath =  Wrap.StrGet(swIID, "s")
            
                //MsgBox fullPath
            
                r = Wrap.Register(fullPath,     "DllGetClassObject" , "i=ppp", "r=l")
            
                //'=====================================================
                //'Создаем фабрику-классов
                Wrap.NumPut 0, ppv    
                Wrap.IIDFromString CLSID_Outlook, pCLSID
                Wrap.IIDFromString IID_IClassFactory, pIID
                q = Wrap.DllGetClassObject(pCLSID, pIID, ppv)
            
                //'=====================================================
                //'Создаем объект IViewCtl
                pIClassFactory = Wrap.NumGet(ppv)
                Wrap.NumPut 0, ppv    
                Wrap.IIDFromString IID_IViewCtl, pIID
                vfunc pIClassFactory, &h0C    
                q = Wrap.IClassFactory_CreateInstance(pIClassFactory, 0, pIID, ppv)
            
                //'=====================================================
                //'Запрашиваем интерфейс IOleObject    
                pIViewCtl = Wrap.NumGet(ppv)
                Wrap.NumPut 0, ppv    
                Wrap.IIDFromString IID_IOleObject, pIID
                vfunc pIViewCtl, (1 - 1 ) * 4
                q = Wrap.IUnknown_QueryInterface(pIViewCtl, pIID, ppv)
            
                //'=====================================================
                //'Перехватываем IOleObject::SetClientSite
                pIOleObject = Wrap.NumGet(ppv)
                vtable        = Wrap.NumGet(pIOleObject)
                oldAddr2    = Wrap.NumGet(vtable, (4 - 1) * 4)    
                Wrap.VirtualProtect vtable + &h0C, 4, PAGE_EXECUTE_READWRITE, res
                Wrap.NumPut    Addr3,     vtable, &h0C
            End Function

            //DelHook
            Public Function DelHook()
                //'Убираем перехват на IOleObject::SetClientSite
                vtable        = Wrap.NumGet(pIOleObject)
                Wrap.NumPut    oldAddr2,     vtable, &h0C
                Wrap.VirtualProtect vtable + &h0C, 4, Wrap.NumGet(res), res
                
                //'Снимаем перехват    
                If pOleContainer <> 0 Then
                    vtable        = Wrap.NumGet(pOleContainer)
                    Wrap.NumPut    oldAddr1,     vtable, 0
                    Wrap.VirtualProtect vtable, 4, Wrap.NumGet(res), res
                End If
            
                vfunc pIClassFactory, (3 - 1) * 4
                q = Wrap.IUnknown_Release(pIClassFactory)
            
                Set oServ     = Nothing
                Set Wrap     = Nothing
            End Function
            
            Hook()
            
            Function Window_Onresize()    
                Set Obj = document.getElementById("Outlook")

                Obj.width     = document.body.clientWidth  - 20
                Obj.height     = document.body.clientHeight - 20
            End Function    
                
            Function Window_Onload()
                //MsgBox "Window_Onload"
                Window_Onresize()    
            End Function
                
            Function Window_OnUnload()
                //MsgBox "Window_OnUnload"
                DelHook()
            End Function
        </script>
    </head>
<body>
    <object id=Outlook classid=clsid:261B8CA9-3BAF-4BD0-B0C2-BF04286785C6></object>

    <script FOR=Outlook EVENT=SelectionChange language=vbscript>
        Set Selection = Outlook.Selection
        If Selection.Count() >0 Then
            Set mes   = Selection.Item(1)
            MsgBox mes.EntryID
        End If
    </script>

</body>
</html>

11 (изменено: chessman, 2012-05-16 22:07:40)

Re: Microsoft Outlook View Control

Наверное нужно еще указать, что я тестировал примеры под Win7.

Под XP SP3, обнаружилось, что для IE тут подходит 1-й пример (для HTA), т.к. IE выполняет код в одном процессе. Но тоже есть особенность, нужно переменную sIID сделать публичной, иначе происходит критическая ошибка вот тут

sIID = Wrap.StrGet(swIID)

Видимо, что-то с деструктором строк не так. Вообще это не существенно, можно было просто тупо проверять 16 байт IID, без вызова StringFromGUID2 и дальнейшей сверки строк.
Ну, в общем на XP тоже работает.

12

Re: Microsoft Outlook View Control

оно существует, но мешает старый патч (разрешения)

<html>
    <head>
        <script type='text/javascript'>
window.onload=function(e)
{
function Outlook::SelectionChange(x)
{
alert(document.getElementById('Outlook').object.Selection);
}
}
        </script>
    </head>
<body>
<!--object id=Outlook classid=clsid:261B8CA9-3BAF-4BD0-B0C2-BF04286785C6></object-->
<object id=Outlook classid=clsid:0006F063-0000-0000-C000-000000000046>
<PARAM NAME="Folder" VALUE="Inbox">
</object>
</body>
</html>

Я конечно далек от мысли... (с)

13

Re: Microsoft Outlook View Control

Так а что конкретно нужно сделать, т.к. вышеприведенный код не работает.

14

Re: Microsoft Outlook View Control

ничего, код работает, разрешений нет прямых ни у кого

<html>
    <head>
        <script type='text/javascript'>
window.onload = function(e)
{
var x = document.createElement('object');
x.classid = 'clsid:{261B8CA9-3BAF-4BD0-B0C2-BF04286785C6}';
document.getElementById('Outlook').classid = x.object ? x.classid : 'clsid:{0006F063-0000-0000-C000-000000000046}';
x = function()
{
function Outlook::SelectionChange()
{
if(e) return;
try { alert(document.getElementById('Outlook').object.Selection) } catch(e) { alert(e.description) };
}
};
x();
}
        </script>
    </head>
<body>
<object id='Outlook'>
</object>
</body>
</html>

Я конечно далек от мысли... (с)

15

Re: Microsoft Outlook View Control

В Win7 пишет "Разрешение отклонено".

16

Re: Microsoft Outlook View Control

о чем и речь - патч года 2002 на сколько помню, позволяет работать с содержимым, только если контрол домашняя страница папки оутлука (т.е. только в самом оутлуке)

Я конечно далек от мысли... (с)

17

Re: Microsoft Outlook View Control

Т.е. реально, без "доработки" не взлетит?

18

Re: Microsoft Outlook View Control

не знаю, наверное только по подобному пути, что и Вы писали
хотя как знать, можно запускать и сам оутлук с указанием нужного скрипта - тогда все ограничения легко обходятся

Я конечно далек от мысли... (с)

19 (изменено: max7, 2012-06-18 13:13:27)

Re: Microsoft Outlook View Control

Нашел на просторах интернета: Outlook Redemption http://www.dimastr.com/redemption/home.htm - очень мощная штука (платная). Главное преимущество: игнорирует ограничения "безопасности" outlook'а, так как работает с "нативными" интерфейсами, а не с объектной моделью outlook'а.

20

Re: Microsoft Outlook View Control

Я этот активИкс давно использую, как он в данной ситуации поможет?

21

Re: Microsoft Outlook View Control

2:max7

OFF:я посмотрел ваши вопросы в теме обсуждения DynamicWrapperX, то, что касается Thread'ов - хочу попытаться запустить DWX,  используя идеи с маршалингом интерфейсов, может срастется.

22

Re: Microsoft Outlook View Control

chessman пишет:

2:max7

OFF:я посмотрел ваши вопросы в теме обсуждения DynamicWrapperX, то, что касается Thread'ов - хочу попытаться запустить DWX,  используя идеи с маршалингом интерфейсов, может срастется.

Отвечаю сам себе-причина, почему не получается вызвать функцию скрипта из созданоого Thread'а-использование движком Vbs ф-и TlsGetValue.

23

Re: Microsoft Outlook View Control

chessman, так что насчёт Коллекции, есть что добавлять?

24

Re: Microsoft Outlook View Control

alexii, в течение недели оформлю в Коллекцию.
Было бы конечно интересно услышать мнения других: завелось/не завелось.

25

Re: Microsoft Outlook View Control

chessman пишет:

Отвечаю сам себе...

Продолжайте... мы следим.

P.S.: Ну так, нужно пропатчить это дело?!

26

Re: Microsoft Outlook View Control

alexii, я опубликовал в Коллекции, можно снимать выделение с темы.

27

Re: Microsoft Outlook View Control

chessman. Немного переделал скрипт.


Option Explicit
Const formWidth = 800
Const formHeight = 400
Dim ExitDo, content, features, window, document, UserForm, Control, OVCtl
'Проверяем что наш скрипт запущен в 32-битном интерпретаторе
RunIn32BitMode
'Создаём окно HTA с HTML содержимым
content =   "<html>" & _
                "<body scroll=no style=""margin:0;"">" &_
                "<table width=100% height=100% cellpadding=2 cellspacing=0>" &_
                    "<tr><td height=100%><object id=UserForm style=""width:100%;height:100%;"" classid=""clsid:C62A69F0-16DC-11CE-9E98-00AA00574A4F""></object></td>" &_
                    "<tr><td><button id=btnSelect style=""width:100%;"">Подтвердить выбор</button></td></tr>" &_
                "</table>" &_
                "</body>" &_
            "</html>"
'Устанавливаем оформление окна            
features = "border=dialog maximizeButton=no minimizeButton=no scroll=no contextMenu=no"
'Получаем ссылку на объект окна
Set window = CreateWindow(content,features)
'Растягиваем окно на экране
window.resizeTo formWidth, formHeight
'Получаем ссылку на внутренний документ
Set document = window.document
'Получаем ссылку на форму внутри документа
Set UserForm = window.UserForm
'Добавляем на форму нужный нам контрол
Set Control = UserForm.Controls.Add("OVCtl.OVCtl", "OVCtl", True)
'Растягиваем контрол на размер формы
Control.width = UserForm.insideWidth
Control.height = UserForm.insideHeight
'Позиционируем наше окно на экране
window.moveTo (window.screen.width - formWidth) / 2, (window.screen.height - formHeight) / 2
'Получаем ссылку на объеки контрола
Set OVCtl = Control.Object
'Подключаем событие нажатие на кнопку выбора
window.btnSelect.onclick = getRef("btnSelect_onclick")
'Подключаем событие выгрузки окна к нужной нам процедуре
Set document.body.onbeforeunload = getRef("document_onbeforeunload")
'Вставляем цикл ожидания завершения работы с формой
Do While Not ExitDo
    WScript.Sleep 100
Loop

'Обработчик события выгрузки формы
Sub document_onbeforeunload()
    'Выставляем флаг завершения работы скрипта
    ExitDo = True
End Sub

Sub btnSelect_onclick()
    Dim i, tmp
    'Получаем содержимое выделения
    if OVCtl.Selection.Count > 0 Then
        For i=1 to OVCtl.Selection.Count
            tmp = tmp & OVCtl.Selection(i) & "; "
        Next
    End if
    MsgBox "Выбраны пункты: " & tmp, vbInformation
End Sub

MsgBox "Скрипт завершил выполнение", vbInformation

'Функция создания HTA окна. Возвращает ссылку на объект window внутри HTA
Function CreateWindow(content,features)
    Dim sws, sw, we, wid, i, swid, doc
    Set sws = CreateObject("Shell.Application").Windows
    Randomize: wid = Clng(Rnd*100000)
    Set we = CreateObject("WScript.Shell").Exec("mshta about:""" & _
    "<script>moveTo(-1000,-1000);resizeTo(0,0);</script>" & _
    "<hta:application id=app " & features & " />" & _
    "<object id=" & wid & " style='display:none' classid='clsid:8856F961-340A-11D0-A96B-00C04FD705A2'>" & _
    "<param name=RegisterAsBrowser value=1>" & _
    "</object>""")
    For i=1 to 1000
        For Each sw in sws
            On Error Resume Next
            swid = Clng(sw.id)
            On Error Goto 0
            if wid = swid Then
                Set doc = sw.container
                doc.write content
                doc.title = "Form1"
                Set CreateWindow = doc.parentWindow
                Exit Function
            End if
        Next
    Next
    Err.Raise vbObjectError, "CreateWindow", "Window not found."
End Function

Sub RunIn32BitMode
    With CreateObject("WScript.Shell")
        If InStr(1,.ExpandEnvironmentStrings("%PROCESSOR_ARCHITECTURE%"),64) > 0 Then
            If InStr(1,WScript.FullName,"SysWOW64",1) <=0 Then
                .Run .ExpandEnvironmentStrings("%windir%\SysWOW64\wscript.exe """ & WScript.ScriptFullName & """")
                WScript.Quit
            End if
        End if
    End With
End Sub

Post's attachments

sample.vbs 3.75 kb, 6 downloads since 2013-03-14 

You don't have the permssions to download the attachments of this post.
Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

28

Re: Microsoft Outlook View Control

Да, работает, прикольно.
Если бы это можно было бы положить на форму в 1С, тогда это выход.

29

Re: Microsoft Outlook View Control

А разве что то мешает ? Я бы потестил, но на компе нет 1С-ки.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

30

Re: Microsoft Outlook View Control

Xameleon пишет:

А разве что то мешает ? Я бы потестил, но на компе нет 1С-ки.

Я могу потестить, если расскажите, как положить это на форму.

31

Re: Microsoft Outlook View Control

Проблемка в том, что у меня слишком малый опыт работы с 1С и формами пока что ещё не пользовался, поэтому мне для начала надо ещё самому разобраться как это делать. ) Но предполагаю, что можно начать с добавления на форму Forms.Form.1, а на неё добавить OVCtl.OVCtl, как и у меня в коде


'Добавляем на форму нужный нам контрол
Set Control = UserForm.Controls.Add("OVCtl.OVCtl", "OVCtl", True)

Благодаря этой подложке я и получил возможность обращаться к свойству Selection у объекта OVCtl
Хотя возможно в 1C всё это не требуется и всё решается гораздо проще. ) Если же нет, то наверное можно обойтись и генерацией HTA формы ? Или же Ваша задача требует именно формы 1C ?

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

32 (изменено: chessman, 2013-03-14 11:57:56)

Re: Microsoft Outlook View Control

Саму задачу для 1С я уже решил,  как описал выше.

Ваш вариант тоже интересен, поскольку юзает штатные возможности. Но, вот как его прикрутить к 1С-й форме - я не знаю (пока ). Открытие отдельно от 1С еще какого-то стороннего окна и запуск доп. процесса не есть гуд.
Если будет время, я посмотрю что можно сделать в этом направлении.
В любом случае - спасибо за идею и пример.

33

Re: Microsoft Outlook View Control

chessman пишет:

Саму задачу для 1С я уже решил,  как описал выше.

Ааа. ) Ну тогда лучше не трогать, то что работает. Золотое правило.

В любом случае - спасибо за идею и пример.

Не за что. Рад был помочь. )

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

34

Re: Microsoft Outlook View Control

Попробовал в 1С разместить на форме Forms.Frame и на него положил ViewControl.
Все нормально работает, контрол отображается, свойства писем читаются.
Остается теперь как-то прокинуть события от ViewControl в 1С. Наверное, если это скормить 1С-му браузеру, то там наверное можно сделать подписку на них.

Xameleon, еще раз спс за идею!

35

Re: Microsoft Outlook View Control

Отлично ! ) Хотел уточнить, а для каких целей и какие события необходимо ловить у ViewControl ? Может и с этим смогу помочь ?

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

36

Re: Microsoft Outlook View Control

Xameleon пишет:

Отлично ! ) Хотел уточнить, а для каких целей и какие события необходимо ловить у ViewControl ? Может и с этим смогу помочь ?

Вот это "SelectionChange". Смысл такой - встали на сообщение, отработало событие, получили детали сообщения, в отдельном списке показали приаттаченные файлы. Эти файл(ы) потом  отметили и загрузили в базу.

37

Re: Microsoft Outlook View Control

Выбор производит пользователь ? Вариант с кнопкой подтверждения не подходит ?

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

38

Re: Microsoft Outlook View Control

Xameleon пишет:

Выбор производит пользователь ? Вариант с кнопкой подтверждения не подходит ?

Да, пользователь. "С кнопкой" не пойдет, поскольку народ уже привык без нее, да и это не совсем айс, при наличии события.

39

Re: Microsoft Outlook View Control

Ясно. ) А множественный выбор как при этом надо обработать (При выборе через CTLR / SHIFT) ? Там при каждом щелчке событие же срабатывает ? Элементы выбора при этом будут повторно обрабатываться ?

Добавлено в 18:26

Предполагаю, что придётся тогда несколько изменить идеологию. Сначала добавить на форму 1C объект WebBrowser. Он же Shell.Explorer (Объект Internet Explorer при этом не создаётся, что приятно), далее выполнить Navigate на заранее созданную страницу в Outlook Home Directory. Внутри страницы создать объект OVctl и обработчик события. Тогда дальше уже можно будет легко зацепить его к внешним обработчикам. Пока что это теория, но попробую реализовать.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

40

Re: Microsoft Outlook View Control

Ну, там методом Count() можно посмотреть, сколько выделено и обработать Item(1).

41

Re: Microsoft Outlook View Control

Понял. Не могу найти информацию - в 1C есть аналог VB кода типа


Dim WithEvents Object As Activex.Class 

?

Если да, то прикастовать события вроде бы несложно.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

42 (изменено: chessman, 2013-03-14 19:28:19)

Re: Microsoft Outlook View Control

Xameleon пишет:

Добавлено в 18:26

Предполагаю, что придётся тогда несколько изменить идеологию. Сначала добавить на форму 1C объект WebBrowser. Он же Shell.Explorer (Объект Internet Explorer при этом не создаётся, что приятно), далее выполнить Navigate на заранее созданную страницу в Outlook Home Directory. Внутри страницы создать объект OVctl и обработчик события. Тогда дальше уже можно будет легко зацепить его к внешним обработчикам. Пока что это теория, но попробую реализовать.

А есть уверенность, что после этого будет доступно свойство Selection?

43

Re: Microsoft Outlook View Control

Xameleon пишет:

Понял. Не могу найти информацию - в 1C есть аналог VB кода типа


Dim WithEvents Object As Activex.Class 

?

Если да, то прикастовать события вроде бы несложно.

Такого нет.

44

Re: Microsoft Outlook View Control

chessman пишет:

А есть уверенность, что после этого будет доступно свойство Selection?

Есть предположение, с некоторой степенью уверенности. Уверенность основана на информации с http://pabweb.ru/32ch15g.shtml )

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

45

Re: Microsoft Outlook View Control

если речь о 8.х, то можно полехтмл

Я конечно далек от мысли... (с)

46

Re: Microsoft Outlook View Control

smaharbA пишет:

если речь о 8.х, то можно полехтмл

Есть готовое решение? Сам пробовал?