File: Resource.sml

package info (click to toggle)
polyml 5.7.1-5
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, sid
  • size: 40,616 kB
  • sloc: cpp: 44,142; ansic: 26,963; sh: 22,002; asm: 13,486; makefile: 602; exp: 525; python: 253; awk: 91
file content (171 lines) | stat: -rw-r--r-- 7,444 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
(*
    Copyright (c) 2001, 2015
        David C.J. Matthews

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License version 2.1 as published by the Free Software Foundation.
    
    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.
    
    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*)

structure Resource :
  sig
    datatype ResourceType =
        RT_CURSOR | RT_BITMAP | RT_ICON | RT_MENU | RT_DIALOG | RT_STRING | RT_FONTDIR |
        RT_FONT | RT_ACCELERATOR | RT_RCDATA | RT_MESSAGETABLE | RT_GROUP_CURSOR |
        RT_GROUP_ICON | RT_VERSION | RT_DLGINCLUDE | RT_ANICURSOR | RT_ANIICON |
        RT_PLUGPLAY | RT_VXD

    type HRSRC
    type HRSRCGLOBAL
    type HINSTANCE

    datatype RESID = IdAsInt of int | IdAsString of string
    val MAKEINTRESOURCE : int -> RESID

    type HUPDATE

    val BeginUpdateResource : string * bool -> HUPDATE
    val EndUpdateResource : HUPDATE * bool -> unit
    val FindResource : HINSTANCE * RESID * ResourceType -> HRSRC
    val FindResourceEx : HINSTANCE * ResourceType * RESID * Locale.LANGID -> HRSRC
    val FreeLibrary : HINSTANCE -> unit
    val LoadLibrary : string -> HINSTANCE
    val LoadResource : HINSTANCE * HRSRC -> HRSRCGLOBAL
    val LoadString : HINSTANCE * RESID -> string
    val LockResource : HRSRCGLOBAL -> Word8Vector.vector
    val SizeofResource : HINSTANCE * HRSRC -> int
    val UpdateResource :
       HUPDATE * ResourceType * RESID * Locale.LANGID * Word8Vector.vector option -> unit
  end
 =
