Skip to content

Instantly share code, notes, and snippets.

@zerofancy
Created August 5, 2024 17:32
Show Gist options
  • Save zerofancy/83db2f1c9f9cd26073661253904f9698 to your computer and use it in GitHub Desktop.
Save zerofancy/83db2f1c9f9cd26073661253904f9698 to your computer and use it in GitHub Desktop.
封装JNA MessageBox方法
package top.ntutn.ui
import com.sun.jna.Pointer
import com.sun.jna.platform.win32.WinDef
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import top.ntutn.util.User32Extend
import top.ntutn.util.User32ExtendFlags
class JNAMessageBox {
companion object {
fun builder(hWnd: Long? = null, buildBlock: Builder.() -> Unit) = Builder(hWnd).apply(buildBlock)
}
enum class ButtonFlags(val value: Long) {
ABOUT_RETRY_IGNORE(User32ExtendFlags.MB_ABORTRETRYIGNORE),
CANCEL_TRY_CONTINUE(User32ExtendFlags.MB_CANCELTRYCONTINUE),
OK(User32ExtendFlags.MB_OK),
OK_CANCEL(User32ExtendFlags.MB_OKCANCEL),
RETRY_CANCEL(User32ExtendFlags.MB_RETRYCANCEL),
YES_NO(User32ExtendFlags.MB_YESNO),
YES_NO_CANCEL(User32ExtendFlags.MB_YESNOCANCEL),
}
enum class IconFlags(val value: Long) {
NONE(0),
WARNING(User32ExtendFlags.MB_ICONWARNING),
INFORMATION(User32ExtendFlags.MB_ICONINFORMATION),
QUESTION(User32ExtendFlags.MB_ICONQUESTION),
ERROR(User32ExtendFlags.MB_ICONERROR)
}
enum class DefaultButton(val value: Long) {
FIRST(User32ExtendFlags.MB_DEFBUTTON1),
SECOND(User32ExtendFlags.MB_DEFBUTTON2),
THIRD(User32ExtendFlags.MB_DEFBUTTON3),
FORTH(User32ExtendFlags.MB_DEFBUTTON4)
}
enum class Return(val value: Int) {
ABOUT(User32ExtendFlags.MB_RETURN_IDABORT),
CANCEL(User32ExtendFlags.MB_RETURN_IDCANCEL),
CONTINUE(User32ExtendFlags.MB_RETURN_IDCONTINUE),
IGNORE(User32ExtendFlags.MB_RETURN_IDIGNORE),
NO(User32ExtendFlags.MB_RETURN_IDNO),
OK(User32ExtendFlags.MB_RETURN_IDOK),
RETRY(User32ExtendFlags.MB_RETURN_IDRETRY),
TRY_AGAIN(User32ExtendFlags.MB_RETURN_IDTRYAGAIN),
YES(User32ExtendFlags.MB_RETURN_IDYES)
}
class Builder(hWnd: Long? = null) {
val building = JNAMessageBox()
init {
building.hWnd = hWnd
}
fun noIcon() = apply {
building.iconFlags = IconFlags.NONE
}
fun informationIcon() = apply {
building.iconFlags = IconFlags.INFORMATION
}
fun warningIcon() = apply {
building.iconFlags = IconFlags.WARNING
}
fun errorIcon() = apply {
building.iconFlags = IconFlags.ERROR
}
fun content(text: String, title: String) = apply {
building.text = text
building.title = title
}
fun buttonAboutRetryIgnore(
defaultButton: DefaultButton = DefaultButton.FIRST,
aboutCallback: (() -> Unit)? = null,
retryCallback: (() -> Unit)? = null,
ignoreCallback: (() -> Unit)? = null
) = apply {
building.buttonFlags = ButtonFlags.ABOUT_RETRY_IGNORE
building.defaultButton = defaultButton
building.callbacks[Return.ABOUT] = aboutCallback
building.callbacks[Return.RETRY] = retryCallback
building.callbacks[Return.IGNORE] = ignoreCallback
}
fun buttonCancelTryContinue(
defaultButton: DefaultButton = DefaultButton.FIRST,
cancelCallback: (() -> Unit)? = null,
tryCallback: (() -> Unit)? = null,
continueCallback: (() -> Unit)? = null
) = apply {
building.buttonFlags = ButtonFlags.CANCEL_TRY_CONTINUE
building.defaultButton = defaultButton
building.callbacks[Return.CANCEL] = cancelCallback
building.callbacks[Return.TRY_AGAIN] = tryCallback
building.callbacks[Return.CONTINUE] = continueCallback
}
fun buttonOk(okCallback: (() -> Unit)? = null) = apply {
building.buttonFlags = ButtonFlags.OK
building.defaultButton = DefaultButton.FIRST
building.callbacks[Return.OK] = okCallback
}
fun buttonOkCancel(
defaultButton: DefaultButton = DefaultButton.FIRST,
okCallback: (() -> Unit)? = null,
cancelCallback: (() -> Unit)? = null
) = apply {
building.buttonFlags = ButtonFlags.OK_CANCEL
building.defaultButton = defaultButton
building.callbacks[Return.OK] = okCallback
building.callbacks[Return.CANCEL] = cancelCallback
}
fun retryCancel(
defaultButton: DefaultButton = DefaultButton.FIRST,
retryCallback: (() -> Unit)? = null,
cancelCallback: (() -> Unit)? = null
) = apply {
building.buttonFlags = ButtonFlags.RETRY_CANCEL
building.defaultButton = defaultButton
building.callbacks[Return.RETRY] = retryCallback
building.callbacks[Return.CANCEL] = cancelCallback
}
fun yesNo(
defaultButton: DefaultButton = DefaultButton.FIRST,
yesCallback: (() -> Unit)? = null,
noCallback: (() -> Unit)? = null
) =
apply {
building.buttonFlags = ButtonFlags.YES_NO
building.defaultButton = defaultButton
building.callbacks[Return.YES] = yesCallback
building.callbacks[Return.NO] = noCallback
}
fun yesNoCancel(
defaultButton: DefaultButton = DefaultButton.FIRST,
yesCallback: (() -> Unit)? = null,
noCallback: (() -> Unit)? = null,
cancelCallback: (() -> Unit)? = null
) = apply {
building.buttonFlags = ButtonFlags.YES_NO_CANCEL
building.defaultButton = defaultButton
building.callbacks[Return.YES] = yesCallback
building.callbacks[Return.NO] = noCallback
building.callbacks[Return.CANCEL] = cancelCallback
}
fun build() = building
}
var hWnd: Long? = null
var title = ""
var text = ""
var buttonFlags = ButtonFlags.OK
var iconFlags = IconFlags.NONE
var defaultButton = DefaultButton.FIRST
var isTopMost = false
private val uType: Long
get() {
var tmp = buttonFlags.value or iconFlags.value or defaultButton.value
if (isTopMost) {
tmp = tmp or User32ExtendFlags.MB_TOPMOST
}
return tmp
}
val callbacks = hashMapOf<Return, (() -> Unit)?>()
fun showSync() {
val res = User32Extend.instance.MessageBox(WinDef.HWND(hWnd?.let { Pointer(it) }), text, title, uType)
val returnValue = Return.entries.find { it.value == res } ?: return
callbacks[returnValue]?.invoke()
}
suspend fun showInIOScope() = withContext(Dispatchers.IO) {
User32Extend.instance.MessageBox(WinDef.HWND(hWnd?.let { Pointer(it) }), text, title, uType)
}
fun showAsync() = GlobalScope.launch {
val res = showInIOScope()
val returnValue = Return.entries.find { it.value == res } ?: return@launch
callbacks[returnValue]?.invoke()
}
}
package top.ntutn.util
import com.sun.jna.Native
import com.sun.jna.platform.win32.User32
import com.sun.jna.platform.win32.WinDef.HWND
import com.sun.jna.win32.W32APIOptions
interface User32Extend: User32 {
companion object {
val instance: User32Extend = Native.load("user32", User32Extend::class.java, W32APIOptions.DEFAULT_OPTIONS)
}
/**
* int MessageBox(
* [in, optional] HWND hWnd,
* [in, optional] LPCTSTR lpText,
* [in, optional] LPCTSTR lpCaption,
* [in] UINT uType
* );
*/
fun MessageBox(hWnd: HWND, lpText: String, lpCaption: String, uType: Long): Int
}
package top.ntutn.util
object User32ExtendFlags {
const val MB_ABORTRETRYIGNORE = 0x00000002L
const val MB_CANCELTRYCONTINUE = 0x00000006L
@Deprecated("It's hard to handle WM_HELP message in Java/Kotlin")
const val MB_HELP = 0x00004000L
const val MB_OK = 0x00000000L
const val MB_OKCANCEL = 0x00000001L
const val MB_RETRYCANCEL = 0x00000005L
const val MB_YESNO = 0x00000004L
const val MB_YESNOCANCEL = 0x00000003L
const val MB_ICONEXCLAMATION = 0x00000030L
const val MB_ICONWARNING = 0x00000030L
const val MB_ICONINFORMATION = 0x00000040L
const val MB_ICONASTERISK = 0x00000040L
const val MB_ICONQUESTION = 0x00000020L
const val MB_ICONSTOP = 0x00000010L
const val MB_ICONERROR = 0x00000010L
const val MB_ICONHAND = 0x00000010L
const val MB_DEFBUTTON1 = 0x00000000L
const val MB_DEFBUTTON2 = 0x00000100L
const val MB_DEFBUTTON3 = 0x00000200L
const val MB_DEFBUTTON4 = 0x00000300L
const val MB_APPLMODAL = 0x00000000L
const val MB_SYSTEMMODAL = 0x00001000L
const val MB_TASKMODAL = 0x00002000L
const val MB_DEFAULT_DESKTOP_ONLY = 0x00020000L
const val MB_RIGHT = 0x00080000L
const val MB_RTLREADING = 0x00100000L
const val MB_SETFOREGROUND = 0x00010000L
const val MB_TOPMOST = 0x00040000L
const val MB_SERVICE_NOTIFICATION = 0x00200000L
const val MB_RETURN_IDABORT = 3
const val MB_RETURN_IDCANCEL = 2
const val MB_RETURN_IDCONTINUE = 11
const val MB_RETURN_IDIGNORE = 5
const val MB_RETURN_IDNO = 7
const val MB_RETURN_IDOK = 1
const val MB_RETURN_IDRETRY = 4
const val MB_RETURN_IDTRYAGAIN = 10
const val MB_RETURN_IDYES = 6
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment