Sublime Forum

[Solved] Problem inside Plugin (ApplicationCommand)

#1

Hi,
I’ve created a Plugin named “Test”. It calls from Win32.api the MessageboxA.
If I execute the api-call with Ctrl+B it works like expected.
But if I bind the call inside a ApplicationCommand class, I get an error.

This code works with Ctrl+B[code]
from ctypes import *

MB_DEFBUTTON1 = 0x0
MB_DEFBUTTON2 = 0x100
MB_DEFBUTTON3 = 0x200
MB_ICONASTERISK = 0x40
MB_ICONEXCLAMATION = 0x30
MB_ICONHAND = 0x10
MB_ICONINFORMATION = MB_ICONASTERISK
MB_ICONQUESTION = 0x20
MB_ICONSTOP = MB_ICONHAND
MB_OK = 0x0
MB_OKCANCEL = 0x1
MB_YESNO = 0x4
MB_YESNOCANCEL = 0x3
MB_ABORTRETRYIGNORE = 0x2
MB_RETRYCANCEL = 0x5

class MessageBox:
def box_a(self, text, title=‘Message Box’, utype=MB_OK, hwnd=None):
mb = windll.user32.MessageBoxA
mb(hwnd, c_char_p(text), c_char_p(title), c_long(utype))

msg = MessageBox()
msg.box_a(‘Thats a message’)[/code]

And this code was created as plugin “test” and bind with “F12”.[code]
import sublime, sublime_plugin
from ctypes import *

MB_DEFBUTTON1 = 0x0
MB_DEFBUTTON2 = 0x100
MB_DEFBUTTON3 = 0x200
MB_ICONASTERISK = 0x40
MB_ICONEXCLAMATION = 0x30
MB_ICONHAND = 0x10
MB_ICONINFORMATION = MB_ICONASTERISK
MB_ICONQUESTION = 0x20
MB_ICONSTOP = MB_ICONHAND
MB_OK = 0x0
MB_OKCANCEL = 0x1
MB_YESNO = 0x4
MB_YESNOCANCEL = 0x3
MB_ABORTRETRYIGNORE = 0x2
MB_RETRYCANCEL = 0x5

class TestCommand(sublime_plugin.ApplicationCommand):
def run(self):
self.box_a(‘Test-Box’)

def box_a(self, text, title='Message Box', utype=MB_OK, hwnd=None):
    mb = windll.user32.MessageBoxA
    mb(hwnd, c_char_p(text), c_char_p(title), c_long(utype))

[/code]
This fails with error message:

[quote] mb(hwnd, c_char_p(text), c_char_p(title), c_long(utype))
TypeError: bytes or integer address expected instead of str instance[/quote]

What do I wrong?

Thanks in advance.

0 Likes

#2

I’m guessing you are using Python 2 when you run the build command. Sublime uses Python 3 which handles strings and bytes significantly differently.

First off, a little tip, you don’t always have to explicitly cast values with ctypes. It will often figure out the type for you.

MessageBoxA is the ANSI version. If you want to use that, you have to first convert Python’s unicode strings into something it can handle, like this:

import locale
preferred_encoding = locale.getpreferredencoding(False)
mb(hwnd, text.encode(preferred_encoding), title.encode(preferred_encoding), utype)

However, that’s a pain. It’s better to just use the “wide” Unicode version:

mbw = windll.user32.MessageBoxW
mbw(hwnd, text, title, utype)

Also, you may find that your dialog box will pop up in the background. This is because the plugin runs in a background process separate from sublime. The handle to the window will be None. AFAICT, you can access the hwnd from sublime’s window object, but that will hang sublime. You can try adding MB_TOPMOST or MB_SYSTEMMODAL flag to the utype options.

Personally I do not like popup windows. I’m not sure what you are trying to achieve, but I encourage you to look at other options.

0 Likes

#3

Thanks for your explanation.
That I’ve used a message box was only a test for me, to handle sublime_plugin.ApplicationCommand.
I’ve written some plugins for SciTE editor (in Lua). And now I want to do the same for ST. It’s a very fine editor and so I’m learning Python too. :wink:

0 Likes