FreeFry Posted January 21, 2008 Share Posted January 21, 2008 (edited) Hi, I'm having problem with a script I was trying in response to solve another problem.I'm trying to add an entry to a window's system/control menu(the menu that appears when you right click the title bar of a window)This is the code that I currently have, which causes the crash:expandcollapse popupOpt("WinTitleMatchMode", 4) Global Const $MIIM_TYPE = 0x00000010 Global Const $MIIM_STRING = 0x00000040 Global Const $MIIM_FTYPE = 0x00000100 Global Const $MFT_STRING = 0x0000 Dim $ItemDataString = "Test" Dim $WindowHandle = WinGetHandle("[CLASS:SciTEWindow]") If @error Then MsgBox(0, "Error", "There was an error getting the window handle!") Exit EndIf $HMENU = DllCall("user32.dll", "hwnd", "GetSystemMenu", "hwnd", $WindowHandle, "int", False) If @error Then MsgBox(0, "Error", "An error occured when getting the SystemMenu: " & @error) Exit EndIf $MENUITEMINFO = DllStructCreate("uint;uint;uint;uint;uint;hwnd;hwnd;hwnd;ulong_ptr;char;uint;hwnd") If @error Then MsgBox(0, "Error", "There was an error while creating the structure: " & @error) Exit EndIf DllStructSetData($MENUITEMINFO, 2, $MIIM_STRING+$MIIM_FTYPE) DllStructSetData($MENUITEMINFO, 3, $MFT_STRING) DllStructSetData($MENUITEMINFO, 10, $ItemDataString) DllStructSetData($MENUITEMINFO, 11, StringLen($ItemDataString)) DllStructSetData($MENUITEMINFO, 1, DllStructGetSize($MENUITEMINFO)) ; not sure if this needs to be set after all the data is set, or if it can be set before.. DllCall("user32.dll", "int", "InsertMenuItem", "hwnd", $HMENU[0], "uint", 1, "byte", 1, "ptr", DllStructGetPtr($MENUITEMINFO)) If @error Then MsgBox(0, "Error", "There was an error in the InsertMenuItem function: " & @error) EndIf $MENUITEMINFO = 0Reference pages with the functions:GetSystemMenu: http://msdn2.microsoft.com/en-us/library/ms647985.aspxInsertMenuItem: http://msdn2.microsoft.com/en-us/library/m...988(VS.85).aspxI'm not sure wheter it's a syntax error on my part(probably), or if it might be some kind of bug/incompability(less likely) between autoit and this/these function(s).I hope someone can shine some light at this, as I'm trying to understand how the DllCall syntax translates between the Windows API and AutoIt. Edited January 21, 2008 by FreeFry Link to comment Share on other sites More sharing options...
DaleHohm Posted January 21, 2008 Share Posted January 21, 2008 If you say AutoIt crashes, you need to include the error messages generated when it does so. Dale Free Internet Tools: DebugBar, AutoIt IE Builder, HTTP UDF, MODIV2, IE Developer Toolbar, IEDocMon, Fiddler, HTML Validator, WGet, curl MSDN docs: InternetExplorer Object, Document Object, Overviews and Tutorials, DHTML Objects, DHTML Events, WinHttpRequest, XmlHttpRequest, Cross-Frame Scripting, Office object model Automate input type=file (Related) Alternative to _IECreateEmbedded? better: _IECreatePseudoEmbedded Better Better? IE.au3 issues with Vista - Workarounds SciTe Debug mode - it's magic: #AutoIt3Wrapper_run_debug_mode=Y Doesn't work needs to be ripped out of the troubleshooting lexicon. It means that what you tried did not produce the results you expected. It begs the questions 1) what did you try?, 2) what did you expect? and 3) what happened instead? Reproducer: a small (the smallest?) piece of stand-alone code that demonstrates your trouble Link to comment Share on other sites More sharing options...
Siao Posted January 21, 2008 Share Posted January 21, 2008 Pretty sure it's a memory problem. When you're messing with external process, you have to make sure the structs you pass are accessible to it. See GuiMenu UDF. "be smart, drink your wine" Link to comment Share on other sites More sharing options...
FreeFry Posted January 22, 2008 Author Share Posted January 22, 2008 (edited) Ok, Sorry, forgot that, I assume this is the error message:There's also a file called 7b8_appcompat.txt:7b8_appcompat.txtThanks Siao, I'll also have a look into that. Edit:Upploaded txt file instea of pasting it within code tags.. Edited January 22, 2008 by FreeFry Link to comment Share on other sites More sharing options...
Swift Posted January 22, 2008 Share Posted January 22, 2008 Long File Link to comment Share on other sites More sharing options...
FreeFry Posted January 22, 2008 Author Share Posted January 22, 2008 (edited) Long File Yea, well it's part of a crashlog, what do you expect? Anyways, I've looked in how this is done in the GuiMenu UDF, and there's a few things that I don't understand(actually, the way it's done in the UDF should be wrong, but it works :S) The way the structure is done in the UDF uses element names(is this perhaps required?), but if you compare that structure to the one in the documentation about the structure(http://msdn2.microsoft.com/en-us/library/ms647578(VS.85).aspx) it is all wrong. :S I'm confused.. From what I could gather from the documentation about the structure, this is the correct structure: "uint;uint;uint;uint;uint;hwnd;hwnd;hwnd;ulong_ptr;char;uint;hwnd" But in the UDF, this is how it's done: "int Size;int Mask;int Type;int State;int ID;int SubMenu;int BmpChecked;int BmpUnchecked;int ItemData;ptr TypeData;int CCH;int BmpItem" It's weird as all of the first 5 elements in the structure is clearly supposed to be uint's but still in the UDF they're not ... :S Someone please explain this. Edited January 22, 2008 by FreeFry Link to comment Share on other sites More sharing options...
LOULOU Posted January 22, 2008 Share Posted January 22, 2008 Yea, well it's part of a crashlog, what do you expect? Anyways, I've looked in how this is done in the GuiMenu UDF, and there's a few things that I don't understand(actually, the way it's done in the UDF should be wrong, but it works :S) The way the structure is done in the UDF uses element names(is this perhaps required?), but if you compare that structure to the one in the documentation about the structure(http://msdn2.microsoft.com/en-us/library/ms647578(VS.85).aspx) it is all wrong. :S I'm confused.. From what I could gather from the documentation about the structure, this is the correct structure: "uint;uint;uint;uint;uint;hwnd;hwnd;hwnd;ulong_ptr;char;uint;hwnd" But in the UDF, this is how it's done: "int Size;int Mask;int Type;int State;int ID;int SubMenu;int BmpChecked;int BmpUnchecked;int ItemData;ptr TypeData;int CCH;int BmpItem" It's weird as all of the first 5 elements in the structure is clearly supposed to be uint's but still in the UDF they're not ... :S Someone please explain this. In the new version 10.0 long_ptr don't exist and wa replaced by long* maybe the problem comes from that. Link to comment Share on other sites More sharing options...
FreeFry Posted January 22, 2008 Author Share Posted January 22, 2008 (edited) Well, the helpfile doesn't say anything about that.. Edit: Well actually it does say something about that, but that's related to DllCall, and not DllStructCreate. Anyways, I've got it to a working state now(though, sometimes it doesn't work for some reason :S): expandcollapse popupOpt("WinTitleMatchMode", 4) Global Const $MIIM_STRING = 0x00000040 Run("notepad.exe") WinWait("[CLASS:Notepad]") Dim $WindowHandle = WinGetHandle("[CLASS:Notepad]") Dim $TextStr = "Test" $Text = DllStructCreate("char Text[" & StringLen($TextStr)+1 & "]") If @error Then MsgBox(0, "Error", "There was an error while creating the Text structure: " & @error) Exit EndIf DllStructSetData($Text, "Text", $TextStr) If @error Then MsgBox(0, "Error", "There was an error getting the window handle!") Exit EndIf $HMENU = DllCall("user32.dll", "hwnd", "GetSystemMenu", "hwnd", $WindowHandle, "int", False) If @error Then MsgBox(0, "Error", "An error occured when getting the SystemMenu: " & @error) Exit EndIf $MENUITEMINFO = DllStructCreate("uint Size;uint Mask;uint Type;uint State;uint ID;hwnd SubMenu;hwnd BmpChecked;hwnd BmpUnchecked;int ItemData;ptr TypeData;uint CCH;hwnd BmpItem") If @error Then MsgBox(0, "Error", "There was an error while creating the MENUITEMINFO structure: " & @error) Exit EndIf DllStructSetData($MENUITEMINFO, "Size", DllStructGetSize($MENUITEMINFO)) ; cbSize DllStructSetData($MENUITEMINFO, "Mask", $MIIM_STRING) ; fMask DllStructSetData($MENUITEMINFO, "TypeData", DllStructGetPtr($Text)) ; dwTypeData $a = DllCall("user32.dll", "int", "InsertMenuItem", "hwnd", $HMENU[0], "int", 8, "int", True, "ptr", DllStructGetPtr($MENUITEMINFO)) If @error Then MsgBox(0, "Error", "There was an error in the InsertMenuItem function: " & @error) ElseIf Not $a[0] Then MsgBox(0, "Error", "The InsertMenuItem function did not add a new menu item.") Else MsgBox(0, "Success", "A new menu item called '" & $TextStr & "' was added to the System Menu") EndIf I think that the error that caused the crash was related to using the wrong structure type(I used a char when it really should've been a pointer to another structure with the text specified) Edit: Now I just need to find a way of hooking into the window and catch the message whenver the menu item is clicked. :| And I have no clue if that's possible or if it even can be done with AutoIt... Edited January 22, 2008 by FreeFry Link to comment Share on other sites More sharing options...
Siao Posted January 22, 2008 Share Posted January 22, 2008 (edited) Now I just need to find a way of hooking into the window and catch the message whenver the menu item is clicked. :| And I have no clue if that's possible or if it even can be done with AutoIt...It's definitely possible, there are some shareware apps (WireKeys and others) that do this, and I recall reading an article outlining the process somewhere, can't find it atm.. Proper way is by the use of global hooks (SetWindowsHookEx, etc.), and of course you need a dll for that. Which may be outside of what you can or want to do. Of course, there's always cheese like this, which would work reliably enough, I guess: #include <GuiMenu.au3> #Include <Misc.au3> Global $sTitle = 'Calculator', $iOurItem, $bChecked = False If Not WinExists($sTitle) Then Run('calc.exe') WinWait($sTitle) EndIf $hCalc = WinGetHandle($sTitle) $hCalcMenu = _GUICtrlMenu_GetSystemMenu($hCalc) _GUICtrlMenu_AppendMenu($hCalcMenu, $MF_SEPARATOR, 0, 0) $iOurItem = _GUICtrlMenu_AddMenuItem($hCalcMenu, "Always On Top") While WinExists($hCalc) Sleep(50) If _IsPressed(1) And WinActive($hCalc) Then If _GUICtrlMenu_MenuItemFromPoint($hCalc, $hCalcMenu) = $iOurItem Then $bChecked = Not $bChecked _GUICtrlMenu_SetItemChecked($hCalcMenu, $iOurItem, $bChecked) WinSetOnTop($hCalc, "", $bChecked) EndIf EndIf WEnd Exit Doesn't work too well if menu is invoked by rightclicking button on taskbar though. And I'm not a fan of polling approach in general. But these are your options. Edited January 22, 2008 by Siao "be smart, drink your wine" Link to comment Share on other sites More sharing options...
FreeFry Posted January 22, 2008 Author Share Posted January 22, 2008 Thanks for your response Siao. Yes, neither I am very found of polling, I like hooks more(no chance of missing a message).. Well, I don't know how to code a DLL so that's a problem. :/ Correct me if I'm wrong, but the only hooks autoit handle is the low level Mouse and Keyboard hook right? Atleast that's the only two I've seen that doesn't require the callback procedure to be in a DLL. Link to comment Share on other sites More sharing options...
rasim Posted January 23, 2008 Share Posted January 23, 2008 FreeFryNice work! I like it! But where you take $MIIM_STRING = 0x00000040 and why you set data only for this: DllStructSetData($MENUITEMINFO, "Size", DllStructGetSize($MENUITEMINFO)) ; cbSize DllStructSetData($MENUITEMINFO, "Mask", $MIIM_STRING) ; fMask DllStructSetData($MENUITEMINFO, "TypeData", DllStructGetPtr($Text)) ; dwTypeData? Link to comment Share on other sites More sharing options...
FreeFry Posted January 23, 2008 Author Share Posted January 23, 2008 I'm not if I understand you correctly rasim, but I was testing, and found out that you only have to set those 3 elements in the structure to be able to add a new entry to the system menu. Link to comment Share on other sites More sharing options...
rasim Posted January 23, 2008 Share Posted January 23, 2008 I'm not if I understand you correctly rasim, but I was testing, and found out that you only have to set those 3 elements in the structure to be able to add a new entry to the system menu.Inderstand, but what about $MIIM_STRING = 0x00000040? Why exactly this value? Link to comment Share on other sites More sharing options...
FreeFry Posted January 23, 2008 Author Share Posted January 23, 2008 Because that's the value that makes it add a text string.There are other values that does other things, they can be found/seen at the reference page for the structure:http://msdn2.microsoft.com/en-us/library/m...578(VS.85).aspx Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now