struct
    open Foreign
    open Base

    datatype RESID = datatype RESID

    fun MAKEINTRESOURCE i = 
        if i >= 0 andalso i < 65536 then IdAsInt i
        else raise Fail "resource id out of range"

    fun checkHandle h = (checkResult(not(isHNull h)); h)

    datatype ResourceType =
        RT_CURSOR | RT_BITMAP | RT_ICON | RT_MENU | RT_DIALOG | RT_STRING | RT_FONTDIR |
        RT_FONT | RT_ACCELERATOR | RT_RCDATA | RT_MESSAGETABLE | RT_GROUP_CURSOR |
        RT_GROUP_ICON | RT_VERSION | RT_DLGINCLUDE | RT_ANICURSOR | RT_ANIICON |
        RT_PLUGPLAY | RT_VXD

    local

        fun toRes 1 = RT_CURSOR | toRes 2 = RT_BITMAP | toRes 3 = RT_ICON | toRes 4 = RT_MENU
         |  toRes 5 = RT_DIALOG | toRes 6 = RT_STRING | toRes 7 = RT_FONTDIR | toRes 8 = RT_FONT
         |  toRes 9 = RT_ACCELERATOR | toRes 10 = RT_RCDATA | toRes 11 = RT_MESSAGETABLE
         |  toRes 12 = RT_GROUP_CURSOR | toRes 14 = RT_GROUP_ICON | toRes 16 = RT_VERSION
         |  toRes 17 = RT_DLGINCLUDE | toRes 19 = RT_PLUGPLAY | toRes 20 = RT_VXD
         |  toRes 21 = RT_ANICURSOR |  toRes 22 = RT_ANIICON
         |  toRes _ = raise Fail "Unknown Resource Type"

        fun fromRes RT_CURSOR = 1 | fromRes RT_BITMAP = 2 | fromRes RT_ICON = 3
         |  fromRes RT_MENU = 4 | fromRes RT_DIALOG = 5 | fromRes RT_STRING = 6
         |  fromRes RT_FONTDIR = 7 | fromRes RT_FONT = 8 | fromRes RT_ACCELERATOR = 9
         |  fromRes RT_RCDATA = 10 | fromRes RT_MESSAGETABLE = 11 | fromRes RT_GROUP_CURSOR = 12
         |  fromRes RT_GROUP_ICON = 14 | fromRes RT_VERSION = 16 | fromRes RT_DLGINCLUDE = 17
         |  fromRes RT_PLUGPLAY = 19 | fromRes RT_VXD = 20 | fromRes RT_ANICURSOR = 21
         |  fromRes RT_ANIICON = 22 
    in
        val RESOURCETYPE = 
            absConversion {abs = toRes, rep = fromRes} cInt
    end

    local
        datatype HRSRCGLOBAL = HRSRCGLOBAL of Memory.voidStar * int
    in
        type HRSRCGLOBAL = HRSRCGLOBAL

        val LoadLibrary = checkHandle o winCall1 (kernel "LoadLibraryA") (cString) cHINSTANCE
        and FreeLibrary = winCall1 (kernel "FreeLibrary") (cHINSTANCE) (successState "FreeLibrary")
        and FindResource = checkHandle o
            winCall3 (kernel "FindResourceA")
                (cHINSTANCE, cRESID, RESOURCETYPE) cHRSRC
        and SizeofResource = winCall2 (kernel "SizeofResource") (cHINSTANCE, cHRSRC) cDWORD
        (* The name and type are in the reverse order in FindResource and FindResourceEx *)
        and FindResourceEx = checkHandle o
             winCall4 (kernel "FindResourceExA")
                (cHINSTANCE, RESOURCETYPE, cRESID, LocaleBase.LANGID) cHRSRC

        (* LoadResource - load a resource into memory and get a handle to it. *)
        local
            val loadResource = winCall2 (kernel  "LoadResource") (cHINSTANCE, cHRSRC)
            and lockResource = winCall1 (kernel "LockResource") (cPointer) cPointer
            and loadString = winCall4 (user "LoadStringA") (cHINSTANCE, cRESID, cPointer, cInt) cInt
        in
            fun LoadResource (hInst, hRsrc) =
            let
                val size = SizeofResource (hInst, hRsrc)
                val load = loadResource cPointer
                val rsrc = load(hInst, hRsrc)
            in
                HRSRCGLOBAL(rsrc, size)
            end

            (* LockResource - get the resource as a piece of binary store. *)
            fun LockResource (HRSRCGLOBAL(hg, size)) =
            let
                val res = lockResource hg
            in
                Word8Vector.tabulate(size, fn i => Memory.get8(res, Word.fromInt i))
            end

            fun LoadString (hInst, resId): string =
            let
                (* The underlying call returns the number of bytes copied EXCLUDING the terminating null. *)
                (* The easiest way to make sure we have enough store is to loop. *)
                open Memory
                fun tryLoad n =
                let
                    val store = malloc n
                    val used = Word.fromInt(loadString(hInst, resId, store, Word.toInt n))
                in
                    (* We can't distinguish the empty string from a missing resource. *)
                    if used = 0w0 then ""
                    else if used < n-0w1
                    then fromCstring store before free store
                    else (free store; tryLoad(n*0w2))
                end
            in
                tryLoad 0w100
            end
        end

        val BeginUpdateResource =
            (fn c => (checkResult(not(isHNull c)); c)) o
            winCall2 (user "BeginUpdateResourceA") (cString, cBool) cHUPDATE

        val EndUpdateResource =
            winCall2 (user "EndUpdateResource") (cHUPDATE, cBool) (successState "EndUpdateResource")

        local
            val updateResource =
                winCall6 (user "UpdateResource")
                    (cHUPDATE, RESOURCETYPE, cRESID, LocaleBase.LANGID, cOptionPtr cByteArray, cInt)
                    (successState "UpdateResource")
        in
            (* NONE here means delete the resource, SOME means a value to store.  *)
            (* N.B. If updating a string the new value must be in Unicode. *)
            fun UpdateResource(hup, rt, resid, lang, v as SOME vec) =
                updateResource(hup, rt, resid, lang, v, Word8Vector.length vec)
            |   UpdateResource(hup, rt, resid, lang, NONE) =
                updateResource(hup, rt, resid, lang, NONE, 0)
        end
    end
end;