Ошибка окна сообщения: иностранный импорт небезопасен

StackOverflow https://stackoverflow.com/questions/7304317

  •  25-10-2019
  •  | 
  •  

Вопрос

import Graphics.Win32
import System.Win32.DLL
import Control.Exception (bracket)
import Foreign
import System.Exit
main :: IO ()
main = do
    mainInstance <- getModuleHandle Nothing
    hwnd <- createWindow_ 200 200 wndProc mainInstance
    createButton_ hwnd mainInstance
    messagePump hwnd
wndProc :: HWND -> WindowMessage -> WPARAM -> LPARAM -> IO LRESULT
wndProc hwnd wmsg wParam lParam
    | wmsg == wM_DESTROY = do
        sendMessage hwnd wM_QUIT 1 0
        return 0
    | wmsg == wM_COMMAND && wParam == 1 = do
        messageBox nullPtr "Yahoo!!" "Message box" 0 -- Error! Why? :(
        return 0
    | otherwise = defWindowProc (Just hwnd) wmsg wParam lParam
createWindow_ :: Int -> Int -> WindowClosure -> HINSTANCE -> IO HWND
createWindow_ width height wndProc mainInstance = do
    let winClass = mkClassName "ButtonExampleWindow"
    icon <- loadIcon Nothing iDI_APPLICATION
    cursor <- loadCursor Nothing iDC_ARROW
    bgBrush <- createSolidBrush (rgb 240 240 240)
    registerClass (cS_VREDRAW + cS_HREDRAW, mainInstance, Just icon, Just cursor, Just bgBrush, Nothing, winClass)
    w <- createWindow winClass "Button example" wS_OVERLAPPEDWINDOW Nothing Nothing (Just width) (Just height) Nothing Nothing mainInstance wndProc
    showWindow w sW_SHOWNORMAL
    updateWindow w
    return w
createButton_ :: HWND -> HINSTANCE -> IO ()
createButton_ hwnd mainInstance = do
    hBtn <- createButton "Press me" wS_EX_CLIENTEDGE (bS_PUSHBUTTON + wS_VISIBLE + wS_CHILD) (Just 50) (Just 80) (Just 80) (Just 20) (Just hwnd) (Just (castUINTToPtr 1)) mainInstance
    return ()
messagePump :: HWND -> IO ()
messagePump hwnd = allocaMessage $ \ msg ->
    let pump = do
        getMessage msg (Just hwnd) `catch` \ _ -> exitWith ExitSuccess
        translateMessage msg
        dispatchMessage msg
        pump
    in pump

Вот простое приложение Win32 с помощью кнопки, но когда я нажимаю кнопку, должна быть поле сообщения (22 строка), но есть ошибка:

кнопки. Возможно, «небезопасно иностранный импорт» должен быть «безопасным»?

Как я могу это исправить?

Это было полезно?

Решение

Как прокомментировал Даниэль Вагнер, это ошибка в пакете Win32. MessageBoxW Должен быть импортирован безопасно, из-за многих побочных эффектов, которые у него есть.

А messageBox Функция является оберткой для «небезопасно» MessageBoxW функция Когда небезопасная функция функции небезопасна, Хаскелл предполагает, что поток не будет вызывать кода Haskell, пока не вернется. Однако, если вы позвоните MessageBoxW, Windows бросит в окно довольно много оконных сообщений, которые вы создали в строке 30, поэтому код Haskell будет запускаться, пока вы находитесь в небезопасной внешней функции. Это также причина, по которой звонки messageBox заработает до того как Это окно было создано.

Возможный обходной путь - это просто исправить функцию самостоятельно. Во -первых, изменить

import Graphics.Win32

к

import Graphics.Win32 hiding (messageBox, c_MessageBox)

Затем скопируйте определения messageBox а также c_MessageBox из модуля Graphics.Win32.Misc, с unsafe удалено и/или safe добавлен:

messageBox :: HWND -> String -> String -> MBStyle -> IO MBStatus
messageBox wnd text caption style =
  withTString text $ \ c_text ->
  withTString caption $ \ c_caption ->
  failIfZero "MessageBox" $ c_MessageBox wnd c_text c_caption style
foreign import stdcall safe "windows.h MessageBoxW"
  c_MessageBox :: HWND -> LPCTSTR -> LPCTSTR -> MBStyle -> IO MBStatus
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top