Skip to content

Commit

Permalink
feat(win32-api): add UnregisterClassW(), update GetClassInfoExW()
Browse files Browse the repository at this point in the history
  • Loading branch information
waitingsong committed Jun 30, 2024
1 parent 303e2d3 commit 93f7bb4
Show file tree
Hide file tree
Showing 10 changed files with 235 additions and 2 deletions.
5 changes: 4 additions & 1 deletion packages/win32-api/src/lib/user32/dict/G.def.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ export class DefUser32_G extends DefUser32_F {
static GetCaretPos = [D.BOOL, [`_Out_ ${S.LPPOINT}`]]

/** https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getclassinfoexw */
static GetClassInfoExW = [D.BOOL, [D.HINSTANCE, D.LPCTSTR, `_Out_ ${S.LPWNDCLASSEXW}`]]
static GetClassInfoExW = [D.BOOL, [D.HINSTANCE, [D.WString], `_Out_ ${S.LPWNDCLASSEXW}`]] as const

// /** https://learn.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-getclassnamew */
// static GetClassNameW = [D.INT, [D.HWND, D.LPTSTR, D.INT]]

/** https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getcursorpos */
static GetCursorPos = [D.BOOL, [`_Out_ ${S.LPPOINT}`]]
Expand Down
3 changes: 3 additions & 0 deletions packages/win32-api/src/lib/user32/dict/TU.def.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ export class DefUser32_U extends DefUser32_T {

static UnhookWinEvent = [D.BOOL, [D.HWINEVENTHOOK]]

/** https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-unregisterclassw */
static UnregisterClassW = [D.BOOL, [D.WString, D.HINSTANCE]]

static UpdateWindow = [D.BOOL, [D.HWND]]

}
Expand Down
3 changes: 3 additions & 0 deletions packages/win32-api/src/lib/user32/dict/TU.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ export class User32_U extends User32_T {

UnhookWinEvent: (hWinEventHook: T.HWINEVENTHOOK) => T.BOOL

/** https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-unregisterclassw */
UnregisterClassW: (lpClassName: T.LPCTSTR | T.ATOM, hInstance: T.HINSTANCE) => T.BOOL

UpdateWindow: (hWnd: T.HWND) => T.BOOL

}
Expand Down
2 changes: 2 additions & 0 deletions packages/win32-api/src/lib/user32/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { DllNames } from '##/lib/types.js'

import { DefUser32 } from './api.def.js'
import { User32 } from './api.types.js'
import { multipleChoiceMapperList } from './mapper/index.mapper.js'


export {
Expand All @@ -18,5 +19,6 @@ export const load = (fns?: LoadOptions['usedFuncNames']) => _load<User32>({
dll: dllName + '.dll',
dllFuncs: DefUser32,
usedFuncNames: fns,
multipleChoiceMapperList: multipleChoiceMapperList,
})

51 changes: 51 additions & 0 deletions packages/win32-api/src/lib/user32/mapper/GetClassInfoExW.mapper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import assert from 'assert'

import type { FlattenNestedTuple } from '@waiting/shared-types'
import { WString } from 'win32-def/def'
import type { MultipleChoiceMapper } from 'win32-def/types'

import type { DefUser32 as Def } from '../api.def.js'
import type { User32 as Lib } from '../api.types.js'


export const funcName = 'GetClassInfoExW'
type Func = Lib[typeof funcName]
type Params = Parameters<Func>

type DefFunc = typeof Def[typeof funcName]
type DefParams = FlattenNestedTuple<DefFunc[1]>

export const GetClassInfoExW_mapper: MultipleChoiceMapper<Params, DefParams> = (name, runtimeArgs, defParamsArray) => {
if (name !== funcName) { return }
const lpszClass = runtimeArgs[1]

for (const row of defParamsArray) {
assert(Array.isArray(row))
const defArg = row[1]

switch (typeof lpszClass) {
case 'string': {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (defArg === WString) { // WString
return row
}
break
}

case 'object': {
assert(lpszClass instanceof Buffer, 'Invalid lpszClass type, must Buffer if object')
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (defArg === WString) { // WString
return row
}
break
}

default:
throw new Error(`Invalid lpszClass type: ${typeof lpszClass}`)
}
}
// return [] // will throw Error
}


11 changes: 11 additions & 0 deletions packages/win32-api/src/lib/user32/mapper/index.mapper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { MultipleChoiceMapperList, MultipleChoiceMapperSet } from 'win32-def/types'

import * as GetClassInfoExW from './GetClassInfoExW.mapper.js'


export const multipleChoiceMapperList: MultipleChoiceMapperList = new Map()
export const multipleChoiceMapperSet: MultipleChoiceMapperSet = new Set()

multipleChoiceMapperList.set(GetClassInfoExW.funcName, multipleChoiceMapperSet)
multipleChoiceMapperSet.add(GetClassInfoExW.GetClassInfoExW_mapper)

Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ describe(fileShortPath(import.meta.url), () => {
describe('GetModuleHandleW()', () => {
const name = DllNames.kernel32 + '.dll'

it('null', () => {
const lib = Lib.load()
assert(lib)

const hModule = lib.GetModuleHandleW(null)
assert(hModule)
})

it('string', () => {
const lib = Lib.load()
assert(lib)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { ucsBufferFrom } from 'win32-def'
import { Kernel32 as Lib, DllNames } from '##/index.js'


describe.only(fileShortPath(import.meta.url), () => {
describe(fileShortPath(import.meta.url), () => {
describe('GetModuleHandleExW()', () => {
const name = DllNames.kernel32 + '.dll'

Expand Down
76 changes: 76 additions & 0 deletions packages/win32-api/test/lib/user32/1000.RegisterClassExW.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import assert from 'node:assert/strict'

import { fileShortPath } from '@waiting/shared-core'
import { WNDCLASSEXW_Factory } from 'win32-def/struct'
import type { WNDCLASSEXW_Type } from 'win32-def/struct'

import { User32 as Lib, Kernel32 } from '##/index.js'


describe(fileShortPath(import.meta.url), () => {
const lib = Lib.load()
assert(lib)
const libKnl = Kernel32.load()
assert(libKnl)
const hModule = libKnl.GetModuleHandleW(null)
assert(hModule)

const lpszClassName = 'test-class-name-' + Date.now().toString()
const lpszMenuName = 'test-menu-name-' + Date.now().toString()

describe('RegisterClassExW()', () => {

it('no hInstance', () => {
const { payload } = WNDCLASSEXW_Factory()
assert(payload.cbSize === 80)
payload.lpszClassName = lpszClassName
payload.lpszMenuName = lpszMenuName

const atom = lib.RegisterClassExW(payload)
assert(atom)
lib.UnregisterClassW(atom, 0)
})

it('hInstance', () => {
const { payload } = WNDCLASSEXW_Factory()
assert(payload.cbSize === 80)
payload.lpszClassName = lpszClassName
payload.lpszMenuName = lpszMenuName
payload.hInstance = hModule

const atom = lib.RegisterClassExW(payload)
assert(atom)
lib.UnregisterClassW(atom, 0)
})


it('RegisterClassExW() re-gen', async () => {
const { payload: p1 } = WNDCLASSEXW_Factory()
assert(p1.cbSize === 80)
p1.lpszClassName = lpszClassName
p1.lpszMenuName = lpszMenuName
p1.hInstance = hModule

const atom = lib.RegisterClassExW(p1)
assert(atom)

try {
lib.UnregisterClassW(atom, 0)
const atom2 = lib.RegisterClassExW(p1)
assert(atom2)
try {
const atom3 = lib.RegisterClassExW(p1)
assert(!atom3)
}
finally {
lib.UnregisterClassW(atom2, 0)
}
}
finally {
lib.UnregisterClassW(atom, 0)
}
})
})

})

76 changes: 76 additions & 0 deletions packages/win32-api/test/lib/user32/1001.GetClassInfoExW.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import assert from 'node:assert/strict'

import { fileShortPath } from '@waiting/shared-core'
import { ucsBufferFrom } from 'win32-def'
import { WNDCLASSEXW_Factory } from 'win32-def/struct'
import type { WNDCLASSEXW_Type } from 'win32-def/struct'

import { User32 as Lib, Kernel32 } from '##/index.js'


describe(fileShortPath(import.meta.url), () => {
const lib = Lib.load()
assert(lib)
const libKnl = Kernel32.load()
assert(libKnl)
const hModule = libKnl.GetModuleHandleW(null)
assert(hModule)

const lpszClassName = 'test-class-' + Date.now().toString()
const lpszMenuName = 'test-menu-' + Date.now().toString()

describe('GetClassInfoExW()', () => {
it('GetClassInfoExW() pass string', () => {
const { payload } = WNDCLASSEXW_Factory()
assert(payload.cbSize === 80)
payload.lpszClassName = lpszClassName
payload.lpszMenuName = lpszMenuName
payload.hInstance = hModule
payload.style = 0x1000

const atom = lib.RegisterClassExW(payload)
assert(atom)

try {
const { payload: p2 } = WNDCLASSEXW_Factory()
const ret = lib.GetClassInfoExW(hModule, lpszClassName, p2)
assert(ret)
assert(p2.lpszClassName === lpszClassName)
assert(p2.lpszMenuName === lpszMenuName)
assert(p2.hInstance === hModule)
assert(p2.style === 0x1000)
assert(ret === atom)
}
finally {
lib.UnregisterClassW(atom, 0)
}
})

it('GetClassInfoExW() pass buffer', () => {
const { payload } = WNDCLASSEXW_Factory()
assert(payload.cbSize === 80)
payload.lpszClassName = lpszClassName
payload.lpszMenuName = lpszMenuName
payload.hInstance = hModule
payload.style = 0x1000

const atom = lib.RegisterClassExW(payload)
assert(atom)

try {
const { payload: p2 } = WNDCLASSEXW_Factory()
const ret = lib.GetClassInfoExW(hModule, ucsBufferFrom(lpszClassName), p2)
assert(ret)
assert(p2.lpszClassName === lpszClassName)
assert(p2.lpszMenuName === lpszMenuName)
assert(p2.hInstance === hModule)
assert(p2.style === 0x1000)
}
finally {
lib.UnregisterClassW(atom, 0)
}
})
})

})

0 comments on commit 93f7bb4

Please sign in to comment.