Module: system-internals Author: Jonathan Bachrach, Gary Palter Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND define constant $architecture-little-endian? :: = #t; define constant $machine-name = #"x86"; define constant $os-name = #"win32"; define constant $DWORD_SIZE = raw-as-integer(primitive-word-size()); define constant $OSVERSIONINFO-SIZE = 5 * $DWORD_SIZE + 128; define constant $VER_PLATFORM_WIN32s = 0; define constant $VER_PLATFORM_WIN32_WINDOWS = 1; define constant $VER_PLATFORM_WIN32_NT = 2; define constant $command-line-option-prefix = '/'; define constant $osversioninfo = method () let buffer :: = make(, size: $OSVERSIONINFO-SIZE, fill: '\0'); primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(buffer)), integer-as-raw(0), integer-as-raw(0)) := integer-as-raw(size(buffer)); %call-c-function ("GetVersionExA", c-modifiers: "__stdcall") (lpOSVersionInfo :: ) => (success? :: ) (primitive-cast-raw-as-pointer(primitive-string-as-raw(buffer))) end; buffer end (); define inline-only function os-platform () => (platform :: ) raw-as-integer(primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer (primitive-string-as-raw($osversioninfo)), integer-as-raw(4), integer-as-raw(0))) end function os-platform; define constant $os-variant = method () select (os-platform()) $VER_PLATFORM_WIN32s => #"win3.1"; $VER_PLATFORM_WIN32_WINDOWS => begin let minorversion = raw-as-integer(primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer (primitive-string-as-raw($osversioninfo)), integer-as-raw(2), integer-as-raw(0))); if (minorversion = 0) #"win95" elseif (minorversion = 10) #"win98" else /* if (minorversion = 90) */ #"winme" end end; $VER_PLATFORM_WIN32_NT => begin let majorversion = raw-as-integer(primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer (primitive-string-as-raw($osversioninfo)), integer-as-raw(1), integer-as-raw(0))); let minorversion = raw-as-integer(primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer (primitive-string-as-raw($osversioninfo)), integer-as-raw(2), integer-as-raw(0))); if (majorversion < 5) #"winnt"; elseif (minorversion = 0) #"win2000" else /* if (minorversion = 1) */ #"winxp" end end end end (); define constant $os-version = method () let majorversion = raw-as-integer(primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer (primitive-string-as-raw($osversioninfo)), integer-as-raw(1), integer-as-raw(0))); let minorversion = raw-as-integer(primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer (primitive-string-as-raw($osversioninfo)), integer-as-raw(2), integer-as-raw(0))); let buildnumber = raw-as-integer(primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer (primitive-string-as-raw($osversioninfo)), integer-as-raw(3), integer-as-raw(0))); if (os-platform() == $VER_PLATFORM_WIN32_WINDOWS) buildnumber := logand(buildnumber, #xFFFF) end; let additionalinfo = begin let buffer = make(); block (return) for (i :: from 0 below 128) let c = raw-as-integer(primitive-c-unsigned-char-at (primitive-cast-raw-as-pointer (primitive-string-as-raw($osversioninfo)), integer-as-raw(i), integer-as-raw(5 * $DWORD_SIZE))); if (c = 0) return (as(, buffer)) else add!(buffer, as(, c)) end end; as(, buffer) end end; let version = concatenate-as(, integer-to-string(majorversion), ".", integer-to-string(minorversion), ".", integer-to-string(buildnumber)); if (size(additionalinfo) > 0) concatenate-as(, version, " ", additionalinfo) else version end end (); define constant $UNLEN = 256; // Maximum username length define function command-line-option-prefix () => (prefix :: ) $command-line-option-prefix end function command-line-option-prefix; define function login-name () => (name :: false-or()) let buffer :: = make(, size: $UNLEN + 1, fill: '\0'); let length :: = make(, size: $DWORD_SIZE, fill: '\0'); primitive-c-unsigned-long-at(primitive-cast-raw-as-pointer(primitive-string-as-raw(length)), integer-as-raw(0), integer-as-raw(0)) := integer-as-raw($UNLEN + 1); if (primitive-raw-as-boolean(%call-c-function ("GetUserNameA", c-modifiers: "__stdcall") (lpBuffer :: , nSize :: ) => (success? :: ) (primitive-cast-raw-as-pointer (primitive-string-as-raw(buffer)), primitive-cast-raw-as-pointer (primitive-string-as-raw(length))) end)) let length = raw-as-integer(primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(length)), integer-as-raw(0), integer-as-raw(0))); copy-sequence(buffer, end: length - 1) else #f end end function login-name; define function login-group () => (group :: false-or()) if (os-platform() == $VER_PLATFORM_WIN32_NT) let name = login-name(); if (name) let sid-buffer :: = make(, size: 1024, fill: '\0'); let sid-buffer-length :: = make(, size: $DWORD_SIZE, fill: '\0'); let sid-use :: = make(, size: $DWORD_SIZE, fill: '\0'); let domain-name :: = make(, size: 1024, fill: '\0'); let domain-name-length :: = make(, size: $DWORD_SIZE, fill: '\0'); primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(sid-buffer-length)), integer-as-raw(0), integer-as-raw(0)) := integer-as-raw(size(sid-buffer)); primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(domain-name-length)), integer-as-raw(0), integer-as-raw(0)) := integer-as-raw(size(domain-name)); if (primitive-raw-as-boolean (%call-c-function ("LookupAccountNameA", c-modifiers: "__stdcall") (lpSystemName :: , lpAccountName :: , Sid :: , cbSid :: , ReferencedDomainName :: , cbReferencedDomainName :: , peUse :: ) => (success? :: ) (primitive-cast-raw-as-pointer(integer-as-raw(0)), primitive-string-as-raw(name), primitive-cast-raw-as-pointer(primitive-string-as-raw(sid-buffer)), primitive-cast-raw-as-pointer(primitive-string-as-raw(sid-buffer-length)), primitive-string-as-raw(domain-name), primitive-cast-raw-as-pointer(primitive-string-as-raw(domain-name-length)), primitive-cast-raw-as-pointer(primitive-string-as-raw(sid-use))) end)) let domain-name-length = raw-as-integer (primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(domain-name-length)), integer-as-raw(0), integer-as-raw(0))); if (~zero?(domain-name-length)) copy-sequence(domain-name, end: domain-name-length) else #f end else #f end else #f end else //---*** Always return #f until we can find an API (or a registry entry) //---*** that returns the user's workgroup/domain under Windows 95/98. #f end end function login-group; define constant $HKEY_LOCAL_MACHINE :: = as(, #x80000002); define constant $KEY_QUERY_VALUE = 1; define constant $ERROR_SUCCESS = 0; define inline-only function current-version-key (name :: ) => (value :: false-or()) block (return) local method doit (key :: , subKey :: , f :: ) => () let handle :: = make(, size: $DWORD_SIZE, fill: '\0'); let valid? :: = #f; block () let status = raw-as-integer(%call-c-function ("RegOpenKeyExA", c-modifiers: "__stdcall") (hKey :: , lpSubKey :: , ulOptions :: , samDesired :: , phkResult :: ) => (success? :: ) (primitive-cast-raw-as-pointer (primitive-unwrap-machine-word(key)), primitive-string-as-raw(subKey), integer-as-raw(0), integer-as-raw($KEY_QUERY_VALUE), primitive-cast-raw-as-pointer (primitive-string-as-raw(handle))) end); if (status = $ERROR_SUCCESS) valid? := #t; f(primitive-wrap-machine-word (primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(handle)), integer-as-raw(0), integer-as-raw(0)))) else return(#f) end; cleanup if (valid?) %call-c-function ("RegCloseKey", c-modifiers: "__stdcall") (hKey :: ) => (success? :: ) (primitive-cast-raw-as-pointer (primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(handle)), integer-as-raw(0), integer-as-raw(0)))) end end end end method doit; doit($HKEY_LOCAL_MACHINE, "Software", method (handle :: ) => () doit(handle, "Microsoft", method (handle :: ) => () doit(handle, if (os-platform() == $VER_PLATFORM_WIN32_NT) "Windows NT" else "Windows" end, method (handle :: ) => () doit(handle, "CurrentVersion", method (handle :: ) => () let type-buffer :: = make(, size: $DWORD_SIZE, fill: '\0'); let buffer-size-buffer :: = make(, size: $DWORD_SIZE, fill: '\0'); let status = raw-as-integer (%call-c-function ("RegQueryValueExA", c-modifiers: "__stdcall") (hKey :: , lpValueName :: , lpReserved :: , lpType :: , lpData :: , lpcbData :: ) => (success? :: ) (primitive-cast-raw-as-pointer (primitive-unwrap-machine-word(handle)), primitive-string-as-raw(name), primitive-cast-raw-as-pointer(integer-as-raw(0)), primitive-cast-raw-as-pointer (primitive-string-as-raw(type-buffer)), primitive-cast-raw-as-pointer(integer-as-raw(0)), primitive-cast-raw-as-pointer (primitive-string-as-raw(buffer-size-buffer))) end); if (status = $ERROR_SUCCESS) let buffer-size = raw-as-integer (primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer (primitive-string-as-raw(buffer-size-buffer)), integer-as-raw(0), integer-as-raw(0))); // NOTE: For registry entries, the returned buffer-size // includes the trailing NUL character ... let buffer :: = make(, size: buffer-size, fill: '\0'); let status = raw-as-integer (%call-c-function ("RegQueryValueExA", c-modifiers: "__stdcall") (hKey :: , lpValueName :: , lpReserved :: , lpType :: , lpData :: , lpcbData :: ) => (success? :: ) (primitive-cast-raw-as-pointer (primitive-unwrap-machine-word(handle)), primitive-string-as-raw(name), primitive-cast-raw-as-pointer(integer-as-raw(0)), primitive-cast-raw-as-pointer (primitive-string-as-raw(type-buffer)), primitive-cast-raw-as-pointer (primitive-string-as-raw(buffer)), primitive-cast-raw-as-pointer (primitive-string-as-raw(buffer-size-buffer))) end); if (status = $ERROR_SUCCESS) return(copy-sequence(buffer, end: buffer-size - 1)) else return(#f) end else return(#f) end end) end) end) end) end end function current-version-key; define function owner-name () => (name :: false-or()) current-version-key("RegisteredOwner") end function owner-name; define function owner-organization () => (organization :: false-or()) current-version-key("RegisteredOrganization") end function owner-organization; define constant $environment-variable-delimiter = ';'; define function environment-variable (name :: ) => (value :: false-or()) let eb-size :: = 1024; let envvar-buffer :: = make(, size: eb-size, fill: '\0'); let envvar-size :: = raw-as-integer(%call-c-function ("GetEnvironmentVariableA", c-modifiers: "__stdcall") (lpName :: , lpBuffer :: , nSize :: ) => (value-size :: ) (primitive-string-as-raw(name), primitive-string-as-raw(envvar-buffer), integer-as-raw(eb-size)) end); if (envvar-size > eb-size) // Value was too large to fit in our initial buffer but GetEnvironmentVariableA // tells us how long it actually is so we can just make a buffer large enough let eb-size :: = envvar-size + 1; envvar-buffer := make(, size: eb-size, fill: '\0'); envvar-size := raw-as-integer(%call-c-function ("GetEnvironmentVariableA", c-modifiers: "__stdcall") (lpName :: , lpBuffer :: , nSize :: ) => (value-size :: ) (primitive-string-as-raw(name), primitive-string-as-raw(envvar-buffer), integer-as-raw(eb-size)) end) end; if (envvar-size > 0) copy-sequence(envvar-buffer, end: envvar-size) else %call-c-function ("SetLastError", c-modifiers: "__stdcall") (dwErrorCode :: ) => (nothing :: ) (integer-as-raw(0)) end; #f end end function environment-variable; define function environment-variable-setter (new-value :: false-or(), name :: ) => (new-value :: false-or()) //---*** Should we signal an error here if this call fails? %call-c-function ("SetEnvironmentVariableA", c-modifiers: "__stdcall") (lpName :: , lpValue :: ) => (success? :: ) (primitive-string-as-raw(name), if (new-value) primitive-string-as-raw(new-value) else integer-as-raw(0) end) end; new-value end function environment-variable-setter; define constant $STARTUPINFO_SIZE = 16 * $DWORD_SIZE; define constant $STARTF_USESHOWWINDOW = 1; define constant $STARTF_USESTDHANDLES = #x00000100; define constant $SW-SHOWNORMAL = 1; define constant $SW-SHOWMINIMIZED = 2; define constant $SW-SHOWNOACTIVATE = 4; define constant $SW-SHOWMINNOACTIVE = 7; define constant $BUFFER-MAX = 4096; define constant $SECURITY_ATTRIBUTES_SIZE = 3 * $DWORD_SIZE; define constant $STD_INPUT_HANDLE = -10; // define constant $STD_OUTPUT_HANDLE = -11; // define constant $STD_ERROR_HANDLE = -12; define constant $WAIT_FAILED = -1; define constant $WAIT_OBJECT_0 = 0; // define constant $WAIT_TIMEOUT = #x102; define inline-only function startupinfo-cb-setter (cb :: , startupinfo :: ) => (cb :: ) primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(startupinfo)), integer-as-raw(0), integer-as-raw(0)) := integer-as-raw(cb); cb end function startupinfo-cb-setter; define inline-only function startupinfo-dwFlags (startupinfo :: ) => (dwFlags :: ) raw-as-integer (primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(startupinfo)), integer-as-raw(11), integer-as-raw(0))) end function startupinfo-dwFlags; define inline-only function startupinfo-dwFlags-setter (dwFlags :: , startupinfo :: ) => (dwFlags :: ) primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(startupinfo)), integer-as-raw(11), integer-as-raw(0)) := integer-as-raw(dwFlags); dwFlags end function startupinfo-dwFlags-setter; define inline-only function startupinfo-wShowWindow-setter (wShowWindow :: , startupinfo :: ) => (wShowWindow :: ) primitive-c-unsigned-short-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(startupinfo)), integer-as-raw(24), integer-as-raw(0)) := integer-as-raw(wShowWindow); wShowWindow end function startupinfo-wShowWindow-setter; define function startupinfo-StdOutput-setter (output-pipe :: , startupinfo :: ) => () let output-pipe-ptr = primitive-cast-raw-as-pointer(primitive-unwrap-machine-word(output-pipe)); let startupinfo-ptr = primitive-cast-raw-as-pointer(primitive-string-as-raw(startupinfo)); primitive-c-unsigned-long-at (startupinfo-ptr, integer-as-raw(14), integer-as-raw(0)) := (%call-c-function ("GetStdHandle", c-modifiers: "__stdcall") (nstdhandle :: ) => (handle :: ) (integer-as-raw($STD_INPUT_HANDLE)) end); primitive-c-pointer-at (startupinfo-ptr, integer-as-raw(15), integer-as-raw(0)) := output-pipe-ptr; primitive-c-pointer-at (startupinfo-ptr, integer-as-raw(16), integer-as-raw(0)) := output-pipe-ptr; end function startupinfo-StdOutput-setter; define constant $PROCESS_INFORMATION_SIZE = 4 * $DWORD_SIZE; define inline-only function process-information-hProcess (process-information :: ) => (hProcess :: ) primitive-wrap-machine-word (primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(process-information)), integer-as-raw(0), integer-as-raw(0))) end function process-information-hProcess; define inline-only function process-information-hThread (process-information :: ) => (hThread :: ) primitive-wrap-machine-word (primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(process-information)), integer-as-raw(1), integer-as-raw(0))) end function process-information-hThread; /// Masks out all but the result code to enable easier comparisions. define constant $HRESULT_CODE_MASK = #x0000FFFF; define inline-only function win32-last-error () => (status :: ) raw-as-integer (primitive-machine-word-logand (%call-c-function ("GetLastError", c-modifiers: "__stdcall") () => (status :: ) () end, integer-as-raw($HRESULT_CODE_MASK))) end function win32-last-error; define function run-application (command :: , #key under-shell? = #f, inherit-console? = #t, activate? = #t, minimize? = #f, outputter :: false-or(), asynchronous? = #f) => (status :: ) let startupInfo :: = make(, size: $STARTUPINFO_SIZE, fill: '\0'); let processInfo :: = make(, size: $PROCESS_INFORMATION_SIZE, fill: '\0'); let command = if (under-shell?) concatenate-as(, environment-variable("COMSPEC"), " /c ", command) else command end; startupinfo-cb(startupInfo) := $STARTUPINFO_SIZE; startupinfo-dwFlags(startupInfo) := $STARTF_USESHOWWINDOW; startupinfo-wShowWindow(startupInfo) := case activate? & minimize? => $SW-SHOWMINIMIZED; activate? & ~minimize? => $SW-SHOWNORMAL; ~activate? & minimize? => $SW-SHOWMINNOACTIVE; ~activate? & ~minimize? => $SW-SHOWNOACTIVATE; // compiler can't figure out that above covers all cases, so thinks // there is a chance of returning #f. Disabuse it of that notion. otherwise => -1; end; let (input-pipe :: , output-pipe :: ) = values(primitive-wrap-machine-word(integer-as-raw(0)), primitive-wrap-machine-word(integer-as-raw(0))); if (outputter) startupinfo-dwFlags(startupInfo) := logior(startupinfo-dwFlags(startupInfo), $STARTF_USESTDHANDLES); inherit-console? := #t; let (input-p, output-p) = Win32CreatePipe(); input-pipe := input-p; output-pipe := output-p; startupinfo-StdOutput(startupInfo) := output-pipe; end if; if (primitive-raw-as-boolean (%call-c-function ("CreateProcessA", c-modifiers: "__stdcall") (lpApplicationName :: , lpCommandLine :: , lpProcessAttributes :: , lpThreadAttributes :: , bInheritHandles :: , dwCreationFlags :: , lpEnvironment :: , lpCurrentDirectory :: , lpStartupInfo :: , lpProcessInformation :: ) => (success? :: ) (integer-as-raw(0), primitive-string-as-raw(command), integer-as-raw(0), integer-as-raw(0), if (inherit-console?) integer-as-raw(1) else integer-as-raw(0) end, integer-as-raw(0), integer-as-raw(0), integer-as-raw(0), primitive-cast-raw-as-pointer(primitive-string-as-raw(startupInfo)), primitive-cast-raw-as-pointer(primitive-string-as-raw(processInfo))) end)) block () if (outputter) let dylan-win32-buffer = make(, size: $BUFFER-MAX, fill: '\0'); let win32-buffer = primitive-wrap-machine-word(primitive-string-as-raw(dylan-win32-buffer)); let actual-transfer = Win32LocalAlloc(); let wait-result = primitive-wrap-machine-word (%call-c-function ("WaitForSingleObject", c-modifiers: "__stdcall") (hHandle :: , dwMilliseconds :: ) => (result :: ) (primitive-cast-raw-as-pointer (primitive-unwrap-machine-word(process-information-hProcess(processInfo))), integer-as-raw(500)) end); if (wait-result == $WAIT_FAILED) win32-last-error() end; let process-is-alive? = wait-result ~= $WAIT_OBJECT_0; while (process-is-alive?) if (Win32PeekNamedPipe(input-pipe, actual-transfer)) let available = raw-as-integer(primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer (primitive-unwrap-machine-word(actual-transfer)), integer-as-raw(0), integer-as-raw(0))); while (~zero?(available)) if (Win32ReadFile(input-pipe, win32-buffer, actual-transfer)) outputter(dylan-win32-buffer, end: raw-as-integer (primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer (primitive-unwrap-machine-word(actual-transfer)), integer-as-raw(0), integer-as-raw(0)))) else win32-last-error() end; if (Win32PeekNamedPipe(input-pipe, actual-transfer)) available := raw-as-integer(primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer (primitive-unwrap-machine-word(actual-transfer)), integer-as-raw(0), integer-as-raw(0))); else win32-last-error() end; end while; else win32-last-error() end if; let wait-result = primitive-wrap-machine-word (%call-c-function ("WaitForSingleObject", c-modifiers: "__stdcall") (hHandle :: , dwMilliseconds :: ) => (result :: ) (primitive-cast-raw-as-pointer (primitive-unwrap-machine-word(process-information-hProcess(processInfo))), integer-as-raw(500)) end); if (wait-result == $WAIT_FAILED) win32-last-error() end; process-is-alive? := wait-result ~= $WAIT_OBJECT_0; end while; // Make sure that the writing end of the pipe is closed, otherwise we // will never terminate when we try to read from the pipe. unless (Win32CloseHandle(output-pipe)) error("Operating System: Run-application: Output Pipe failed to close"); end; // Now copy the last bit of data from the pipe ... while (Win32ReadFile(input-pipe, win32-buffer, actual-transfer)) outputter(dylan-win32-buffer, end: raw-as-integer (primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer (primitive-unwrap-machine-word(actual-transfer)), integer-as-raw(0), integer-as-raw(0)))); end; else unless (asynchronous?) if (primitive-machine-word-equal? (%call-c-function ("WaitForSingleObject", c-modifiers: "__stdcall") (hHandle :: , dwMilliseconds :: ) => (result :: ) (primitive-cast-raw-as-pointer (primitive-unwrap-machine-word(process-information-hProcess(processInfo))), integer-as-raw(-1)) end, integer-as-raw($WAIT_FAILED))) win32-last-error() end end end; if (asynchronous?) 0 else let statusBuffer :: = make(, size: $DWORD_SIZE, fill: '\0'); if (primitive-raw-as-boolean (%call-c-function ("GetExitCodeProcess", c-modifiers: "__stdcall") (hProcess :: , lpExitCode :: ) => (success? :: ) (primitive-cast-raw-as-pointer (primitive-unwrap-machine-word (process-information-hProcess(processInfo))), primitive-cast-raw-as-pointer(primitive-string-as-raw(statusBuffer))) end)) raw-as-integer (primitive-machine-word-logand (primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(statusBuffer)), integer-as-raw(0), integer-as-raw(0)), integer-as-raw($HRESULT_CODE_MASK))) else win32-last-error() end end cleanup unless (asynchronous?) Win32CloseHandle(process-information-hProcess(processInfo)); Win32CloseHandle(process-information-hThread(processInfo)); end; end else win32-last-error() end end function run-application; define function Win32CloseHandle (handle :: ) => (success? :: ) primitive-raw-as-boolean (%call-c-function ("CloseHandle", c-modifiers: "__stdcall") (hHandle :: ) => (closed? :: ) (primitive-cast-raw-as-pointer (primitive-unwrap-machine-word(handle))) end) end function; define inline-only function Win32CreatePipe() => (input-pipe :: , output-pipe :: ) let PipeSecurity :: = make(, size: $SECURITY_ATTRIBUTES_SIZE, fill: '\0'); let PipeSecurity-pointer = primitive-cast-raw-as-pointer(primitive-string-as-raw(PipeSecurity)); primitive-c-unsigned-long-at (PipeSecurity-pointer, integer-as-raw(0), integer-as-raw(0)) := integer-as-raw($SECURITY_ATTRIBUTES_SIZE); primitive-c-unsigned-long-at (PipeSecurity-pointer, integer-as-raw(2), integer-as-raw(0)) := integer-as-raw(1); let input-pipe = primitive-cast-raw-as-pointer(primitive-unwrap-machine-word(Win32LocalAlloc())); let output-pipe = primitive-cast-raw-as-pointer(primitive-unwrap-machine-word(Win32LocalAlloc())); %call-c-function ("CreatePipe", c-modifiers: "__stdcall") (OutPipeRead :: , OutPipeWrite :: , PipeSecurity :: , unknown :: ) => (created? :: ) (input-pipe, output-pipe, PipeSecurity-pointer, integer-as-raw($BUFFER-MAX)) end; values(primitive-wrap-machine-word (primitive-c-unsigned-long-at (input-pipe, integer-as-raw(0), integer-as-raw(0))), primitive-wrap-machine-word (primitive-c-unsigned-long-at (output-pipe, integer-as-raw(0), integer-as-raw(0)))) end function; // Can be used to see if there's input available on an anonymous pipe ... define inline-only function Win32PeekNamedPipe (input-pipe :: , bytes-available :: ) => (success? :: ) primitive-raw-as-boolean (%call-c-function ("PeekNamedPipe", c-modifiers: "__stdcall") (hNamedPipe :: , lpBuffer :: , nBufferSize :: , lpBytesRead :: , lpTotalBytesAvail :: , lpBytesLeftThisMessage :: ) => (success? :: ) (primitive-cast-raw-as-pointer(primitive-unwrap-machine-word(input-pipe)), primitive-cast-raw-as-pointer(integer-as-raw(0)), integer-as-raw(0), primitive-cast-raw-as-pointer(integer-as-raw(0)), primitive-cast-raw-as-pointer(primitive-unwrap-machine-word(bytes-available)), primitive-cast-raw-as-pointer(integer-as-raw(0))) end) end function Win32PeekNamedPipe; define inline-only function Win32LocalAlloc() => (c-pointer :: ) primitive-wrap-machine-word (primitive-cast-pointer-as-raw (%call-c-function ("LocalAlloc", c-modifiers: "__stdcall") (flags :: , bytes :: ) => (pointer :: ) (integer-as-raw(0), integer-as-raw(4)) end)); end function; define inline-only function Win32ReadFile (handle :: , buffer :: , actual-transfer :: ) => (success? :: ) primitive-raw-as-boolean (%call-c-function ("ReadFile", c-modifiers: "__stdcall") (handle :: , buffer-ptr :: , count :: , actual-count :: , lpOverlapped :: ) => (success? :: ) (primitive-cast-raw-as-pointer(primitive-unwrap-machine-word(handle)), primitive-cast-raw-as-pointer(primitive-unwrap-machine-word(buffer)), integer-as-raw($BUFFER-MAX), primitive-cast-raw-as-pointer (primitive-unwrap-machine-word(actual-transfer)), primitive-cast-raw-as-pointer(integer-as-raw(0))) end); end function; /* define inline-only function Win32WriteFile (handle :: false-or(), buffer :: , actual-transfer :: , dummy-transfer :: ) => (success? :: ) if (handle) primitive-raw-as-boolean (%call-c-function ("WriteFile", c-modifiers: "__stdcall") (handle :: , buffer-ptr :: , count :: , actual-count :: , lpOverlapped :: ) => (success? :: ) (primitive-cast-raw-as-pointer(primitive-unwrap-machine-word(handle)), primitive-cast-raw-as-pointer(primitive-unwrap-machine-word(buffer)), primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer(primitive-unwrap-machine-word(actual-transfer)), integer-as-raw(0), integer-as-raw(0)), primitive-cast-raw-as-pointer(primitive-unwrap-machine-word(dummy-transfer)), primitive-cast-raw-as-pointer(integer-as-raw(0))) end); end if; end function; */ /// Inter-Process Synchronization tools define function create-application-event (event :: ) => (event-object :: ) primitive-wrap-machine-word (%call-c-function ("CreateEventA", c-modifiers: "__stdcall") (lpEventAttributes :: , bManualReset :: , bInitialState :: , lpName :: ) => (handle :: ) (primitive-cast-raw-as-pointer(integer-as-raw(0)), integer-as-raw(0), integer-as-raw(0), primitive-cast-raw-as-pointer(primitive-string-as-raw(event))) end); end function; define constant $INFINITE_TIMEOUT = -1; define function wait-for-application-event (event-object :: , #key timeout :: = $INFINITE_TIMEOUT) => (success? :: ) let wait-result = primitive-wrap-machine-word (%call-c-function ("WaitForSingleObject", c-modifiers: "__stdcall") (hHandle :: , dwMilliseconds :: ) => (result :: ) (primitive-cast-raw-as-pointer (primitive-unwrap-machine-word(event-object)), integer-as-raw(timeout)) end); %call-c-function ("CloseHandle", c-modifiers: "__stdcall") (hHandle :: ) => (result :: ) (primitive-cast-raw-as-pointer (primitive-unwrap-machine-word(event-object))) end; if (wait-result == $WAIT_FAILED) #f else #t end; end function; define constant $STANDARD_RIGHTS_REQUIRED = #x000F0000; define constant $SYNCHRONIZE = #x00100000; define constant $EVENT_ALL_ACCESS = logior($STANDARD_RIGHTS_REQUIRED, $SYNCHRONIZE, #x03); define function signal-application-event (event :: ) => (success? :: ) let event-object = primitive-wrap-machine-word (%call-c-function ("OpenEventA", c-modifiers: "__stdcall") (dwDesiredAccess :: , bInheritHandle :: , lpName :: ) => (handle :: ) (integer-as-raw($EVENT_ALL_ACCESS), integer-as-raw(0), primitive-cast-raw-as-pointer(primitive-string-as-raw(event))) end); let success? :: = primitive-raw-as-boolean (%call-c-function ("SetEvent", c-modifiers: "__stdcall") (hHandle :: ) => (result :: ) (primitive-cast-raw-as-pointer (primitive-unwrap-machine-word(event-object))) end); %call-c-function ("CloseHandle", c-modifiers: "__stdcall") (hHandle :: ) => (result :: ) (primitive-cast-raw-as-pointer (primitive-unwrap-machine-word(event-object))) end; success? end function; define function load-library (name :: ) => (module) let module = primitive-wrap-machine-word (%call-c-function ("LoadLibraryA", c-modifiers: "__stdcall") (lpName :: ) => (handle :: ) (primitive-cast-raw-as-pointer(primitive-string-as-raw(name))) end); module end function;