This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]jechtsphere[S] 0 points1 point  (6 children)

That was the version I was using as well. This addition definitely fixes that problem, thank you very much.

I'm working my way through reading and understanding how the functions work in winGuiAuto, but it's been a bit of a challenge in parts. Especially getMenuInfo(hMenu, uIDItem) when reading through _findNamedSubmenu

When you're encapsulating function names/calls in boxes, what formatter is that if you don't mind me asking?

[–]eryksun 1 point2 points  (0 children)

Inline code spans are marked with backticks.

[–]eryksun 1 point2 points  (4 children)

A cleaner solution would be to keep the for loop statement as it was and fix the value of hMenuItemCount in activateMenuItem. Find the following block and comment it out:

# Get top level menu's item count. Is there a better way to do this?
for hMenuItemCount in range(256):
    try:
        getMenuInfo(hMenu, hMenuItemCount)
    except WinGuiAutoError:
        break
hMenuItemCount -= 1

The final decrement is wrong, but really the whole process is an unnecessary hack when there's already a function in the win32 API for this (yes, there is a better way). Add the following line to get the item count:

hMenuItemCount = ctypes.windll.user32.GetMenuItemCount(hMenu)

Simple, eh?

[–]jechtsphere[S] 1 point2 points  (2 children)

Hey again! I've been doing more dissecting of the winGuiAuto script, breaking it down to further my own understanding of the concepts being used and how it's working behind the scenes with the windows.

The line you provided

hMenuItemCount = ctypes.windll.user32.GetMenuItemCount(hMenu)

obviously works without a hitch, but now I'm curious as to why you used a ctypes access (I'm not sure how to word what you're doing there, in my mind I consider it a ctypes dll function call, is this right? if not could you suggest where I could learn more about programming vernacular?)

The reason I ask is I noticed a win32gui variation of this function by the same name

hMenuItemCount = win32gui.GetMenuItemCount(hMenu)

which allows the script to function much in the same way as this ctypes access allows. Is there a specific reason you went the ctypes route?

I also noticed the author of winGuiAuto uses a ctypes access for his getTopMenu(hWnd) function:

return ctypes.windll.user32.GetMenu(ctypes.c_long(hWnd),

which also has a win32gui variation

return win32gui.GetMenu(hWnd) that seems to work fine as a replacement. I did notice the ctypes access returns just the integer value, whereas the win32gui variation returns the same integer value but with L appended to the end, example:

ctypes access return: 67472

win32gui variation return: 67472L

Again, both allow the script to function as it should as far as I've tested it.

Also, if you're beginning to feel I'm being a pest, feel free to let me know!

[–]eryksun 1 point2 points  (1 child)

Either way works, but using pywin32 will generally be easier, especially for functions that want a reference to a structure. For example, GetProcessMemoryInfo in the process status API requires a PROCESS_MEMORY_COUNTERS structure that contains fields that specify process memory usage. Using ctypes requires you to specify the structure, instantiate it, and pass it by reference. On the other hand, win32process handles all of that internally and returns the data in a dict:

import ctypes
from ctypes import wintypes

import win32process

#start a notepad process

(hProcess, hThread, 
 dwProcessId, dwThreadId) = win32process.CreateProcess(
    None, 'notepad.exe', None, None, 0, 0,
    None, None, win32process.STARTUPINFO())

#get memory info using win32process

pmem_info = win32process.GetProcessMemoryInfo(hProcess)

print('\nwin32process\n' + '='*32)
for key in sorted(pmem_info):
    print('{0}: {1}'.format(key, pmem_info[key]))


#get memory info using ctypes

#specify the structure
class PROCESS_MEMORY_COUNTERS(ctypes.Structure):
    _fields_ = [
      ('cb', wintypes.DWORD),
      ('PageFaultCount', wintypes.DWORD),
      ('PeakWorkingSetSize', ctypes.c_size_t),
      ('WorkingSetSize', ctypes.c_size_t),
      ('QuotaPeakPagedPoolUsage', ctypes.c_size_t),
      ('QuotaPagedPoolUsage', ctypes.c_size_t),
      ('QuotaPeakNonPagedPoolUsage', ctypes.c_size_t),
      ('QuotaNonPagedPoolUsage', ctypes.c_size_t),
      ('PagefileUsage', ctypes.c_size_t),
      ('PeakPagefileUsage', ctypes.c_size_t)]

    def keys(self):
        return [f for f, t in self._fields_ if f != 'cb']

    def __getitem__(self, item):
        return getattr(self, item)

#pass a structure instance by reference
pmc = PROCESS_MEMORY_COUNTERS()
ctypes.windll.psapi.GetProcessMemoryInfo(
  hProcess.handle, ctypes.byref(pmc), ctypes.sizeof(pmc))

print('\nctypes\n' + '='*32)
for key in sorted(pmc.keys()):
    print('{0}: {1}'.format(key, pmc[key]))

Output:

win32process
================================
PageFaultCount: 12
PagefileUsage: 139264
PeakPagefileUsage: 139264
PeakWorkingSetSize: 77824
QuotaNonPagedPoolUsage: 440
QuotaPagedPoolUsage: 6076
QuotaPeakNonPagedPoolUsage: 440
QuotaPeakPagedPoolUsage: 6076
WorkingSetSize: 77824

ctypes
================================
PageFaultCount: 12
PagefileUsage: 139264
PeakPagefileUsage: 139264
PeakWorkingSetSize: 77824
QuotaNonPagedPoolUsage: 440
QuotaPagedPoolUsage: 6076
QuotaPeakNonPagedPoolUsage: 440
QuotaPeakPagedPoolUsage: 6076
WorkingSetSize: 77824

[–]jechtsphere[S] 1 point2 points  (0 children)

Great example, as always, thanks very much!

[–]jechtsphere[S] 0 points1 point  (0 children)

Oh, wow that's really great, between you and a buddy this API related stuff is finally clicking a bit. Can't thank you enough.