get-resource' and
write-resource': support .ini files
This commit is contained in:
parent
b4c3d82c94
commit
18eb7c86b5
|
@ -38,9 +38,13 @@
|
||||||
|
|
||||||
(define advapi-dll (and (eq? (system-type) 'windows)
|
(define advapi-dll (and (eq? (system-type) 'windows)
|
||||||
(ffi-lib "Advapi32.dll")))
|
(ffi-lib "Advapi32.dll")))
|
||||||
|
(define kernel-dll (and (eq? (system-type) 'windows)
|
||||||
|
(ffi-lib "kernel32.dll")))
|
||||||
|
|
||||||
(define-ffi-definer define-advapi advapi-dll
|
(define-ffi-definer define-advapi advapi-dll
|
||||||
#:default-make-fail make-not-available)
|
#:default-make-fail make-not-available)
|
||||||
|
(define-ffi-definer define-kernel kernel-dll
|
||||||
|
#:default-make-fail make-not-available)
|
||||||
|
|
||||||
(define win64? (equal? "win32\\x86_64" (path->string (system-library-subpath #f))))
|
(define win64? (equal? "win32\\x86_64" (path->string (system-library-subpath #f))))
|
||||||
(define win_abi (if win64? #f 'stdcall))
|
(define win_abi (if win64? #f 'stdcall))
|
||||||
|
@ -48,6 +52,7 @@
|
||||||
(define _LONG _long)
|
(define _LONG _long)
|
||||||
(define _DWORD _int32)
|
(define _DWORD _int32)
|
||||||
(define _REGSAM _DWORD)
|
(define _REGSAM _DWORD)
|
||||||
|
(define _BOOL (make-ctype _int (lambda (v) (if v 1 0)) (lambda (v) (not (zero? v)))))
|
||||||
|
|
||||||
(define KEY_QUERY_VALUE #x1)
|
(define KEY_QUERY_VALUE #x1)
|
||||||
(define KEY_SET_VALUE #x2)
|
(define KEY_SET_VALUE #x2)
|
||||||
|
@ -85,10 +90,32 @@
|
||||||
|
|
||||||
(define-advapi RegCloseKey (_fun #:abi win_abi _HKEY -> _LONG))
|
(define-advapi RegCloseKey (_fun #:abi win_abi _HKEY -> _LONG))
|
||||||
|
|
||||||
|
(define-kernel WritePrivateProfileStringW (_fun #:abi win_abi
|
||||||
|
_string/utf-16 ; app
|
||||||
|
_string/utf-16 ; key
|
||||||
|
_string/utf-16 ; val
|
||||||
|
_string/utf-16 ; filename
|
||||||
|
-> _BOOL))
|
||||||
|
(define-kernel GetPrivateProfileStringW (_fun #:abi win_abi
|
||||||
|
_string/utf-16 ; app
|
||||||
|
_string/utf-16 ; key
|
||||||
|
_string/utf-16 ; default
|
||||||
|
_pointer ; result
|
||||||
|
_DWORD ; result size in wide chars
|
||||||
|
_string/utf-16 ; filename
|
||||||
|
-> _DWORD))
|
||||||
|
|
||||||
|
(define (file->ini f)
|
||||||
|
(cond
|
||||||
|
[(not f) (file->ini
|
||||||
|
(build-path (find-system-path 'home-dir) "mred.ini"))]
|
||||||
|
[(string? f) (file->ini (string->path f))]
|
||||||
|
[(path? f) (path->string (cleanse-path (path->complete-path f)))]))
|
||||||
|
|
||||||
(define (extract-sub-hkey file hkey entry op create-key?)
|
(define (extract-sub-hkey file hkey entry op create-key?)
|
||||||
(cond
|
(cond
|
||||||
[(not (eq? 'windows (system-type))) (values #f #f)]
|
[(not (eq? 'windows (system-type))) (values #f #f)]
|
||||||
[file #f]
|
[file (values #f #f)]
|
||||||
[(regexp-match #rx"^(.*)\\\\+([^\\]*)$" entry)
|
[(regexp-match #rx"^(.*)\\\\+([^\\]*)$" entry)
|
||||||
=> (lambda (m)
|
=> (lambda (m)
|
||||||
(let ([sub-hkey (RegOpenKeyExW hkey (cadr m) 0 op)]
|
(let ([sub-hkey (RegOpenKeyExW hkey (cadr m) 0 op)]
|
||||||
|
@ -122,10 +149,27 @@
|
||||||
(unless (memq rtype '(string bytes integer))
|
(unless (memq rtype '(string bytes integer))
|
||||||
(raise-type-error 'get-resource "'string, 'bytes, or 'integer" rtype))
|
(raise-type-error 'get-resource "'string, 'bytes, or 'integer" rtype))
|
||||||
|
|
||||||
|
(define (to-rtype s)
|
||||||
|
(let ([to-string (lambda (s)
|
||||||
|
(if (bytes? s)
|
||||||
|
(bytes->string/utf-8 s #\?)
|
||||||
|
s))])
|
||||||
|
(cond
|
||||||
|
[(eq? rtype 'string) (to-string s)]
|
||||||
|
[(eq? rtype 'integer)
|
||||||
|
(let ([n (string->number (to-string s))])
|
||||||
|
(or (and n (exact-integer? n) n)
|
||||||
|
0))]
|
||||||
|
[else
|
||||||
|
(if (string? s)
|
||||||
|
(string->bytes/utf-8 s)
|
||||||
|
s)])))
|
||||||
|
|
||||||
(define-values (sub-hkey sub-entry)
|
(define-values (sub-hkey sub-entry)
|
||||||
(extract-sub-hkey file hkey entry KEY_QUERY_VALUE #f))
|
(extract-sub-hkey file hkey entry KEY_QUERY_VALUE #f))
|
||||||
|
|
||||||
(and sub-hkey
|
(cond
|
||||||
|
[sub-hkey
|
||||||
(begin0
|
(begin0
|
||||||
(let-values ([(len type)
|
(let-values ([(len type)
|
||||||
;; Get size, first
|
;; Get size, first
|
||||||
|
@ -144,28 +188,31 @@
|
||||||
[(= type REG_DWORD)
|
[(= type REG_DWORD)
|
||||||
(number->string (ptr-ref s _DWORD))]
|
(number->string (ptr-ref s _DWORD))]
|
||||||
[else
|
[else
|
||||||
s])]
|
s])])
|
||||||
[to-string (lambda (s)
|
(to-rtype s))])
|
||||||
(if (bytes? s)
|
|
||||||
(bytes->string/utf-8 s #\?)
|
|
||||||
s))])
|
|
||||||
(cond
|
|
||||||
[(eq? rtype 'string) (to-string s)]
|
|
||||||
[(eq? rtype 'integer)
|
|
||||||
(let ([n (string->number (to-string s))])
|
|
||||||
(or (and n (exact-integer? n) n)
|
|
||||||
0))]
|
|
||||||
[else
|
|
||||||
(if (string? s)
|
|
||||||
(string->bytes/utf-8 s)
|
|
||||||
s)]))])
|
|
||||||
(if (box? value)
|
(if (box? value)
|
||||||
(begin
|
(begin
|
||||||
(set-box! value r)
|
(set-box! value r)
|
||||||
#t)
|
#t)
|
||||||
r)))))))
|
r)))))))
|
||||||
(unless (eq? hkey sub-hkey)
|
(unless (eq? hkey sub-hkey)
|
||||||
(RegCloseKey sub-hkey)))))
|
(RegCloseKey sub-hkey)))]
|
||||||
|
[(eq? 'windows (system-type))
|
||||||
|
(let* ([SIZE 1024]
|
||||||
|
[dest (make-bytes (* SIZE 2) 0)]
|
||||||
|
[DEFAULT "$$default"]
|
||||||
|
[len (GetPrivateProfileStringW section entry DEFAULT
|
||||||
|
dest SIZE
|
||||||
|
(file->ini file))])
|
||||||
|
(let ([s (cast dest _pointer _string/utf-16)])
|
||||||
|
(and (not (equal? s DEFAULT))
|
||||||
|
(let ([r (to-rtype s)])
|
||||||
|
(if value
|
||||||
|
(begin
|
||||||
|
(set-box! value r)
|
||||||
|
#t)
|
||||||
|
r)))))]
|
||||||
|
[else #f]))
|
||||||
|
|
||||||
(define (write-resource section entry value [file #f]
|
(define (write-resource section entry value [file #f]
|
||||||
#:type [type 'string]
|
#:type [type 'string]
|
||||||
|
@ -181,18 +228,21 @@
|
||||||
(unless (memq type '(string bytes dword))
|
(unless (memq type '(string bytes dword))
|
||||||
(raise-type-error 'write-resource "'string, 'bytes, or 'dword" type))
|
(raise-type-error 'write-resource "'string, 'bytes, or 'dword" type))
|
||||||
|
|
||||||
(define-values (sub-hkey sub-entry)
|
(define (to-string value)
|
||||||
(extract-sub-hkey file hkey entry KEY_SET_VALUE create-key?))
|
|
||||||
|
|
||||||
(and sub-hkey
|
|
||||||
(begin0
|
|
||||||
(let ([v (case type
|
|
||||||
[(string)
|
|
||||||
(to-utf-16
|
|
||||||
(cond
|
(cond
|
||||||
[(exact-integer? value) (number->string value)]
|
[(exact-integer? value) (number->string value)]
|
||||||
[(string? value) value]
|
[(string? value) value]
|
||||||
[else (bytes->string/utf-8 value #\?)]))]
|
[else (bytes->string/utf-8 value #\?)]))
|
||||||
|
|
||||||
|
(define-values (sub-hkey sub-entry)
|
||||||
|
(extract-sub-hkey file hkey entry KEY_SET_VALUE create-key?))
|
||||||
|
|
||||||
|
(cond
|
||||||
|
[sub-hkey
|
||||||
|
(begin0
|
||||||
|
(let ([v (case type
|
||||||
|
[(string)
|
||||||
|
(to-utf-16 (to-string value))]
|
||||||
[(bytes)
|
[(bytes)
|
||||||
(cond
|
(cond
|
||||||
[(exact-integer? value)
|
[(exact-integer? value)
|
||||||
|
@ -212,7 +262,10 @@
|
||||||
[(dword) REG_DWORD])])
|
[(dword) REG_DWORD])])
|
||||||
(RegSetValueExW sub-hkey sub-entry ty v (bytes-length v)))
|
(RegSetValueExW sub-hkey sub-entry ty v (bytes-length v)))
|
||||||
(unless (eq? hkey sub-hkey)
|
(unless (eq? hkey sub-hkey)
|
||||||
(RegCloseKey sub-hkey)))))
|
(RegCloseKey sub-hkey)))]
|
||||||
|
[(eq? 'windows (system-type))
|
||||||
|
(WritePrivateProfileStringW section entry (to-string value) (file->ini file))]
|
||||||
|
[else #f]))
|
||||||
|
|
||||||
(define (to-utf-16 s)
|
(define (to-utf-16 s)
|
||||||
(let ([v (malloc _gcpointer)])
|
(let ([v (malloc _gcpointer)])
|
||||||
|
|
|
@ -2,14 +2,19 @@
|
||||||
@(require "common.ss"
|
@(require "common.ss"
|
||||||
(for-label file/resource))
|
(for-label file/resource))
|
||||||
|
|
||||||
@(define-syntax-rule (compat section indexed-racket)
|
@(define-syntax-rule (compat file section indexed-racket what)
|
||||||
@elem{For backward compatibilty, the
|
@elem{For backward compatibilty, the
|
||||||
result is @racket[#f] for platforms other than Windows, when
|
result is @racket[#f] for platforms other than Windows. The registry
|
||||||
@racket[file] is not @racket[#f], or when @racket[section] is not
|
is @|what| when
|
||||||
|
@racket[file] is @racket[#f] and when @racket[section] is
|
||||||
@indexed-racket["HKEY_CLASSES_ROOT"],
|
@indexed-racket["HKEY_CLASSES_ROOT"],
|
||||||
@indexed-racket["HKEY_CURRENT_CONFIG"],
|
@indexed-racket["HKEY_CURRENT_CONFIG"],
|
||||||
@indexed-racket["HKEY_CURRENT_USER"],
|
@indexed-racket["HKEY_CURRENT_USER"],
|
||||||
@indexed-racket["HKEY_LOCAL_MACHINE"], or @indexed-racket["HKEY_USERS"].})
|
@indexed-racket["HKEY_LOCAL_MACHINE"], or @indexed-racket["HKEY_USERS"].
|
||||||
|
When @racket[file] is @racket[#f] and @racket[section] is not one of
|
||||||
|
the special registry strings, then
|
||||||
|
@racket[(build-path (find-system-path 'home-dir) "mred.ini")]
|
||||||
|
is @|what|.})
|
||||||
|
|
||||||
@title[#:tag "resource"]{Windows Registry}
|
@title[#:tag "resource"]{Windows Registry}
|
||||||
|
|
||||||
|
@ -22,7 +27,8 @@
|
||||||
[#:type type (or/c 'string 'bytes 'integer) _derived-from-value-box])
|
[#:type type (or/c 'string 'bytes 'integer) _derived-from-value-box])
|
||||||
(or/c #f string? bytes? exact-integer? #t)]{
|
(or/c #f string? bytes? exact-integer? #t)]{
|
||||||
|
|
||||||
Gets a value from the Windows registry. @compat[section indexed-racket]
|
Gets a value from the Windows registry or an @filepath{.ini}
|
||||||
|
file. @compat[file section indexed-racket "read"]
|
||||||
|
|
||||||
The resource value is keyed on the combination of @racket[section] and
|
The resource value is keyed on the combination of @racket[section] and
|
||||||
@racket[entry]. The result is @racket[#f] if no value is found for
|
@racket[entry]. The result is @racket[#f] if no value is found for
|
||||||
|
@ -31,7 +37,7 @@ The resource value is keyed on the combination of @racket[section] and
|
||||||
box is filled with the value; when @racket[value-box] is @racket[#f], the result is the found
|
box is filled with the value; when @racket[value-box] is @racket[#f], the result is the found
|
||||||
value.
|
value.
|
||||||
|
|
||||||
The @racket[type] argument determines how a value in the registry is
|
The @racket[type] argument determines how a value in the resource is
|
||||||
converted to a Racket value. If @racket[value-box] is a box, then the
|
converted to a Racket value. If @racket[value-box] is a box, then the
|
||||||
default @racket[type] is derived from the initial box content,
|
default @racket[type] is derived from the initial box content,
|
||||||
otherwise the default @racket[type] is @racket['string].
|
otherwise the default @racket[type] is @racket['string].
|
||||||
|
@ -40,11 +46,12 @@ Registry values of any format can be extracted. Values using the
|
||||||
registry format @tt{REG_SZ} are treated as strings, and values with
|
registry format @tt{REG_SZ} are treated as strings, and values with
|
||||||
the format @tt{REG_DWORD} are treated as 32-bit signed integers. All
|
the format @tt{REG_DWORD} are treated as 32-bit signed integers. All
|
||||||
other formats are treated as raw bytes. Data from the registry is
|
other formats are treated as raw bytes. Data from the registry is
|
||||||
converted to the requested type @racket[type]:
|
converted to the requested @racket[type] as follows:
|
||||||
|
|
||||||
@itemlist[
|
@itemlist[
|
||||||
|
|
||||||
@item{A @tt{REG_SZ} registry value is converted to an integer using
|
@item{A @tt{REG_SZ} registry value
|
||||||
|
is converted to an integer using
|
||||||
@racket[string->number] (using @racket[0] if the result is not
|
@racket[string->number] (using @racket[0] if the result is not
|
||||||
an exact integer), and it is converted to bytes using
|
an exact integer), and it is converted to bytes using
|
||||||
@racket[string->bytes/utf-8].}
|
@racket[string->bytes/utf-8].}
|
||||||
|
@ -59,9 +66,12 @@ Registry values of any format can be extracted. Values using the
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
To get the ``default'' value for an entry, use a trailing backslash. For
|
Resources from @filepath{.ini} files are always strings, and are
|
||||||
example, the following expression gets a command line for starting a
|
converted like @tt{REG_SZ} registry values.
|
||||||
browser:
|
|
||||||
|
To get the ``default'' value for a registry entry, use a trailing
|
||||||
|
backslash. For example, the following expression gets a command line
|
||||||
|
for starting a browser:
|
||||||
|
|
||||||
@racketblock[
|
@racketblock[
|
||||||
(get-resource "HKEY_CLASSES_ROOT"
|
(get-resource "HKEY_CLASSES_ROOT"
|
||||||
|
@ -76,17 +86,22 @@ browser:
|
||||||
[#:create-key? create-key? any/c #f])
|
[#:create-key? create-key? any/c #f])
|
||||||
boolean?]{
|
boolean?]{
|
||||||
|
|
||||||
Write a value to the Windows registry. @compat[section racket]
|
Write a value to the Windows registry or an @filepath{.ini}
|
||||||
|
file. @compat[file section racket "written"]
|
||||||
|
|
||||||
The resource value is keyed on the combination of @racket[section] and
|
The resource value is keyed on the combination of @racket[section] and
|
||||||
@racket[entry]. If @racket[create-key?] is false, the resource entry
|
@racket[entry]. If @racket[create-key?] is false when writing to the
|
||||||
must already exist, otherwise the write fails. The result is
|
registry, the resource entry must already exist, otherwise the write
|
||||||
@racket[#f] if the write fails or @racket[#t] if it succeeds.
|
fails. The result is @racket[#f] if the write fails or @racket[#t] if
|
||||||
|
it succeeds.
|
||||||
|
|
||||||
The @racket[type] argument determines the format of the value in the
|
The @racket[type] argument determines the format of the value written to the
|
||||||
registry: @racket['string] writes using the @tt{REG_SZ} format,
|
registry: @racket['string] writes using the @tt{REG_SZ} format,
|
||||||
@racket['bytes] writes using the @tt{REG_BINARY} format, and
|
@racket['bytes] writes using the @tt{REG_BINARY} format, and
|
||||||
@racket['dword] writes using the @tt{REG_DWORD} format. Any kind of
|
@racket['dword] writes using the @tt{REG_DWORD} format. Any kind of
|
||||||
@racket[value] can be converted for any kind of @racket[type] using
|
@racket[value] can be converted for any kind of @racket[type] using
|
||||||
the inverse of the conversions for @racket[get-resource].}
|
the inverse of the conversions for @racket[get-resource].
|
||||||
|
|
||||||
|
When writing to an @filepath{.ini} file, the format is always a
|
||||||
|
string, independent of @racket[type].}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
|
|
||||||
(Section 'resource)
|
(Section 'resource)
|
||||||
|
|
||||||
(require file/resource)
|
(require file/resource
|
||||||
|
racket/file)
|
||||||
|
|
||||||
(let ()
|
(let ()
|
||||||
(define key "HKEY_CURRENT_USER")
|
(define key "HKEY_CURRENT_USER")
|
||||||
|
@ -52,8 +53,18 @@
|
||||||
(rtest #"i\377mage" get-resource key (entry "Data") #:type 'bytes)
|
(rtest #"i\377mage" get-resource key (entry "Data") #:type 'bytes)
|
||||||
(rtest 0 get-resource key (entry "Data") #:type 'integer)
|
(rtest 0 get-resource key (entry "Data") #:type 'integer)
|
||||||
|
|
||||||
|
;; .ini file:
|
||||||
|
(let ([tmp-ini (make-temporary-file "temp~a.ini")])
|
||||||
|
(rtest #f get-resource "Temporary" "Stuff" #f tmp-ini)
|
||||||
|
(rtest #t write-resource "Temporary" "Stuff" "howdy" tmp-ini)
|
||||||
|
(rtest "howdy" get-resource "Temporary" "Stuff" #f tmp-ini)
|
||||||
|
(rtest #f get-resource "Temporary" "more" #f tmp-ini)
|
||||||
|
(rtest #t write-resource "Temporary" "more" 10 tmp-ini)
|
||||||
|
(rtest 10 get-resource "Temporary" "more" #f tmp-ini #:type 'integer)
|
||||||
|
(when (eq? 'windows (system-type))
|
||||||
|
(test "[Temporary]\r\nStuff=howdy\r\nmore=10\r\n" file->string tmp-ini)
|
||||||
|
(delete-file tmp-ini)))
|
||||||
|
|
||||||
(void))
|
(void))
|
||||||
|
|
||||||
(report-errs)
|
(report-errs)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user