From 8ec71a8b460ad99b7977e263b4dfe0b916e68c47 Mon Sep 17 00:00:00 2001 From: blob1807 <12388588+blob1807@users.noreply.github.com> Date: Tue, 7 Apr 2026 23:36:38 +1000 Subject: [PATCH 1/5] [win32 api] Add Reg Association API --- core/sys/windows/shlwapi.odin | 8 ++ core/sys/windows/types.odin | 158 +++++++++++++++++++++++++++++++--- 2 files changed, 156 insertions(+), 10 deletions(-) diff --git a/core/sys/windows/shlwapi.odin b/core/sys/windows/shlwapi.odin index 095fff304..5b90e97dc 100644 --- a/core/sys/windows/shlwapi.odin +++ b/core/sys/windows/shlwapi.odin @@ -9,4 +9,12 @@ foreign shlwapi { PathFindExtensionW :: proc(pszPath: wstring) -> wstring --- PathFindFileNameW :: proc(pszPath: wstring) -> wstring --- SHAutoComplete :: proc(hwndEdit: HWND, dwFlags: DWORD) -> LWSTDAPI --- + + AssocCreate :: proc(clsid: CLSID, riid: REFIID, ppv: ^rawptr) -> HRESULT --- + SHGetAssocKeys :: proc(pqa: ^IQueryAssociations, rgKeys: ^HKEY, cKeys: DWORD) -> HRESULT --- + AssocQueryStringW :: proc(flags: ASSOCF, str: ASSOCSTR, pszAssoc: LPCWSTR, pszExtra: LPCWSTR, pszOut: LPWSTR, pcchOut: ^DWORD) -> LWSTDAPI --- + AssocQueryStringByKeyW :: proc(flags: ASSOCF, str: ASSOCSTR, hkAssoc: HKEY, pszExtra: LPCWSTR, pszOut: LPWSTR, pcchOut: ^DWORD) -> HRESULT --- + AssocQueryKeyW :: proc(flags: ASSOCF, key: ASSOCKEY, pszAssoc: LPCWSTR, pszExtra: LPCWSTR, phkeyOut: ^HKEY) -> HRESULT --- + AssocIsDangerous :: proc(pszAssoc: PCWSTR) -> HRESULT --- + AssocGetPerceivedType :: proc(pszExt: PCWSTR, ptype: ^PERCEIVED, pflag: ^PERCEIVEDFLAG, ppszType: ^PWSTR) -> HRESULT --- } diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 54ebd9481..9b4e92a3f 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -4196,6 +4196,34 @@ COMDLG_FILTERSPEC :: struct { pszName, pszSpec: LPCWSTR, } +PERCEIVED :: enum c_int { + TYPE_FIRST = -3, + TYPE_CUSTOM = -3, + TYPE_UNSPECIFIED = -2, + TYPE_FOLDER = -1, + TYPE_UNKNOWN = 0, + TYPE_TEXT = 1, + TYPE_IMAGE = 2, + TYPE_AUDIO = 3, + TYPE_VIDEO = 4, + TYPE_COMPRESSED = 5, + TYPE_DOCUMENT = 6, + TYPE_SYSTEM = 7, + TYPE_APPLICATION = 8, + TYPE_GAMEMEDIA = 9, + TYPE_CONTACTS = 10, + TYPE_LAST = 10, +} + +PERCEIVEDFLAG :: DWORD +PERCEIVEDFLAG_UNDEFINED :: 0x0000 +PERCEIVEDFLAG_SOFTCODED :: 0x0001 +PERCEIVEDFLAG_HARDCODED :: 0x0002 +PERCEIVEDFLAG_NATIVESUPPORT :: 0x0004 +PERCEIVEDFLAG_GDIPLUS :: 0x0010 +PERCEIVEDFLAG_WMSDK :: 0x0020 +PERCEIVEDFLAG_ZIPFOLDER :: 0x0040 + DECIMAL :: struct { wReserved: USHORT, using _: struct #raw_union { @@ -4277,17 +4305,19 @@ SHACF_AUTOAPPEND_FORCE_OFF :: 0x80000000 // Ignore the registry default and fo LWSTDAPI :: HRESULT -CLSID_FileOpenDialog := &GUID{0xDC1C5A9C, 0xE88A, 0x4DDE, {0xA5, 0xA1, 0x60, 0xF8, 0x2A, 0x20, 0xAE, 0xF7}} -CLSID_FileSaveDialog := &GUID{0xC0B4E2F3, 0xBA21, 0x4773, {0x8D, 0xBA, 0x33, 0x5E, 0xC9, 0x46, 0xEB, 0x8B}} -CLSID_TaskbarList := &GUID{0x56FDF344, 0xFD6D, 0x11d0, {0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90}} +CLSID_FileOpenDialog := &GUID{0xDC1C5A9C, 0xE88A, 0x4DDE, {0xA5, 0xA1, 0x60, 0xF8, 0x2A, 0x20, 0xAE, 0xF7}} +CLSID_FileSaveDialog := &GUID{0xC0B4E2F3, 0xBA21, 0x4773, {0x8D, 0xBA, 0x33, 0x5E, 0xC9, 0x46, 0xEB, 0x8B}} +CLSID_TaskbarList := &GUID{0x56FDF344, 0xFD6D, 0x11d0, {0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90}} +CLSID_QueryAssociations := GUID{0xa07034fd, 0x6caa, 0x4954, {0xac, 0x3f, 0x97, 0xa2, 0x72, 0x16, 0xf9, 0x8a}} -IID_IShellItem := &GUID{0x43826d1e, 0xe718, 0x42ee, {0xbc, 0x55, 0xa1, 0xe2, 0x61, 0xc3, 0x7b, 0xfe}} -IID_IFileDialog := &GUID{0x42F85136, 0xDB7E, 0x439C, {0x85, 0xF1, 0xE4, 0x07, 0x5D, 0x13, 0x5F, 0xC8}} -IID_IFileSaveDialog := &GUID{0x84BCCD23, 0x5FDE, 0x4CDB, {0xAE, 0xA4, 0xAF, 0x64, 0xB8, 0x3D, 0x78, 0xAB}} -IID_IFileOpenDialog := &GUID{0xD57C7288, 0xD4AD, 0x4768, {0xBE, 0x02, 0x9D, 0x96, 0x95, 0x32, 0xD9, 0x60}} -IID_ITaskbarList := &GUID{0x56FDF342, 0xFD6D, 0x11d0, {0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90}} -IID_ITaskbarList2 := &GUID{0x602D4995, 0xB13A, 0x429b, {0xA6, 0x6E, 0x19, 0x35, 0xE4, 0x4F, 0x43, 0x17}} -IID_ITaskbarList3 := &GUID{0xea1afb91, 0x9e28, 0x4b86, {0x90, 0xe9, 0x9e, 0x9f, 0x8a, 0x5e, 0xef, 0xaf}} +IID_IShellItem := &GUID{0x43826d1e, 0xe718, 0x42ee, {0xbc, 0x55, 0xa1, 0xe2, 0x61, 0xc3, 0x7b, 0xfe}} +IID_IFileDialog := &GUID{0x42F85136, 0xDB7E, 0x439C, {0x85, 0xF1, 0xE4, 0x07, 0x5D, 0x13, 0x5F, 0xC8}} +IID_IFileSaveDialog := &GUID{0x84BCCD23, 0x5FDE, 0x4CDB, {0xAE, 0xA4, 0xAF, 0x64, 0xB8, 0x3D, 0x78, 0xAB}} +IID_IFileOpenDialog := &GUID{0xD57C7288, 0xD4AD, 0x4768, {0xBE, 0x02, 0x9D, 0x96, 0x95, 0x32, 0xD9, 0x60}} +IID_ITaskbarList := &GUID{0x56FDF342, 0xFD6D, 0x11d0, {0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90}} +IID_ITaskbarList2 := &GUID{0x602D4995, 0xB13A, 0x429b, {0xA6, 0x6E, 0x19, 0x35, 0xE4, 0x4F, 0x43, 0x17}} +IID_ITaskbarList3 := &GUID{0xea1afb91, 0x9e28, 0x4b86, {0x90, 0xe9, 0x9e, 0x9f, 0x8a, 0x5e, 0xef, 0xaf}} +IID_IQueryAssociations := &GUID{0xc46ca590, 0x3c3f, 0x11d2, {0xbe, 0xe6, 0x00, 0x00, 0xf8, 0x05, 0xca, 0x57}} IModalWindow :: struct #raw_union { #subtype IUnknown: IUnknown, @@ -4670,6 +4700,91 @@ ITaskbarList3Vtbl :: struct { SetThumbnailClip: proc "system" (this: ^ITaskbarList3, hwnd: HWND, prcClip: ^RECT) -> HRESULT, } +ASSOCF_Bits :: enum c_int { + INIT_NOREMAPCLSID = 0, + INIT_BYEXENAME = 1, + OPEN_BYEXENAME = 1, + INIT_DEFAULTTOSTAR = 2, + INIT_DEFAULTTOFOLDER = 3, + NOUSERSETTINGS = 4, + NOTRUNCATE = 5, + VERIFY = 6, + REMAPRUNDLL = 7, + NOFIXUPS = 8, + IGNOREBASECLASS = 9, + INIT_IGNOREUNKNOWN = 10, + INIT_FIXED_PROGID = 11, + IS_PROTOCOL = 12, + INIT_FOR_FILE = 13, + IS_FULL_URI = 14, + PER_MACHINE_ONLY = 15, + APP_TO_APP = 16, +} +ASSOCF :: bit_set[ASSOCF_Bits; c_int] + +ASSOCSTR :: enum c_int { + COMMAND = 1, + EXECUTABLE, + FRIENDLYDOCNAME, + FRIENDLYAPPNAME, + NOOPEN, + SHELLNEWVALUE, + DDECOMMAND, + DDEIFEXEC, + DDEAPPLICATION, + DDETOPIC, + INFOTIP, + QUICKTIP, + TILEINFO, + CONTENTTYPE, + DEFAULTICON, + SHELLEXTENSION, + DROPTARGET, + DELEGATEEXECUTE, + SUPPORTED_URI_PROTOCOLS, + PROGID, + APPID, + APPPUBLISHER, + APPICONREFERENCE, + MAX, +} + +ASSOCKEY :: enum c_int { + SHELLEXECCLASS = 1, + APP, + CLASS, + BASECLASS, + MAX, +} + +ASSOCDATA :: enum c_int { + MSIDESCRIPTOR = 1, + NOACTIVATEHANDLER, + UNUSED1, + HASPERUSERASSOC, + EDITFLAGS, + VALUE, + MAX, +} + +ASSOCENUM :: enum c_int { + NONE, +} + +IQueryAssociations :: struct #raw_union { + #subtype IUnknown: IUnknown, + using Vtbl: ^IQueryAssociationsVtbl, +} + +IQueryAssociationsVtbl :: struct { + using IUnknownVtbl: IUnknownVtbl, + Init: proc "system" (this: ^IQueryAssociations, flags: ASSOCF, pszAssoc: LPCWSTR, hkProgid: HKEY, hwnd: HWND) -> HRESULT, + GetString: proc "system" (this: ^IQueryAssociations, flags: ASSOCF, str: ASSOCSTR, pszExtra: LPCWSTR, pszOut: LPWSTR, pcchOut: ^DWORD) -> HRESULT, + GetKey: proc "system" (this: ^IQueryAssociations, flags: ASSOCF, key: ASSOCKEY, pszExtra: LPCWSTR, phkeyOut: ^HKEY) -> HRESULT, + GetData: proc "system" (this: ^IQueryAssociations, flags: ASSOCF, data: ASSOCDATA, pszExtra: LPCWSTR, pvOut: rawptr, pcbOut: ^DWORD) -> HRESULT, + GetEnum: proc "system" (this: ^IQueryAssociations, flags: ASSOCF, assocenum: ASSOCENUM, pszExtra: LPCWSTR, riid: REFIID, ppvOut: ^rawptr) -> HRESULT, +} + MEMORYSTATUSEX :: struct { dwLength: DWORD, dwMemoryLoad: DWORD, @@ -5254,3 +5369,26 @@ Com_Error_Bits :: enum DWORD { } Com_Error :: distinct bit_set[Com_Error_Bits; DWORD] +FILETYPEATTRIBUTEFLAGS_Bits :: enum DWORD { + Exclude = 0, + Show = 1, + HasExtension = 2, + NoEdit = 3, + NoRemove = 4, + NoNewVerb = 5, + NoEditVerb = 6, + NoRemoveVerb = 7, + NoEditDesc = 8, + NoEditIcon = 9, + NoEditDflt = 10, + NoEditVerbCmd = 11, + NoEditVerbExe = 12, + NoDDE = 13, + NoEditMIME = 15, + OpenIsSafe = 16, + AlwaysUnsafe = 17, + NoRecentDocs = 20, + SafeForElevation = 21, + AlwaysUseDirectInvoke = 22, +} +FILETYPEATTRIBUTEFLAGS :: bit_set[FILETYPEATTRIBUTEFLAGS_Bits; DWORD] From bb7c80f73cda38f32d37f8963481a8d3a44bc391 Mon Sep 17 00:00:00 2001 From: blob1807 <12388588+blob1807@users.noreply.github.com> Date: Tue, 7 Apr 2026 23:44:30 +1000 Subject: [PATCH 2/5] Fix indentation --- core/sys/windows/types.odin | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 9b4e92a3f..f9485c48c 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -4197,22 +4197,22 @@ COMDLG_FILTERSPEC :: struct { } PERCEIVED :: enum c_int { - TYPE_FIRST = -3, - TYPE_CUSTOM = -3, - TYPE_UNSPECIFIED = -2, - TYPE_FOLDER = -1, - TYPE_UNKNOWN = 0, - TYPE_TEXT = 1, - TYPE_IMAGE = 2, - TYPE_AUDIO = 3, - TYPE_VIDEO = 4, - TYPE_COMPRESSED = 5, - TYPE_DOCUMENT = 6, - TYPE_SYSTEM = 7, - TYPE_APPLICATION = 8, - TYPE_GAMEMEDIA = 9, - TYPE_CONTACTS = 10, - TYPE_LAST = 10, + FIRST = -3, + CUSTOM = -3, + UNSPECIFIED = -2, + FOLDER = -1, + UNKNOWN = 0, + TEXT = 1, + IMAGE = 2, + AUDIO = 3, + VIDEO = 4, + COMPRESSED = 5, + DOCUMENT = 6, + SYSTEM = 7, + APPLICATION = 8, + GAMEMEDIA = 9, + CONTACTS = 10, + LAST = 10, } PERCEIVEDFLAG :: DWORD From adc0327bdb977b8a5bdf5452f3a137dd74ccd4d0 Mon Sep 17 00:00:00 2001 From: blob1807 <12388588+blob1807@users.noreply.github.com> Date: Wed, 8 Apr 2026 00:22:18 +1000 Subject: [PATCH 3/5] [win32 api] Add missed Assoc proc --- core/sys/windows/shell32.odin | 2 ++ core/sys/windows/types.odin | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/core/sys/windows/shell32.odin b/core/sys/windows/shell32.odin index 1a0844b39..0fdcc69d7 100644 --- a/core/sys/windows/shell32.odin +++ b/core/sys/windows/shell32.odin @@ -38,6 +38,8 @@ foreign shell32 { DragQueryPoint :: proc(hDrop: HDROP, ppt: ^POINT) -> BOOL --- DragQueryFileW :: proc(hDrop: HDROP, iFile: UINT, lpszFile: LPWSTR, cch: UINT) -> UINT --- DragFinish :: proc(hDrop: HDROP) --- // @New + + AssocCreateForClasses :: proc (rgClasses: [^]ASSOCIATIONELEMENT, cClasses: ULONG, riid: REFIID, ppv: ^rawptr) -> HRESULT --- } APPBARDATA :: struct { diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index f9485c48c..bb0291e2a 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -5392,3 +5392,24 @@ FILETYPEATTRIBUTEFLAGS_Bits :: enum DWORD { AlwaysUseDirectInvoke = 22, } FILETYPEATTRIBUTEFLAGS :: bit_set[FILETYPEATTRIBUTEFLAGS_Bits; DWORD] + +ASSOCCLASS :: enum c_int { + SHELL_KEY = 0, + PROGID_KEY, + PROGID_STR, + CLSID_KEY, + CLSID_STR, + APP_KEY, + APP_STR, + SYSTEM_STR, + FOLDER, + STAR, + FIXED_PROGID_STR, + PROTOCOL_STR, +} + +ASSOCIATIONELEMENT :: struct { + ac: ASSOCCLASS, + hkClass: HKEY, + pszClass: PCWSTR, +} From 8c6f45ceb10626ede4ed3bd2d5a81007b919759e Mon Sep 17 00:00:00 2001 From: blob1807 <12388588+blob1807@users.noreply.github.com> Date: Thu, 9 Apr 2026 10:59:53 +1000 Subject: [PATCH 4/5] Rename `FILETYPEATTRIBUTEFLAGS_Bits` -> `FILETYPEATTRIBUTEFLAG` --- core/sys/windows/types.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index bb0291e2a..2c9ea55fe 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -5369,7 +5369,7 @@ Com_Error_Bits :: enum DWORD { } Com_Error :: distinct bit_set[Com_Error_Bits; DWORD] -FILETYPEATTRIBUTEFLAGS_Bits :: enum DWORD { +FILETYPEATTRIBUTEFLAG :: enum DWORD { Exclude = 0, Show = 1, HasExtension = 2, @@ -5391,7 +5391,7 @@ FILETYPEATTRIBUTEFLAGS_Bits :: enum DWORD { SafeForElevation = 21, AlwaysUseDirectInvoke = 22, } -FILETYPEATTRIBUTEFLAGS :: bit_set[FILETYPEATTRIBUTEFLAGS_Bits; DWORD] +FILETYPEATTRIBUTEFLAGS :: bit_set[FILETYPEATTRIBUTEFLAG; DWORD] ASSOCCLASS :: enum c_int { SHELL_KEY = 0, From 3d4ccb3ec509e9eeb8743669695a40a39d015e6c Mon Sep 17 00:00:00 2001 From: blob1807 <12388588+blob1807@users.noreply.github.com> Date: Tue, 14 Apr 2026 20:53:05 +1000 Subject: [PATCH 5/5] Update `SHGetAssocKeys`; `rgKeys` to multipointer --- core/sys/windows/shlwapi.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/sys/windows/shlwapi.odin b/core/sys/windows/shlwapi.odin index 5b90e97dc..19a255331 100644 --- a/core/sys/windows/shlwapi.odin +++ b/core/sys/windows/shlwapi.odin @@ -11,7 +11,7 @@ foreign shlwapi { SHAutoComplete :: proc(hwndEdit: HWND, dwFlags: DWORD) -> LWSTDAPI --- AssocCreate :: proc(clsid: CLSID, riid: REFIID, ppv: ^rawptr) -> HRESULT --- - SHGetAssocKeys :: proc(pqa: ^IQueryAssociations, rgKeys: ^HKEY, cKeys: DWORD) -> HRESULT --- + SHGetAssocKeys :: proc(pqa: ^IQueryAssociations, rgKeys: [^]HKEY, cKeys: DWORD) -> HRESULT --- AssocQueryStringW :: proc(flags: ASSOCF, str: ASSOCSTR, pszAssoc: LPCWSTR, pszExtra: LPCWSTR, pszOut: LPWSTR, pcchOut: ^DWORD) -> LWSTDAPI --- AssocQueryStringByKeyW :: proc(flags: ASSOCF, str: ASSOCSTR, hkAssoc: HKEY, pszExtra: LPCWSTR, pszOut: LPWSTR, pcchOut: ^DWORD) -> HRESULT --- AssocQueryKeyW :: proc(flags: ASSOCF, key: ASSOCKEY, pszAssoc: LPCWSTR, pszExtra: LPCWSTR, phkeyOut: ^HKEY) -> HRESULT ---