Sign in to follow this  
Followers 0
AdmiralAlkex

[solved] COM sink object/IUnknown events (I don't know :S)

8 posts in this topic

#1 ·  Posted (edited)

I wanted to see if I could manage to use IAppVisibility (Win8) in one of my scripts.

(it seems the name was changed in Release Preview but MSDN wasn't updated)

It took some time but I learned to make tlb file and made definitions for GetAppVisibilityOnMonitor and IsLauncherVisible methods (working good as far as I can tell), but I would like Advise and Unadvise too if possible, but I don't know how...

See definition on above link.

Only example I found is some (too advanced for me to translate) c++ code. Here. But it compiles and runs fine at least.

trancexx is doing a similar thing in maybe that can be used somehow?

Anyone have a clue?

Test script with the working funcs:

#include <WinAPI.au3>

;===============================================================================
#interface "IAppVisibility"
Global Const $sCLSID_AppVisibility = "{7E5FE3D9-985F-4908-91F9-EE19F9FD1514}"
Global Const $sIID_IAppVisibility = "{2246EA2D-CAEA-4444-A3C4-6DE827E44313}"
; Definition
Global Const $tagIAppVisibility = "GetAppVisibilityOnMonitor hresult(ptr;int*);" & _
"IsLauncherVisible hresult(int*);" & _
"Advise hresult(ptr;dword*);" & _
"Unadvise hresult(dword);"
;==============================================================================

Local $oAppVisibility = ObjCreateInterface($sCLSID_AppVisibility, $sIID_IAppVisibility, $tagIAppVisibility)

;~ MsgBox(0, @ScriptName, IsObj($oAppVisibility))
;~ ConsoleWrite(IsObj($oAppVisibility) & @CRLF)

If Not IsObj($oAppVisibility) Then
ConsoleWrite("NOT IsObj" & @LF)
MsgBox(0, "", "NOT IsObj")
Exit
EndIf

HotKeySet("ö", "_IsLauncherVisible")
HotKeySet("å", "_GetAppVisibilityOnMonitor")

$oMyError = ObjEvent("AutoIt.Error", "ErrFunc") ; Install a custom error handler

$callback=DllCallbackRegister("_MonitorEnumProc","int","ptr;ptr;ptr;lparam")
Global $Monitor
DllCall("user32.dll","int","EnumDisplayMonitors","ptr",0,"ptr",0,"ptr",DllCallbackGetPtr($callback),"lparam",10)

While 1
Sleep(1000)
WEnd

Func _IsLauncherVisible()
Local $bVisible
$iRet = $oAppVisibility.IsLauncherVisible($bVisible)
;~ If @error Then ;Enable this and disable AutoIt.Error if on Alpha
;~ MsgBox(0, @ScriptName, @error)
;~ EndIf
ToolTip("1: " & $iRet & @CRLF & "2: " & $bVisible)
EndFunc

Func _GetAppVisibilityOnMonitor()
Local $iMode
$iRet = $oAppVisibility.GetAppVisibilityOnMonitor($Monitor, $iMode)
ToolTip("1: " & $iRet & @CRLF & "2: " & $iMode)
EndFunc

; This is a custom error handler
Func ErrFunc()
$HexNumber = Hex($oMyError.number, 8)
MsgBox(0, "", "We intercepted a COM Error !" & @CRLF & _
"Number is: " & $HexNumber & @CRLF & _
"WinDescription is: " & $oMyError.windescription)
$iEventError = 1 ; Use to check when a COM Error occurs
EndFunc ;==>ErrFunc

Func _MonitorEnumProc($hMonitor, $hdcMonitor, $lprect, $lparam)
MsgBox(0, "Monitor", "Monitor handle: " & $hMonitor & @CRLF & "LPARAM: " & $lparam)
$Monitor = $hMonitor
EndFunc

Here's tlb stuff:

==================================================================================

coclass AppVisibility;
CLSID = {7E5FE3D9-985F-4908-91F9-EE19F9FD1514};

// Implemented interface: <Interface> IAppVisibility

==================================================================================

Interface IAppVisibility;
IID = {2246EA2D-CAEA-4444-A3C4-6DE827E44313};
// Inherits from: IUnknown {00000000-0000-0000-C000-000000000046}

1.
STDCALL FUNC PUREVIRTUAL;
HRESULT GetAppVisibilityOnMonitor(
[in]
hMonitor,
[out] int* pMode
);

2.
STDCALL FUNC PUREVIRTUAL;
HRESULT IsLauncherVisible(
[out] int* pfVisible
);

3.
STDCALL FUNC PUREVIRTUAL;
HRESULT Advise(
[in]
* pCallback,
[out] dword* pdwCookie
);

4.
STDCALL FUNC PUREVIRTUAL;
HRESULT Unadvise(
[in] dword dwCookie
);


==================================================================================

enum MONITOR_APP_VISIBILITY;
{
MAV_UNKNOWN = 0,
MAV_NO_APP_VISIBLE = 1,
MAV_APP_VISIBLE = 2
};


==================================================================================

Interface IAppVisibilityEvents;
IID = {6584CE6B-7D82-49C2-89C9-C6BC02BA8C38};
// Inherits from: IUnknown {00000000-0000-0000-C000-000000000046}

1.
STDCALL FUNC PUREVIRTUAL;
HRESULT AppVisibilityOnMonitorChanged(
[in]
hMonitor,
[in]
previousMode,
[in]
currentMode
);

2.
STDCALL FUNC PUREVIRTUAL;
HRESULT LauncherVisibilityChange(
[in] int currentVisibleState
);


==================================================================================
Edited by AdmiralAlkex

Share this post


Link to post
Share on other sites



You just have to realize that object is pointer to pointer pointing to set of function pointers. After that the soultion reveals itself.

I'll show you what I mean if no one else does it in the meantime, when I get home. You see, I'm at the beach now :D.


♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

trancexx is doing a similar thing in maybe that can be used somehow?

Anyone have a clue?

I think you are on the right track, but the example is for IDispatch-Events. The event-interface for IAppVisibility is not that difficult and sophosticated. Create a DLLStruct for the object and the vTable-Struct with all methods using DLLCallbackRegister / ...GetPtr. Now just pass this reference to Advise. I'll hack something together on my Win8 VM :D

*GERMAN* [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

Share this post


Link to post
Share on other sites

This piece of code works for me. Some parts of _AppVisibilityEvents_GetPtr could be replaced with AutoItObject, but I think that would be overkill :D

#include <WinAPI.au3>


Global Const $sIID_IAppVisibilityEvents = "{6584CE6B-7D82-49C2-89C9-C6BC02BA8C38}"
Global Const $sIID_IUnknown = "{00000000-0000-0000-C000-000000000046}"
Global Const $sVTable_IAppVisibilityEvents = "ptr QueryInterface; ptr AddRef; ptr Release; ptr AppVisibilityOnMonitorChanged; ptr LauncherVisibilityChange;"

Func __AppVisibilityEvents_QueryInterface($pSelf, $pRIID, $pObj)
    #forceref $pSelf, $pRIID, $pObj
    ConsoleWrite("__AppVisibilityEvents_QueryInterface called " & $pSelf & "    " & _WinAPI_StringFromGUID($pRIID) & "    ")
    Local $tStruct = DllStructCreate("ptr", $pObj)
    Switch _WinAPI_StringFromGUID($pRIID)
        Case $sIID_IUnknown
            DllStructSetData($tStruct, 1, $pSelf)
            ConsoleWrite("IUnknown" & @CRLF)
            Return 0
        Case $sIID_IAppVisibilityEvents
            DllStructSetData($tStruct, 1, $pSelf)
            ConsoleWrite("IAppVisibilityEvents" & @CRLF)
            Return 0
    EndSwitch
    ConsoleWrite("~ E_NOINTERFACE" & @CRLF)
    Return 0x80004002 ; E_NOINTERFACE
EndFunc   ;==>__AppVisibilityEvents_QueryInterface

Func __AppVisibilityEvents_AddRef($pSelf)
    #forceref $pSelf
    ConsoleWrite("__AppVisibilityEvents_AddRef called" & @CRLF)
    Return 0x80004001 ; E_NOTIMPL
EndFunc   ;==>__AppVisibilityEvents_AddRef

Func __AppVisibilityEvents_Release($pSelf)
    #forceref $pSelf
    ConsoleWrite("__AppVisibilityEvents_Release called" & @CRLF)
    Return 0x80004001 ; E_NOTIMPL
EndFunc   ;==>__AppVisibilityEvents_Release

Func _AppVisibilityEvents_AppVisibilityOnMonitorChanged($pSelf, $hMonitor, $previousMode, $currentMode)
    ConsoleWrite("_AppVisibilityEvents_AppVisibilityOnMonitorChanged called: " & $hMonitor & " " & $previousMode & " " & $currentMode & @CRLF)
    Return 0x80004001 ; E_NOTIMPL
EndFunc

Func _AppVisibilityEvents_LauncherVisibilityChange($pSelf, $currentVisibleState);
    ConsoleWrite("_AppVisibilityEvents_LauncherVisibilityChange called: " & $currentVisibleState & @CRLF)
    Return 0x80004001 ; E_NOTIMPL
EndFunc

Func _AppVisibilityEvents_GetPtr()
    Local Static $tObj = DllStructCreate("ptr"), $tTable
    If Not DllStructGetData($tObj, 1) Then
        $tTable = DllStructCreate($sVTable_IAppVisibilityEvents)
        DllStructSetData($tObj, 1, DllStructGetPtr($tTable))
        DllStructSetData($tTable, 1, DllCallbackGetPtr(DllCallbackRegister("__AppVisibilityEvents_QueryInterface", "long", "ptr;ptr;ptr")))
        DllStructSetData($tTable, 2, DllCallbackGetPtr(DllCallbackRegister("__AppVisibilityEvents_AddRef", "long", "ptr")))
        DllStructSetData($tTable, 3, DllCallbackGetPtr(DllCallbackRegister("__AppVisibilityEvents_Release", "long", "ptr")))
        DllStructSetData($tTable, 4, DllCallbackGetPtr(DllCallbackRegister("_AppVisibilityEvents_AppVisibilityOnMonitorChanged", "long", "ptr;ptr;int;int")))
        DllStructSetData($tTable, 5, DllCallbackGetPtr(DllCallbackRegister("_AppVisibilityEvents_LauncherVisibilityChange", "long", "ptr;int")))
    EndIf
    Return DllStructGetPtr($tObj)
EndFunc



;===============================================================================
#interface "IAppVisibility"
Global Const $sCLSID_AppVisibility = "{7E5FE3D9-985F-4908-91F9-EE19F9FD1514}"
Global Const $sIID_IAppVisibility = "{2246EA2D-CAEA-4444-A3C4-6DE827E44313}"
; Definition
Global Const $tagIAppVisibility = "GetAppVisibilityOnMonitor hresult(ptr;int*);" & _
        "IsLauncherVisible hresult(int*);" & _
        "Advise hresult(ptr;dword*);" & _
        "Unadvise hresult(dword);"
;==============================================================================

Local $oAppVisibility = ObjCreateInterface($sCLSID_AppVisibility, $sIID_IAppVisibility, $tagIAppVisibility)

;~ MsgBox(0, @ScriptName, IsObj($oAppVisibility))
;~ ConsoleWrite(IsObj($oAppVisibility) & @CRLF)

If Not IsObj($oAppVisibility) Then
    ConsoleWrite("NOT IsObj" & @LF)
    MsgBox(0, "", "NOT IsObj")
    Exit
EndIf

Global $dwEventsCookie
$oAppVisibility.Advise(_AppVisibilityEvents_GetPtr(), $dwEventsCookie)
OnAutoItExitRegister("_UnadviseEvents")

HotKeySet("ö", "_IsLauncherVisible")
HotKeySet("å", "_GetAppVisibilityOnMonitor")

$oMyError = ObjEvent("AutoIt.Error", "ErrFunc") ; Install a custom error handler

$callback=DllCallbackRegister("_MonitorEnumProc","int","ptr;ptr;ptr;lparam")
Global $Monitor
DllCall("user32.dll","int","EnumDisplayMonitors","ptr",0,"ptr",0,"ptr",DllCallbackGetPtr($callback),"lparam",10)

While 1
    Sleep(1000)
WEnd

Func _UnadviseEvents()
    $oAppVisibility.Unadvise($dwEventsCookie)
EndFunc

Func _IsLauncherVisible()
    Local $bVisible
    $iRet = $oAppVisibility.IsLauncherVisible($bVisible)
;~   If @error Then   ;Enable this and disable AutoIt.Error if on Alpha
;~       MsgBox(0, @ScriptName, @error)
;~   EndIf
    ToolTip("1: " & $iRet & @CRLF & "2: " & $bVisible)
EndFunc

Func _GetAppVisibilityOnMonitor()
    Local $iMode
    $iRet = $oAppVisibility.GetAppVisibilityOnMonitor($Monitor, $iMode)
    ToolTip("1: " & $iRet & @CRLF & "2: " & $iMode)
EndFunc

; This is a custom error handler
Func ErrFunc()
    $HexNumber = Hex($oMyError.number, 8)
    MsgBox(0, "", "We intercepted a COM Error !" & @CRLF & _
            "Number is: " & $HexNumber & @CRLF & _
            "WinDescription is: " & $oMyError.windescription)
    $iEventError = 1 ; Use to check when a COM Error occurs
EndFunc   ;==>ErrFunc

Func _MonitorEnumProc($hMonitor, $hdcMonitor, $lprect, $lparam)
    MsgBox(0, "Monitor", "Monitor handle: " & $hMonitor & @CRLF & "LPARAM: " & $lparam)
    $Monitor = $hMonitor
EndFunc

*GERMAN* [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

I could kiss you guys, you are awesome! :D

Edit: PS, for anyone reading this thread in the future, there is also a dll alternative, IsImmersiveProcess in User32.dll

Edited by AdmiralAlkex

Share this post


Link to post
Share on other sites

And girls :D


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

And girls :D

Oh, she's with us :huh:

guy

noun

a male. When used to refer to two or more people, the gender restriction is lifted such that one or more of those people may be female

Edited by AdmiralAlkex

Share this post


Link to post
Share on other sites

Oh, I learn something new every day :D


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0

  • Similar Content

    • FrancescoDiMuro
      By FrancescoDiMuro
      Good morning guys
      I was trying to not open another post, writing here my little issue, but seems that no one cares about, and so, I'm opening another post
      What I'm trying to do, is detect the event close sent from the virtual keyboard.
      Why?
      Because, I have an application which, when I set the focus on a textbox, if the virtual keyboard does not exist, then it is created, else, it's not created
      But, everytime I try to close the virtual keyboard, the focus remains on the textbox, and another $EN_FOCUS event it's launched and detected from my WM_COMMAND, and so, the virtual keyboard is opened again. 
      How can I solve this little "issue"? 
      I was trying to detect the event sent from the virtual keyboard, storing the handle of it in a variable, and setting:
      GUISetOnEvent($GUI_EVENT_CLOSE, "CloseVK", $hVirtualKeyboard) without any result.
      Can someone please help me?
      Thanks  
      EDIT:
      Here I'd like to see @Melba23, @water, @Danyfirex...
       
    • zetaimmersion
      By zetaimmersion
      Hi all. 
      I am trying to do 2 things but i cannot seem to get any traction on how to read/implement this idea.
      Premise: PowerPoint file in C\temp\presentation.pptx that contains on the first slide 2 entries as "<one>" and "<two>" which need to be replaced with "user1" and "user2", then a silent Outlook send mail containing the file with a predefined body and subject.
      I narrowed it down to COM objects as the Office does not like intrusive open AutoIt functions. I installed OLE/COM Object Viewer to understand how to create the commands but i am still stuck. So far i am trying to user water's code but i suck
      COM object i was originally trying to modify
      Dim $oPPT, $oPres $oPPT = ObjCreate("PowerPoint.Application") $oPPT.Visible = True $oPres = $oPPT.Presentations.Read Water's code below (0.1% modified)
      #include <File.au3> #include "PowerPoint.au3" #include <misc.au3> Global $sFile = "C:\temp\presentation.pptx" Global $sString2Search = "<username>", $sString2Replace = "Password", $iReplaceOnce = 1, $sFullLogFile = "C:\temp\pptxlog.txt" _ProcessPpt($sFile) Func _ProcessPpt($sFile) $oApp = _PPT_PowerPointApp() Local $bChange = False Local $oInterface = $oApp.Presentations Local $oPresentation = $oInterface.Open($sFile, False, False, False) If @error Then _FileWriteLog($sFullLogFile, "E Error " & @error & " opening File " & $sFile) Return SetError(1, 0, 0) EndIf ;it does not even open my file and from here not sure how to read the text and replace it EndFunc ;==>_ProcessPpt  
    • YellowLab
      By YellowLab
      I am having a very unique, but repeatable problem with ImageMagick COM interface. Here are the applicable lines of code:
      $oIM=ObjCreate("ImageMagickObject.MagickImage.1")
      and then later on...
      $oIM.Convert(String($arFileList[$nFileIndex])&'[0]',"-alpha", "remove",@TempDir&"\temp.jpg")
      the array points to a pdf file with the "convert" command converting the first page of the pdf to a jpg with any alpha layer removed.
      Every time, without fail, the first time I run the script on a freshly booted machine it crashes on the $oIM.Convert command. It does this if it isn't compiled and says there is an error executing the command on the object. If compiled, i get an error that autoit has stopped responding. Anytime I run the script, compiled or not, after this initial crash everything works perfectly fine.
      I am totally at a loss as to why this is occurring and how to correct it.
    • Javik
      By Javik
      Is there a way to read data directly from the Windows Component Object Model (COM) interface?
      I am trying to make a really simple disk space reporter tool for accounts on an Active Directory domain, to read the disk quota limit for the logged on user's home directory, and report how much disk space they are currently using.
      ,
      MSDN:  IDiskQuotaUser interface
      https://msdn.microsoft.com/en-us/library/windows/desktop/aa365033(v=vs.85).aspx
      GetQuotaLimit
      GetQuotaUsed
       
       
    • WoodGrain
      By WoodGrain
      Hi All,
      I've coded the small script below, but it can't seem to get the instance of Windows Media player as it keeps going to @error, I've not used com objects before so any assistance would be appreciate. I already have WMP open and minimised. I retrieved "WMPlayerApp" from the AutoIT info tool, I've included a copy below.
      I'm using these sources:
      https://msdn.microsoft.com/en-us/library/dd564085.aspx
      https://msdn.microsoft.com/en-us/library/dd564018.aspx
      $oWMP = ObjGet("", "WMPlayerApp") If @error Then MsgBox(0, "Can't get WMP", "Couldn't connect to the WMP instance") Exit EndIf $wmpPlayState = $oWMP.playState MsgBox(0, "Play State", $wmpPlayState) $wmpSongName = $oWMP.currentMedia.name MsgBox(0, "Play State", $wmpSongName) I've also seen references to the below, but I want to get an existing open WMP:
      ObjCreate("wmplayer.OCX") and have looked at the WMP.udf but can't see how it will do either of the functions I've coded above.