Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 02/17/2013 in all areas

  1. According to the book Code Complete these are some compelling reasons to avoid global scope. Most of these relate to information hiding in some way or another. A variable that is global is available to functions which may never need to have access to that variable. Most of these are relevant to AutoIt and others are not. * Inadvertent changes to global data. - "You might change the value of a global variable in one place and mistakenly think that it had remained unchanged somewhere else. Such a problem is known as a 'side effect'." Reducing side effects is also achieved by having functions perform one task and perform it well. Also, functions should not modify global data. They also should be referentially transparent. Basically, a function should only operate on data which is passed through its parameters. Additionally, every time a function is called with the same arguments it should return the same result every time. So, avoid using random numbers, time and date functions and avoid asking for user input within functions. * Bizarre and exciting aliasing problems with global data. - "'Aliasing' refers to calling the same variable by two or more different names." * Re-entrant code problems with global data. - "Code that can be entered by more than one thread of control is becoming increasingly common. Multithreaded code creates the possibility that global data will be shared not only among routines, but among different copies of the same program." * Code reuse hindered by global data. - "Ideally, you'd be able to lift out a single routine or class, plug it into another program, and continue merrily on your way. Global data complicates the picture." I've encountered this problem with code that I've tried to reuse in my own scripts. * Uncertain initialization-order issues with global data. - "The order in which data is initialized among different 'translation units' (files) is not defined in some languages." * Modularity and intellectual manageability damaged by global data. - "The essence of creating programs that are larger than a few hundred lines of code is managing complexity. The only way you can intellectually manage a large program is to break it into pieces so that you only have to think about one part at a time." edit: forgot a bullet point
    3 points
  2. _WinGetTextFixed & _StringFixANSIInWide Update: Text problems no longer exist as of v3.3.9.11 Sick of getting rows of '?' from WinGetText, ControlGetText, and other AutoIt functions? The problem lies in the way the text is encoded - AutoIt 'sees' a Windows wide string (UTF-16), but in reality it grabs a string of 8-bit ANSI characters and shoves them into a 16-bit wide string. Here's a small example: Original string "x4" with null-term as an ANSI string sequence: 0x78 0x34 0x00 Same string interpreted as Unicode (reversal is due to little-endian encoding): 0x3478 0x00 The latter string produces the Unicode character "㑸" (hopefully that shows up properly as an asian character) So, as you can see, from the software side, "x4" compacted into a UTF-16 string still produces an acceptable string, even though it wasn't intended to be an asian character. Now, where the '?'s show up is during conversion of the same string back to ANSI. You can see the result of this by doing a ConsoleWrite(), which itself causes an implicit Wide-ANSI conversion to occur. Also, pasting text into another text editor that's using an ANSI code page will give the same results. (A workaround for the conversion is to set the encoding to Unicode) Of course, even if you can display the wide characters correctly, it's not the intended result - you want what the window in question produces. Plus, there are many invalid UTF-16 code points that can be produced, and certain values will be interpreted as a pair of UTF-16 code points.. which just gets messy. So how do we fix this? The easiest workaround, when the format of the string is known to be ANSI beforehand is: $sStr = BinaryToString(StringToBinary($sStr, 2), 1) However, determining whether a window or control will give you ANSI or Wide characters is another issue.. I had written the _StringFixANSIInWide function below to try and detect ANSI-in-Wide situations, and return the corrected string.. Unfortunately its a bit naive in its implementation (see update next paragraph), but it works okay for most situations. I can see it failing only when a Wide string contains nothing but >8-bit characters (usually there is a lot of 7-bit ASCII characters encoded in the lower part of true Wide strings). In theory that is an extremely unlikely situation (unless there are no ASCII characters in a string). Update - _WinGetTextFixed() alternative: Now I've identified the core issue is with the call to SendMessage (using WM_GETTEXT): The function will return either ANSI or Unicode (wide) characters, and its up to our code to determine, based on the length, whether it is an ANSI or wide string. We can then return the correct string. See _WinGetTextFixed() below. Note that AutoIt's WinGetText() function returns text for more than just the window - it returns text for various controls also. While this can be beneficial, it also introduces issues when different controls return Wide or ANSI characters. The result is basically a contaminated string, meaning it packs ANSI characters into UTF-16 sequences and includes legitimate Wide characters in the same string. This is unacceptable and really hard to work with. That's a reason there's now a 'force conversion' parameter in _StringFixANSIInWide. I would really really emphasize that it's best to not use WinGetText() and instead opt for _WinGetTextFixed instead. I may suggest this behavior be fixed in the AutoIt source code, but it looks like all the Devs are gone Anyway, enjoy! Example: Notepad 2 $hWnd = WinGetHandle("[CLASS:Notepad2]") $hControl = ControlGetHandle($hWnd,"","[CLASS:Scintilla]") ; Previous fix: ;~ $sText = _StringFixANSIInWide(ControlGetText($hWnd,"",$hControl)) $sText = _WinGetTextFixed($hControl) ConsoleWrite("Text:"&$sText&@CRLF) Example: SciTE $hWnd = WinGetHandle("[CLASS:SciTEWindow]") $hControl=ControlGetHandle($hWnd,"","[CLASS:Scintilla; INSTANCE:1]") ; Previous fix: ;~ $sText = _StringFixANSIInWide(ControlGetText($hWnd,"",$hControl)) $sText = _WinGetTextFixed($hControl) ConsoleWrite("Text:"&$sText&@CRLF) Example: Programmer's Notepad 2 $hWnd = WinGetHandle("[REGEXPTITLE:Programmer's Notepad]") $hControl = ControlGetHandle($hWnd, "", "[CLASS:ScintillaWindowImpl; INSTANCE:1]") ; Previous fix: ;~ $sText = _StringFixANSIInWide(ControlGetText($hWnd,"",$hControl)) $sText = _WinGetTextFixed($hControl) ConsoleWrite("Text:"&$sText&@CRLF) ; =================================================================================================== ; Func Func _WinGetTextFixed($hWnd) ; ; Function to get Text of a window or control ; This is an alternative to AutoIt's 'WinGetTitle', 'WinGetText', and 'ControlGetText', ; which have issues with reading ANSI text from some windows ; ; Author: Ascend4nt ; =================================================================================================== Func _WinGetTextFixed($hWnd) If Not IsHWnd($hWnd) Then Return SetError(1,0,'') Local $aRet, $stWideText, $stANSIText, $sText Local $nGetTextLen, $nHalfLen ; WM_GETTEXTLENGTH 0x0E $aRet = DllCall("user32.dll", "long", "SendMessageW", "hwnd", $hWnd, "uint", 0x0E, "wparam", 0, "lparam", 0) If @error Then Return SetError(2, @error, '') If Not $aRet[0] Then Return SetError(3, 0, '') $nGetTextLen = $aRet[0] ;~ ConsoleWrite("WM_GETTEXTLENGTH return:"&$nGetTextLen&@CRLF) ; Create a union structure, add 2 characters - 1 for null-term, 1 to handle odd-count cases $stWideText = DllStructCreate("wchar["&$nGetTextLen + 2&"]") If @error Then Return SetError(4, 0, '') $stANSIText = DllStructCreate("char["&($nGetTextLen+2)*2&"]", DllStructGetPtr($stWideText)) ; WM_GETTEXT $aRet = DllCall("user32.dll", "long", "SendMessageW", "hwnd", $hWnd, "uint", 0x0D, "wparam", $nGetTextLen + 1, "ptr", DllStructGetPtr($stWideText)) If @error Then Return SetError(2, @error, '') If Not $aRet[0] Then Return SetError(3, 0, '') $nGetTextLen = $aRet[0] ; Get text as WIDE characters 1st $sText = DllStructGetData($stWideText, 1) ;~ ConsoleWrite("$nGetTextLen = "&$nGetTextLen&", $nHalfLen = "&$nHalfLen&", StringLen() = "&StringLen($sText)&@CRLF) ; Determine if the wide string length is half the supposed returned text length ; - If so, it's an ANSI string $nHalfLen = ($nGetTextLen + BitAND($nGetTextLen, 1) ) / 2 If (StringLen($sText) - $nHalfLen < 2) Then ; Retrieve text correctly as ANSI $sText = DllStructGetData($stANSIText, 1) EndIf Return $sText EndFunc ; ====================================================================================================== ; Func _StringFixANSIInWide($sStr, $bForceCnvt = False) ; ; Function to fix a common issue where ANSI text is embedded in UTF-16 strings ; Problem occurs in 'WinGetText', 'ControlGetText', 'WinGetTitle' ; and some COM functions using 'bstr' types ; ; Easiest method, when you *know* the text is ANSI: ; BinaryToString(StringToBinary($sStr, 2), 1) ; ; *However*, if it is unknown what the string holds, we need to look ; for null characters (0's) in the string ; ; Alternatives:'WideCharToMultiByte' API call, which does the same replacements as below ; However, on Vista+, WC_ERR_INVALID_CHARS can be used to error-out on illegal characters ; ; Author: Ascend4nt ; ====================================================================================================== Func _StringFixANSIInWide($sStr, $bForceCnvt = False) If $sStr = '' Then Return '' Local $nLen, $stStrVer, $stBinVer, $sTmp, $nReplacements ; This fails to work in many mixed-ANSI/UTF-16 scenarios (as seen in WinGetText): ;~ If $bForceCnvt Then ;~ Return BinaryToString(StringToBinary($sStr, 2), 1) ;~ EndIf $nLen = StringLen($sStr) ; Struct for string (+1 for null-term) $stStrVer = DllStructCreate("wchar [" & $nLen + 1 & "]") ; Create a union, granting us binary 1-byte access to the wide chars $stBinVer = DllStructCreate("byte [" & $nLen * 2 & "]", DllStructGetPtr($stStrVer)) ; Set String in structure DllStructSetData($stStrVer, 1, $sStr) ; Load string as binary data, convert to ANSI string ; AND Replace 0's with 0xFFFD (the Unicode 'REPLACEMENT CHARACTER') $sTmp = StringReplace(BinaryToString(DllStructGetData($stBinVer, 1)), ChrW(0), ChrW(0xFFFD), 0, 2) $nReplacements = @extended ; Trim off null-terminator and any other trailing 0's at the end (all converted to 0xFFFD's) While (StringRight($sTmp, 1) = ChrW(0xFFFD)) $sTmp = StringTrimRight($sTmp, 1) $nReplacements -= 1 WEnd ; If no replacements remaining, then every byte contains data, so its a safe bet the string is ANSI ; Also, in mixed-ANSI/UTF-16 situations (sometimes seen in WinGetText), allow a force If ($nReplacements = 0 Or $bForceCnvt) Then Return $sTmp ; Same result as: ;Return BinaryToString(StringToBinary($sStr, 2), 1) Else Return $sStr EndIf EndFunc ;==>_StringFixANSIInWide *updates: - Added a 'force' parameter for scenarios where WinGetText() will return a mix of ANSI and Unicode text in the same string. The result will contain some '?'s in these scenarios, but there's really nothing you can do without modifying the AutoIt source code. update: problem no longer exists as of v3.3.9.11 (see BugTracker ticket # 2362)
    1 point
  3. UEZ

    Transparent PNG issue?

    Try this: #include <GuiConstantsEX.au3> #include <GDIPlus.au3> ;~ #include "resources.au3" _GDIPlus_Startup() $hGui = GUICreate("show png", 350, 300) $hPic = GUICtrlCreatePic("", 25, 25) $Button = GUICtrlCreateButton("view", 130, 250, 75, 21) GUISetState() While 1 $msg = GUIGetMsg() Switch $msg Case $GUI_EVENT_CLOSE ExitLoop Case $Button $OpenFile = FileOpenDialog("Select image file", "", "image(*.png)") _GUICtrlStatic_SetPicture($OpenFile, $hPic, $hGui) EndSwitch WEnd Func _GUICtrlStatic_SetPicture($File, $CtrlId, $hGui) $hImage = _GDIPlus_ImageLoadFromFile($File) $hScrDC = _WinAPI_GetDC(0) $hMemDC = _WinAPI_CreateCompatibleDC($hScrDC) $hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage) $aPos = ControlGetPos($hGui, "", $CtrlId) GUICtrlSetPos($CtrlId, $aPos[0], $aPos[1], _GDIPlus_ImageGetWidth($hImage), _GDIPlus_ImageGetHeight($hImage)) GUICtrlSetImage($CtrlId, "") _SetBitmapToCtrl($CtrlId, $hBitmap) EndFUnc Func _SetBitmapToCtrl($CtrlId, $hBitmap) Local Const $STM_SETIMAGE = 0x0172 Local Const $IMAGE_BITMAP = 0 Local Const $SS_BITMAP = 0xE Local Const $GWL_STYLE = -16 Local $hWnd = GUICtrlGetHandle($CtrlId) If $hWnd = 0 Then Return SetError(1, 0, 0) ; set SS_BITMAP style to control Local $oldStyle = DllCall("user32.dll", "long", "GetWindowLong", "hwnd", $hWnd, "int", $GWL_STYLE) If @error Then Return SetError(2, 0, 0) DllCall("user32.dll", "long", "SetWindowLong", "hwnd", $hWnd, "int", $GWL_STYLE, "long", BitOR($oldStyle[0], $SS_BITMAP)) If @error Then Return SetError(3, 0, 0) Local $oldBmp = DllCall("user32.dll", "hwnd", "SendMessage", "hwnd", $hWnd, "int", $STM_SETIMAGE, "int", $IMAGE_BITMAP, "int", $hBitmap) If @error Then Return SetError(4, 0, 0) If $oldBmp[0] <> 0 Then _WinAPI_DeleteObject($oldBmp[0]) Return 1 EndFunc Br, UEZ
    1 point
  4. I added an alternative function call to 'GdipSetEffectParameters' which accepts a size, and also fixed the code where you set the "areas" structure member, and it seems to return okay. However, I don't actually see anything displayed in the GUI when I select a picture, so I'm not sure what that's about. Here's the code adjustments: Func _GDIPlus_EffectsSetParametersRE($hEffectObject, $pEffectParameters, $nSize) Local $aResult = DllCall($ghGDIPDll, "uint", "GdipSetEffectParameters", "handle", $hEffectObject, "ptr", $pEffectParameters, "uint", $nSize) If @error Then Return SetError(@error, @extended, 0) Return SetError($aResult[0], 0, $aResult[3]) EndFunc ;==>_GDIPlus_EffectsSetParameters Global $nNumRects = 2 Global $tRECTs = DLLStructCreate("long[" & $nNumRects * 4 & "];") DllStructSetData($tRECTs, 1, 55, 1) DllStructSetData($tRECTs, 1, 69, 2) DllStructSetData($tRECTs, 1, 68, 3) DllStructSetData($tRECTs, 1, 81, 4) DllStructSetData($tRECTs, 1, 159, 5) DllStructSetData($tRECTs, 1, 68, 6) DllStructSetData($tRECTs, 1, 172, 7) DllStructSetData($tRECTs, 1, 81, 8) Global Const $tagREDEYECORRECTIONPARAMS = "uint numberOfAreas;ptr areas;" Global $tRedEye = DllStructCreate($tagREDEYECORRECTIONPARAMS) Global Const $pRedEye = DllStructGetPtr($tRedEye) DllStructSetData($tRedEye, "numberOfAreas", $nNumRects) DllStructSetData($tRedEye, "areas", DllStructGetPtr($tRECTs)) $hEffect = _GDIPlus_EffectCreate($GDIP_REDEYECORRECTIONEFFECT) ;ConsoleWrite(_GDIPlus_EffectsSetParameters($hEffect, $pRedEye) & " / " & @error & @LF) ConsoleWrite(_GDIPlus_EffectsSetParametersRE($hEffect, $pRedEye, DllStructGetSize($tRedEye) + ($nNumRects * 4*4)) & " / " & @error & @LF)
    1 point
  5. same horse, different jockey I suppose.
    1 point
  6. I'd probably start of using hotkeys up right down left in conjunction with controlgetfocus and controlfocus with some maths voodoo.
    1 point
  7. UEZ, Your RECT structures must be contiguous in memory, so you have to create them in one DLLStruct, something like: $tRECTs = DLLStructCreate("long[" & $nNumRects*4 "];") Also the RedEyeCorrectionParams structure should be (the 2nd field gets a ptr to $tRECTS): $tagREDEYECORRECTIONPARAMS = "uint numberOfAreas;ptr areas;" Finally, I'm not sure about how you implement the 'SetParameters' call. It's defined like this in the Windows SDK: GdipSetEffectParameters(CGpEffect *effect, const VOID *params, const UINT size); ..and called like this (although I'm not sure why sizeof(RECT) is used as its separate from the structure): GdipSetEffectParameters(&Effect, &Params, sizeof(RedEyeCorrectionParams) + (sizeof(RECT) * nNumAreas) ) You might want to look at 'gdipluseffects.h" header in the Windows SDK, if you have it.
    1 point
  8. 1 point
  9. The use of local variables in the global scope only confuses
    1 point
  10. Calling a grape a football doesn't make it a football. There's only 2 scopes in AutoIt, and using "Local" in a global scope doesn't make it Local to any scope, so using Local is the wrong way to demonstrate to users how to write good code. I said it before, and I will say it again, if you're using it in a Global scope, use the Global keyword. If you're going to use it that way, might as well dispense with the Global keyword completely because it's just redundant.
    1 point
  11. I don't believe Valik would just simply regurgitate information without scrutiny. The less resources you have floating around, the less chance of something breaking. In the case in question, global variables are more likely to cause conflicts and this may take more time to fix if the variables are accessed frequently throughout the script. So we have several objections to using globals when not needed. I think the first statement says it all though: 'variables should always be declared in the smallest scope possible'.
    1 point
  12. Steini63

    Rsline.dll

    Hallo plfirer, no need to use a special dll, callling WinAPI is enough. I did this program last year: See the suggested german autoit forum for details & source (english comments though). : http://www.autoit.de/index.php?page=Thread&threadID=31353 Regards Steini
    1 point
  13. Zedna

    Resize Window Help

    #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> GUICreate("My GUI", 300, 200, Default, Default, BitOr($GUI_SS_DEFAULT_GUI,$WS_MAXIMIZEBOX,$WS_SIZEBOX )) GUISetState(@SW_SHOW) While 1 $msg = GUIGetMsg() If $msg = $GUI_EVENT_CLOSE Then ExitLoop WEnd
    1 point
  14. big_daddy

    AutoIt Menu

    I decided to try my luck at making a Firefox Extension from scratch, so what better for my first extension than something for AutoIt! This extension adds main-menu and context menu navigation for the AutoIt Forums. Screenshot: Now available on AMO! AutoIt Menu v1.3.1 (06/24/2011) If you are updating from a previous version you will need to install from the AMO site this one time. Future updates will happen as expected. --- Version History Added - Compatibility for Firefox through version 6.*Open Tickets Known Bugs: --- Comments and suggestions welcome!
    1 point
  15. Actually I was facing same issue. The solution I found was not to use _IEDocWriteHTML, since that will probably overwrite some iFramecode. This works for me every time: func readit() $oFrame = _IEFrameGetCollection($oie, 0) $i = _IEBodyReadHTML($oFrame) MsgBox(0,"",$i) EndFunc func writeit() $oFrame = _IEFrameGetCollection($oie, 0) _IEBodyWriteHTML($oframe, "<h1>Date: " & @MDAY & random(100,999,1) & "</h1>") EndFunc Notice use of _IEBodyWriteHTML which only updates the content between <body>..</body> of the iFrame. Basically where you write your content.
    1 point
  16. Melba23

    Arrays

    Arion, Or perhaps nutster's excellent UDF. M23
    1 point
×
×
  • Create New...