-
-
Save Varriount/5ec6370dd37bb51cd947 to your computer and use it in GitHub Desktop.
I don't know how I fixed it, but I did. Also, keep in mind that when taking the address of parameters, the parameters must be passed by ref or ptr
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import os, oids, strutils, winlean, socketsll | |
| from windows import nil | |
| ## Proactor | |
| ## -------- | |
| ## | |
| ## This module implements the proactor pattern, unlike selectors the | |
| ## asynchronous I/O operation is first initiated and then waited upon. | |
| # Wrapped API Structures | |
| type | |
| TGUID* {.final, pure.} = object | |
| D1*: int32 | |
| D2*: int16 | |
| D3*: int16 | |
| D4*: array [0..7, int8] | |
| Overlapped* {.final, pure.} = object | |
| ## Be very careful when passing this object around. An overlapped object | |
| ## passed to a windows API call like connectEx MUST remain allocated at | |
| ## the same address untils internal window mechanisms are done with it. | |
| ## Such mechanisms include the Completion Queues, events, etc. | |
| Internal*: ptr LONG | |
| InternalHigh*: ptr LONG | |
| Offset*: DWORD | |
| OffsetHigh*: DWORD | |
| hEvent*: THandle | |
| POverlapped* {.final, pure.} = ptr Overlapped | |
| CompletionRoutine {.final, pure.} = proc ( | |
| dwError, cbTransferred : DWORD, | |
| lpOverlapped: POverlapped, | |
| dwFlags: DWORD | |
| ) | |
| ConnectExProc* {.final, pure.} = proc ( | |
| socket: TSocketHandle, | |
| name: ptr TSockAddr, | |
| namelen: cint, | |
| lpSendBuffer: pointer, dwSendDataLength: DWORD, | |
| lpdwBytesSent: ptr DWORD, | |
| lpOverlapped: POverlapped | |
| ): bool {.stdcall.} | |
| const | |
| IOC_OUT = 0x40000000 | |
| IOC_IN = 0x80000000 | |
| IOC_WS2 = 0x08000000 | |
| IOC_INOUT = IOC_IN or IOC_OUT | |
| template WSAIORW(x,y): expr = (IOC_INOUT or x or y) | |
| const | |
| SIO_GET_EXTENSION_FUNCTION_POINTER* = WSAIORW(IOC_WS2,6).DWORD | |
| var | |
| WSAID_CONNECTEX* = TGUID( | |
| D1: 0x25a207b9, | |
| D2: 0xddf3'i16, | |
| D3: 0x4660'i16, | |
| D4: [0x8e'i8, 0xe9'i8, 0x76'i8, 0xe5'i8, | |
| 0x8c'i8, 0x74'i8, 0x06'i8, 0x3e'i8] | |
| ) | |
| # Wrapped API Procedures | |
| proc CreateIoCompletionPort*(FileHandle: THandle, ExistingCompletionPort: THandle, | |
| CompletionKey: ptr LONG, | |
| NumberOfConcurrentThreads: DWORD): THandle{.stdcall, | |
| dynlib: "kernel32", importc: "CreateIoCompletionPort".} | |
| proc GetQueuedCompletionStatus*(CompletionPort: THandle, | |
| lpNumberOfBytesTransferred: ptr DWORD, lpCompletionKey: ptr int, | |
| lpOverlapped: ptr POverlapped, | |
| dwMilliseconds: DWORD): WINBOOL{.stdcall, | |
| dynlib: "kernel32", importc: "GetQueuedCompletionStatus".} | |
| proc WSAIoctl*(s: TSocketHandle, dwIoControlCode: DWORD, lpvInBuffer: pointer, | |
| cbInBuffer: DWORD, lpvOutBuffer: pointer, cbOutBuffer: dword, | |
| lpcbBytesReturned: ptr DWORD, lpOverlapped: POverlapped, | |
| lpCompletionRoutine: CompletionRoutine): cint {.stdcall, importc: "WSAIoctl", dynlib: "Ws2_32.dll".} | |
| # Helper Structures and Procedures | |
| var | |
| nilKey: LONG | |
| nilHandle: THandle | |
| overlappedStruct: Overlapped | |
| proc createIOCP(maxThreads: int32 = 0): THandle = | |
| result = CreateIoCompletionPort( | |
| INVALID_HANDLE_VALUE, | |
| nilHandle, | |
| addr nilKey, | |
| 0 | |
| ) | |
| proc addHandle(iocp, hFile: THandle, key: var LONG = nilKey): THandle = | |
| result = CreateIoCompletionPort( | |
| hFile, | |
| iocp, | |
| addr key, | |
| 0) | |
| proc getConnectEx*(s: TSocketHandle, guid: var TGUID): ConnectExProc = | |
| # Ref: https://github.com/powdahound/twisted/blob/master/twisted/internet/iocpreactor/iocpsupport/winsock_pointers.c | |
| var bytesRet: DWORD | |
| var connectExPtr: pointer = nil | |
| let state = WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, addr guid, | |
| sizeof(TGUID).dword, addr connectExPtr, sizeof(pointer).DWORD, | |
| addr bytesRet, nil, nil) == 0 | |
| if not state: | |
| assert(false) | |
| result = cast[ConnectExProc](connectExPtr) | |
| # Other stuff | |
| type | |
| TCompletionKey {.pure.} = dword | |
| TCompletionData = object | |
| sock: TSocketHandle | |
| cb: proc (sock: TSocketHandle) {.closure.} | |
| PProactor* {.pure.} = ref object | |
| ioPort: THandle | |
| overlapps: seq[Overlapped] | |
| keys: seq[TCompletionKey] | |
| datas: seq[TCompletionData] | |
| PFuture*[T] = ref object | |
| value*: T | |
| finished*: bool | |
| cb: proc (future: PFuture[T]) {.closure.} | |
| proc newProactor*(): PProactor = | |
| ## Creates a new proactor instance. | |
| new result | |
| result.overlapps = newSeq[Overlapped](16) | |
| result.keys = newSeq[TCompletionKey]() | |
| result.datas = newSeq[TCompletionData]() | |
| result.ioPort = createIOCP() | |
| proc register*(p: PProactor, sock: TSocketHandle) = | |
| # If sock is a local copy, and it's address is given as a key, | |
| # what happens when it goes out of scope? | |
| discard p.ioPort.addHandle(sock.THandle) | |
| if OSLastError().int32 != 0'i32: | |
| OSError(OSLastError()) | |
| proc setCallback*(p: PProactor, sock: TSocketHandle, cb: proc (sock: TSocketHandle) {.closure.}) = | |
| ## Sets the proc to call when a completion event is received for ``sock``. | |
| echo("Setting callback with key: ", $sock.int) | |
| p.keys.add(sock.TCompletionKey) | |
| echo("Middle") | |
| var tdata: TCompletionData | |
| tdata.sock = sock | |
| tdata.cb = cb | |
| p.datas.add(tdata) | |
| echo("End") | |
| proc poll*(p: PProactor, timeout = 500) = | |
| let llTimeout = | |
| if timeout == -1: windows.INFINITE | |
| else: timeout.int32 | |
| var | |
| bytesTransferred:DWORD | |
| key: LONG | |
| statusOverlapped: Overlapped | |
| statusOverlappedPtr = addr statusOverlapped | |
| keyPtr = addr key | |
| echo(repr(p.ioPort)) | |
| var res = GetQueuedCompletionStatus( | |
| p.ioPort, | |
| addr bytesTransferred, | |
| keyPtr, | |
| addr statusOverlappedPtr, | |
| llTimeout.DWORD | |
| ) | |
| key = keyPtr[] | |
| if res.bool: | |
| # We got a completion event. | |
| echo("Got a completion event: ", key) | |
| let dataIndex = p.keys.find(key.TCompletionKey) | |
| if dataIndex < 0: | |
| echo("Possible error: ", dataIndex) | |
| let data = p.datas[0] | |
| data.cb(data.sock) | |
| else: | |
| var errCode = OSLastError() | |
| if errCode.int32 == WAIT_TIMEOUT: | |
| # Timed out | |
| nil | |
| else: OSError(errCode) | |
| # -- Futures | |
| proc newFuture*[T](): PFuture[T] = | |
| new(result) | |
| result.finished = false | |
| proc complete*[T](future: PFuture[T], val: T) = | |
| assert(not future.finished) | |
| future.value = val | |
| future.finished = true | |
| if future.cb != nil: | |
| future.cb(future) | |
| proc `callback=`*[T](future: PFuture[T], | |
| cb: proc (future: PFuture[T]) {.closure.}) = | |
| ## Sets the callback proc to be called when the future completes. | |
| ## | |
| ## If future has already completed then ``cb`` will be called immediately. | |
| future.cb = cb | |
| if future.finished: | |
| future.cb(future) | |
| # template WSAIORW(x,y): expr = (IOC_INOUT or x or y) | |
| # const | |
| # SIO_GET_EXTENSION_FUNCTION_POINTER = WSAIORW(IOC_WS2,6).DWORD | |
| # var | |
| # WSAID_CONNECTEX: TGUID = TGUID(D1: 0x25a207b9, D2: 0xddf3'i16, D3: 0x4660, D4: [ | |
| # 0x8e'i8, 0xe9'i8, 0x76'i8, 0xe5'i8, 0x8c'i8, 0x74'i8, | |
| # 0x06'i8, 0x3e'i8]) | |
| var connectEx: pointer = nil | |
| proc initPointer*(s: TSocketHandle, func: var pointer, guid: var TGUID): bool = | |
| # Ref: https://github.com/powdahound/twisted/blob/master/twisted/internet/iocpreactor/iocpsupport/winsock_pointers.c | |
| var bytesRet: DWord | |
| func = nil | |
| result = WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, addr guid, | |
| sizeof(TGUID).dword, addr func, sizeof(pointer).DWORD, | |
| addr bytesRet, nil, nil) == 0 | |
| proc initAll*() = | |
| connectEx = getConnectEx(socket(), WSAID_CONNECTEX) | |
| proc connect(p: PProactor, ssocket: TSocketHandle, address: string, port: TPort, | |
| af = AF_INET): PFuture[int] = | |
| ## Connects ``socket`` to server at ``address:port``. | |
| ## | |
| ## Returns a ``PFuture`` which will complete when the connection succeeds | |
| ## or an error occurs. | |
| let dummySocket = socket() | |
| let connectExPtr = getConnectEx(dummySocket, WSAID_CONNECTEX) | |
| var retFuture = newFuture[int]()# TODO: Change to void when that regression is fixed. | |
| # Apparently ``ConnectEx`` expects the socket to be initially bound: | |
| var sockAddress: Tsockaddr_in | |
| var sockAddressPtr = cast[ptr TSockAddr](addr(sockAddress)) | |
| sockAddress.sin_family = int16(toInt(AF_INET)) | |
| sockAddress.sin_port = 0 | |
| sockAddress.sin_addr.s_addr = INADDR_ANY | |
| if bindSocket(ssocket, sockAddressPtr, sizeof(sockAddress).TSockLen) < 0'i32: | |
| OSError(OSLastError()) | |
| var aiList = getAddrInfo(address, port, af) | |
| var success = false | |
| var lastError: TOSErrorCode | |
| var it = aiList | |
| while it != nil: | |
| when true: | |
| var ret = connectExPtr(ssocket, it.ai_addr, sizeof(TSockAddrIn).cint, | |
| nil, 0, nil, addr overlappedStruct) | |
| else: | |
| var ol = cast[ptr TOverlapped](alloc0(sizeof(TOverlapped))) | |
| var ret = connectEx(socket, it.ai_addr, sizeof(TSockAddrIn).cint, | |
| nil, 0, nil, ol) | |
| dealloc(ol) | |
| if ret: | |
| echo "Connected" | |
| success = true | |
| retFuture.finished = true | |
| break | |
| else: | |
| lastError = OSLastError() | |
| when defined(windows): | |
| if lastError.int32 == windows.ERROR_IO_PENDING or lastError.int32 == 0: | |
| success = true | |
| p.setCallback(ssocket, | |
| proc (sock: TSocketHandle) {.closure.} = | |
| echo("Connected") | |
| retFuture.complete(0) | |
| ) | |
| break | |
| else: | |
| OSError(lastError) | |
| it = it.ai_next | |
| dealloc(aiList) | |
| if not success: OSError(lastError) | |
| return retFuture | |
| when isMainModule: | |
| initAll() | |
| var p = newProactor() | |
| var sock = socket() | |
| #sock.setBlocking false | |
| p.register(sock) | |
| var f = p.connect(sock, "irc.freenode.net", TPort(6667)) | |
| f.callback = proc (future: PFuture[int]) = echo("Connected in future!") | |
| #p.recv(sock, 10) | |
| while true: | |
| p.poll() | |
| echo "polled" | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # | |
| # | |
| # Nimrod's Runtime Library | |
| # (c) Copyright 2014 Dominik Picheta | |
| # | |
| # See the file "copying.txt", included in this | |
| # distribution, for details about the copyright. | |
| # | |
| ## This module implements a low-level cross-platform sockets interface. Look | |
| ## at the ``net`` module for the higher-level version. | |
| import unsigned, os | |
| when hostos == "solaris": | |
| {.passl: "-lsocket -lnsl".} | |
| when defined(Windows): | |
| import winlean | |
| else: | |
| import posix | |
| type | |
| TPort* = distinct uint16 ## port type | |
| TDomain* = enum ## domain, which specifies the protocol family of the | |
| ## created socket. Other domains than those that are listed | |
| ## here are unsupported. | |
| AF_UNIX, ## for local socket (using a file). Unsupported on Windows. | |
| AF_INET = 2, ## for network protocol IPv4 or | |
| AF_INET6 = 23 ## for network protocol IPv6. | |
| TType* = enum ## second argument to `socket` proc | |
| SOCK_STREAM = 1, ## reliable stream-oriented service or Stream Sockets | |
| SOCK_DGRAM = 2, ## datagram service or Datagram Sockets | |
| SOCK_RAW = 3, ## raw protocols atop the network layer. | |
| SOCK_SEQPACKET = 5 ## reliable sequenced packet service | |
| TProtocol* = enum ## third argument to `socket` proc | |
| IPPROTO_TCP = 6, ## Transmission control protocol. | |
| IPPROTO_UDP = 17, ## User datagram protocol. | |
| IPPROTO_IP, ## Internet protocol. Unsupported on Windows. | |
| IPPROTO_IPV6, ## Internet Protocol Version 6. Unsupported on Windows. | |
| IPPROTO_RAW, ## Raw IP Packets Protocol. Unsupported on Windows. | |
| IPPROTO_ICMP ## Control message protocol. Unsupported on Windows. | |
| TServent* {.pure, final.} = object ## information about a service | |
| name*: string | |
| aliases*: seq[string] | |
| port*: TPort | |
| proto*: string | |
| Thostent* {.pure, final.} = object ## information about a given host | |
| name*: string | |
| aliases*: seq[string] | |
| addrtype*: TDomain | |
| length*: int | |
| addrList*: seq[string] | |
| when defined(windows): | |
| let | |
| OSInvalidSocket* = winlean.INVALID_SOCKET | |
| else: | |
| let | |
| OSInvalidSocket* = posix.INVALID_SOCKET | |
| proc `==`*(a, b: TPort): bool {.borrow.} | |
| ## ``==`` for ports. | |
| proc `$`*(p: TPort): string {.borrow.} | |
| ## returns the port number as a string | |
| proc toInt*(domain: TDomain): cint | |
| ## Converts the TDomain enum to a platform-dependent ``cint``. | |
| proc toInt*(typ: TType): cint | |
| ## Converts the TType enum to a platform-dependent ``cint``. | |
| proc toInt*(p: TProtocol): cint | |
| ## Converts the TProtocol enum to a platform-dependent ``cint``. | |
| when defined(posix): | |
| proc toInt(domain: TDomain): cint = | |
| case domain | |
| of AF_UNIX: result = posix.AF_UNIX | |
| of AF_INET: result = posix.AF_INET | |
| of AF_INET6: result = posix.AF_INET6 | |
| else: nil | |
| proc toInt(typ: TType): cint = | |
| case typ | |
| of SOCK_STREAM: result = posix.SOCK_STREAM | |
| of SOCK_DGRAM: result = posix.SOCK_DGRAM | |
| of SOCK_SEQPACKET: result = posix.SOCK_SEQPACKET | |
| of SOCK_RAW: result = posix.SOCK_RAW | |
| else: nil | |
| proc toInt(p: TProtocol): cint = | |
| case p | |
| of IPPROTO_TCP: result = posix.IPPROTO_TCP | |
| of IPPROTO_UDP: result = posix.IPPROTO_UDP | |
| of IPPROTO_IP: result = posix.IPPROTO_IP | |
| of IPPROTO_IPV6: result = posix.IPPROTO_IPV6 | |
| of IPPROTO_RAW: result = posix.IPPROTO_RAW | |
| of IPPROTO_ICMP: result = posix.IPPROTO_ICMP | |
| else: nil | |
| else: | |
| proc toInt(domain: TDomain): cint = | |
| result = toU16(ord(domain)) | |
| proc toInt(typ: TType): cint = | |
| result = cint(ord(typ)) | |
| proc toInt(p: TProtocol): cint = | |
| result = cint(ord(p)) | |
| proc socket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM, | |
| protocol: TProtocol = IPPROTO_TCP): TSocketHandle = | |
| ## Creates a new socket; returns `InvalidSocket` if an error occurs. | |
| # TODO: The function which will use this will raise EOS. | |
| socket(toInt(domain), toInt(typ), toInt(protocol)) | |
| proc close*(socket: TSocketHandle) = | |
| ## closes a socket. | |
| when defined(windows): | |
| discard winlean.closeSocket(socket) | |
| else: | |
| discard posix.close(socket) | |
| # TODO: These values should not be discarded. An EOS should be raised. | |
| # http://stackoverflow.com/questions/12463473/what-happens-if-you-call-close-on-a-bsd-socket-multiple-times | |
| proc getAddrInfo*(address: string, port: TPort, af: TDomain = AF_INET, typ: TType = SOCK_STREAM, | |
| prot: TProtocol = IPPROTO_TCP): ptr TAddrInfo = | |
| ## **Warning**: The resulting ``ptr TAddrInfo`` must be freed using ``dealloc``! | |
| # Set up the address hints structure | |
| var hints: TAddrInfo | |
| hints.ai_family = toInt(af) | |
| hints.ai_socktype = toInt(typ) | |
| hints.ai_protocol = toInt(prot) | |
| # Get the address info structure | |
| var addressInfoPtr: ptr TAddrInfo | |
| var gaiResult = getAddrInfo(address, $port, addr hints, addressInfoPtr) | |
| if gaiResult != 0'i32: | |
| when defined(windows): | |
| OSError(OSLastError()) | |
| else: | |
| raise newException(EOS, $gai_strerror(gaiResult)) | |
| return addressInfoPtr | |
| proc dealloc*(ai: ptr TAddrInfo) = | |
| freeaddrinfo(ai) | |
| when defined(Windows): | |
| var wsa: TWSADATA | |
| if WSAStartup(0x0101'i16, addr wsa) != 0: OSError(OSLastError()) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # | |
| # | |
| # Nimrod's Runtime Library | |
| # (c) Copyright 2012 Andreas Rumpf | |
| # | |
| # See the file "copying.txt", included in this | |
| # distribution, for details about the copyright. | |
| # | |
| ## This module implements a small wrapper for some needed Win API procedures, | |
| ## so that the Nimrod compiler does not depend on the huge Windows module. | |
| const | |
| useWinUnicode* = not defined(useWinAnsi) | |
| type | |
| THandle* = int | |
| LONG* = int32 | |
| WINBOOL* = int32 | |
| DWORD* = int32 | |
| HDC* = THandle | |
| HGLRC* = THandle | |
| TSECURITY_ATTRIBUTES* {.final, pure.} = object | |
| nLength*: int32 | |
| lpSecurityDescriptor*: pointer | |
| bInheritHandle*: WINBOOL | |
| TSTARTUPINFO* {.final, pure.} = object | |
| cb*: int32 | |
| lpReserved*: cstring | |
| lpDesktop*: cstring | |
| lpTitle*: cstring | |
| dwX*: int32 | |
| dwY*: int32 | |
| dwXSize*: int32 | |
| dwYSize*: int32 | |
| dwXCountChars*: int32 | |
| dwYCountChars*: int32 | |
| dwFillAttribute*: int32 | |
| dwFlags*: int32 | |
| wShowWindow*: int16 | |
| cbReserved2*: int16 | |
| lpReserved2*: pointer | |
| hStdInput*: THandle | |
| hStdOutput*: THandle | |
| hStdError*: THandle | |
| TPROCESS_INFORMATION* {.final, pure.} = object | |
| hProcess*: THandle | |
| hThread*: THandle | |
| dwProcessId*: int32 | |
| dwThreadId*: int32 | |
| TFILETIME* {.final, pure.} = object ## CANNOT BE int64 BECAUSE OF ALIGNMENT | |
| dwLowDateTime*: DWORD | |
| dwHighDateTime*: DWORD | |
| TBY_HANDLE_FILE_INFORMATION* {.final, pure.} = object | |
| dwFileAttributes*: DWORD | |
| ftCreationTime*: TFILETIME | |
| ftLastAccessTime*: TFILETIME | |
| ftLastWriteTime*: TFILETIME | |
| dwVolumeSerialNumber*: DWORD | |
| nFileSizeHigh*: DWORD | |
| nFileSizeLow*: DWORD | |
| nNumberOfLinks*: DWORD | |
| nFileIndexHigh*: DWORD | |
| nFileIndexLow*: DWORD | |
| when useWinUnicode: | |
| type TWinChar* = TUtf16Char | |
| else: | |
| type TWinChar* = char | |
| const | |
| STARTF_USESHOWWINDOW* = 1'i32 | |
| STARTF_USESTDHANDLES* = 256'i32 | |
| HIGH_PRIORITY_CLASS* = 128'i32 | |
| IDLE_PRIORITY_CLASS* = 64'i32 | |
| NORMAL_PRIORITY_CLASS* = 32'i32 | |
| REALTIME_PRIORITY_CLASS* = 256'i32 | |
| WAIT_OBJECT_0* = 0'i32 | |
| WAIT_TIMEOUT* = 0x00000102'i32 | |
| WAIT_FAILED* = 0xFFFFFFFF'i32 | |
| INFINITE* = -1'i32 | |
| STD_INPUT_HANDLE* = -10'i32 | |
| STD_OUTPUT_HANDLE* = -11'i32 | |
| STD_ERROR_HANDLE* = -12'i32 | |
| DETACHED_PROCESS* = 8'i32 | |
| SW_SHOWNORMAL* = 1'i32 | |
| INVALID_HANDLE_VALUE* = THandle(-1) | |
| CREATE_UNICODE_ENVIRONMENT* = 1024'i32 | |
| proc closeHandle*(hObject: THandle): WINBOOL {.stdcall, dynlib: "kernel32", | |
| importc: "CloseHandle".} | |
| proc readFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToRead: int32, | |
| lpNumberOfBytesRead: var int32, lpOverlapped: pointer): WINBOOL{. | |
| stdcall, dynlib: "kernel32", importc: "ReadFile".} | |
| proc writeFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToWrite: int32, | |
| lpNumberOfBytesWritten: var int32, | |
| lpOverlapped: pointer): WINBOOL{. | |
| stdcall, dynlib: "kernel32", importc: "WriteFile".} | |
| proc createPipe*(hReadPipe, hWritePipe: var THandle, | |
| lpPipeAttributes: var TSECURITY_ATTRIBUTES, | |
| nSize: int32): WINBOOL{. | |
| stdcall, dynlib: "kernel32", importc: "CreatePipe".} | |
| when useWinUnicode: | |
| proc createProcessW*(lpApplicationName, lpCommandLine: WideCString, | |
| lpProcessAttributes: ptr TSECURITY_ATTRIBUTES, | |
| lpThreadAttributes: ptr TSECURITY_ATTRIBUTES, | |
| bInheritHandles: WINBOOL, dwCreationFlags: int32, | |
| lpEnvironment, lpCurrentDirectory: WideCString, | |
| lpStartupInfo: var TSTARTUPINFO, | |
| lpProcessInformation: var TPROCESS_INFORMATION): WINBOOL{. | |
| stdcall, dynlib: "kernel32", importc: "CreateProcessW".} | |
| else: | |
| proc createProcessA*(lpApplicationName, lpCommandLine: cstring, | |
| lpProcessAttributes: ptr TSECURITY_ATTRIBUTES, | |
| lpThreadAttributes: ptr TSECURITY_ATTRIBUTES, | |
| bInheritHandles: WINBOOL, dwCreationFlags: int32, | |
| lpEnvironment: pointer, lpCurrentDirectory: cstring, | |
| lpStartupInfo: var TSTARTUPINFO, | |
| lpProcessInformation: var TPROCESS_INFORMATION): WINBOOL{. | |
| stdcall, dynlib: "kernel32", importc: "CreateProcessA".} | |
| proc suspendThread*(hThread: THandle): int32 {.stdcall, dynlib: "kernel32", | |
| importc: "SuspendThread".} | |
| proc resumeThread*(hThread: THandle): int32 {.stdcall, dynlib: "kernel32", | |
| importc: "ResumeThread".} | |
| proc waitForSingleObject*(hHandle: THandle, dwMilliseconds: int32): int32 {. | |
| stdcall, dynlib: "kernel32", importc: "WaitForSingleObject".} | |
| proc terminateProcess*(hProcess: THandle, uExitCode: int): WINBOOL {.stdcall, | |
| dynlib: "kernel32", importc: "TerminateProcess".} | |
| proc getExitCodeProcess*(hProcess: THandle, lpExitCode: var int32): WINBOOL {. | |
| stdcall, dynlib: "kernel32", importc: "GetExitCodeProcess".} | |
| proc getStdHandle*(nStdHandle: int32): THandle {.stdcall, dynlib: "kernel32", | |
| importc: "GetStdHandle".} | |
| proc setStdHandle*(nStdHandle: int32, hHandle: THandle): WINBOOL {.stdcall, | |
| dynlib: "kernel32", importc: "SetStdHandle".} | |
| proc flushFileBuffers*(hFile: THandle): WINBOOL {.stdcall, dynlib: "kernel32", | |
| importc: "FlushFileBuffers".} | |
| proc getLastError*(): int32 {.importc: "GetLastError", | |
| stdcall, dynlib: "kernel32".} | |
| when useWinUnicode: | |
| proc formatMessageW*(dwFlags: int32, lpSource: pointer, | |
| dwMessageId, dwLanguageId: int32, | |
| lpBuffer: pointer, nSize: int32, | |
| Arguments: pointer): int32 {. | |
| importc: "FormatMessageW", stdcall, dynlib: "kernel32".} | |
| else: | |
| proc formatMessageA*(dwFlags: int32, lpSource: pointer, | |
| dwMessageId, dwLanguageId: int32, | |
| lpBuffer: pointer, nSize: int32, | |
| Arguments: pointer): int32 {. | |
| importc: "FormatMessageA", stdcall, dynlib: "kernel32".} | |
| proc localFree*(p: pointer) {. | |
| importc: "LocalFree", stdcall, dynlib: "kernel32".} | |
| when useWinUnicode: | |
| proc getCurrentDirectoryW*(nBufferLength: int32, | |
| lpBuffer: WideCString): int32 {. | |
| importc: "GetCurrentDirectoryW", dynlib: "kernel32", stdcall.} | |
| proc setCurrentDirectoryW*(lpPathName: WideCString): int32 {. | |
| importc: "SetCurrentDirectoryW", dynlib: "kernel32", stdcall.} | |
| proc createDirectoryW*(pathName: WideCString, security: pointer=nil): int32 {. | |
| importc: "CreateDirectoryW", dynlib: "kernel32", stdcall.} | |
| proc removeDirectoryW*(lpPathName: WideCString): int32 {. | |
| importc: "RemoveDirectoryW", dynlib: "kernel32", stdcall.} | |
| proc setEnvironmentVariableW*(lpName, lpValue: WideCString): int32 {. | |
| stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableW".} | |
| proc getModuleFileNameW*(handle: THandle, buf: WideCString, | |
| size: int32): int32 {.importc: "GetModuleFileNameW", | |
| dynlib: "kernel32", stdcall.} | |
| else: | |
| proc getCurrentDirectoryA*(nBufferLength: int32, lpBuffer: cstring): int32 {. | |
| importc: "GetCurrentDirectoryA", dynlib: "kernel32", stdcall.} | |
| proc setCurrentDirectoryA*(lpPathName: cstring): int32 {. | |
| importc: "SetCurrentDirectoryA", dynlib: "kernel32", stdcall.} | |
| proc createDirectoryA*(pathName: cstring, security: Pointer=nil): int32 {. | |
| importc: "CreateDirectoryA", dynlib: "kernel32", stdcall.} | |
| proc removeDirectoryA*(lpPathName: cstring): int32 {. | |
| importc: "RemoveDirectoryA", dynlib: "kernel32", stdcall.} | |
| proc setEnvironmentVariableA*(lpName, lpValue: cstring): int32 {. | |
| stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableA".} | |
| proc getModuleFileNameA*(handle: THandle, buf: CString, size: int32): int32 {. | |
| importc: "GetModuleFileNameA", dynlib: "kernel32", stdcall.} | |
| const | |
| FILE_ATTRIBUTE_ARCHIVE* = 32'i32 | |
| FILE_ATTRIBUTE_COMPRESSED* = 2048'i32 | |
| FILE_ATTRIBUTE_NORMAL* = 128'i32 | |
| FILE_ATTRIBUTE_DIRECTORY* = 16'i32 | |
| FILE_ATTRIBUTE_HIDDEN* = 2'i32 | |
| FILE_ATTRIBUTE_READONLY* = 1'i32 | |
| FILE_ATTRIBUTE_SYSTEM* = 4'i32 | |
| FILE_ATTRIBUTE_TEMPORARY* = 256'i32 | |
| MAX_PATH* = 260 | |
| type | |
| TWIN32_FIND_DATA* {.pure.} = object | |
| dwFileAttributes*: int32 | |
| ftCreationTime*: TFILETIME | |
| ftLastAccessTime*: TFILETIME | |
| ftLastWriteTime*: TFILETIME | |
| nFileSizeHigh*: int32 | |
| nFileSizeLow*: int32 | |
| dwReserved0: int32 | |
| dwReserved1: int32 | |
| cFileName*: array[0..(MAX_PATH) - 1, TWinChar] | |
| cAlternateFileName*: array[0..13, TWinChar] | |
| when useWinUnicode: | |
| proc findFirstFileW*(lpFileName: WideCString, | |
| lpFindFileData: var TWIN32_FIND_DATA): THandle {. | |
| stdcall, dynlib: "kernel32", importc: "FindFirstFileW".} | |
| proc findNextFileW*(hFindFile: THandle, | |
| lpFindFileData: var TWIN32_FIND_DATA): int32 {. | |
| stdcall, dynlib: "kernel32", importc: "FindNextFileW".} | |
| else: | |
| proc findFirstFileA*(lpFileName: cstring, | |
| lpFindFileData: var TWIN32_FIND_DATA): THANDLE {. | |
| stdcall, dynlib: "kernel32", importc: "FindFirstFileA".} | |
| proc findNextFileA*(hFindFile: THANDLE, | |
| lpFindFileData: var TWIN32_FIND_DATA): int32 {. | |
| stdcall, dynlib: "kernel32", importc: "FindNextFileA".} | |
| proc findClose*(hFindFile: THandle) {.stdcall, dynlib: "kernel32", | |
| importc: "FindClose".} | |
| when useWinUnicode: | |
| proc getFullPathNameW*(lpFileName: WideCString, nBufferLength: int32, | |
| lpBuffer: WideCString, | |
| lpFilePart: var WideCString): int32 {. | |
| stdcall, dynlib: "kernel32", | |
| importc: "GetFullPathNameW".} | |
| proc getFileAttributesW*(lpFileName: WideCString): int32 {. | |
| stdcall, dynlib: "kernel32", | |
| importc: "GetFileAttributesW".} | |
| proc setFileAttributesW*(lpFileName: WideCString, | |
| dwFileAttributes: int32): WINBOOL {. | |
| stdcall, dynlib: "kernel32", importc: "SetFileAttributesW".} | |
| proc copyFileW*(lpExistingFileName, lpNewFileName: WideCString, | |
| bFailIfExists: cint): cint {. | |
| importc: "CopyFileW", stdcall, dynlib: "kernel32".} | |
| proc getEnvironmentStringsW*(): WideCString {. | |
| stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsW".} | |
| proc freeEnvironmentStringsW*(para1: WideCString): int32 {. | |
| stdcall, dynlib: "kernel32", importc: "FreeEnvironmentStringsW".} | |
| proc getCommandLineW*(): WideCString {.importc: "GetCommandLineW", | |
| stdcall, dynlib: "kernel32".} | |
| else: | |
| proc getFullPathNameA*(lpFileName: cstring, nBufferLength: int32, | |
| lpBuffer: cstring, lpFilePart: var cstring): int32 {. | |
| stdcall, dynlib: "kernel32", | |
| importc: "GetFullPathNameA".} | |
| proc getFileAttributesA*(lpFileName: cstring): int32 {. | |
| stdcall, dynlib: "kernel32", | |
| importc: "GetFileAttributesA".} | |
| proc setFileAttributesA*(lpFileName: cstring, | |
| dwFileAttributes: int32): WINBOOL {. | |
| stdcall, dynlib: "kernel32", importc: "SetFileAttributesA".} | |
| proc copyFileA*(lpExistingFileName, lpNewFileName: CString, | |
| bFailIfExists: cint): cint {. | |
| importc: "CopyFileA", stdcall, dynlib: "kernel32".} | |
| proc getEnvironmentStringsA*(): cstring {. | |
| stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsA".} | |
| proc freeEnvironmentStringsA*(para1: cstring): int32 {. | |
| stdcall, dynlib: "kernel32", importc: "FreeEnvironmentStringsA".} | |
| proc getCommandLineA*(): cstring {. | |
| importc: "GetCommandLineA", stdcall, dynlib: "kernel32".} | |
| proc rdFileTime*(f: TFILETIME): int64 = | |
| result = ze64(f.dwLowDateTime) or (ze64(f.dwHighDateTime) shl 32) | |
| proc rdFileSize*(f: TWIN32_FIND_DATA): int64 = | |
| result = ze64(f.nFileSizeLow) or (ze64(f.nFileSizeHigh) shl 32) | |
| proc getSystemTimeAsFileTime*(lpSystemTimeAsFileTime: var TFILETIME) {. | |
| importc: "GetSystemTimeAsFileTime", dynlib: "kernel32", stdcall.} | |
| proc sleep*(dwMilliseconds: int32){.stdcall, dynlib: "kernel32", | |
| importc: "Sleep".} | |
| when useWinUnicode: | |
| proc shellExecuteW*(HWND: THandle, lpOperation, lpFile, | |
| lpParameters, lpDirectory: WideCString, | |
| nShowCmd: int32): THandle{. | |
| stdcall, dynlib: "shell32.dll", importc: "ShellExecuteW".} | |
| else: | |
| proc shellExecuteA*(HWND: THandle, lpOperation, lpFile, | |
| lpParameters, lpDirectory: cstring, | |
| nShowCmd: int32): THandle{. | |
| stdcall, dynlib: "shell32.dll", importc: "ShellExecuteA".} | |
| proc getFileInformationByHandle*(hFile: THandle, | |
| lpFileInformation: ptr TBY_HANDLE_FILE_INFORMATION): WINBOOL{. | |
| stdcall, dynlib: "kernel32", importc: "GetFileInformationByHandle".} | |
| const | |
| WSADESCRIPTION_LEN* = 256 | |
| WSASYS_STATUS_LEN* = 128 | |
| FD_SETSIZE* = 64 | |
| MSG_PEEK* = 2 | |
| INADDR_ANY* = 0 | |
| INADDR_LOOPBACK* = 0x7F000001 | |
| INADDR_BROADCAST* = -1 | |
| INADDR_NONE* = -1 | |
| ws2dll = "Ws2_32.dll" | |
| WSAEWOULDBLOCK* = 10035 | |
| WSAEINPROGRESS* = 10036 | |
| proc wsaGetLastError*(): cint {.importc: "WSAGetLastError", dynlib: ws2dll.} | |
| type | |
| TSocketHandle* = distinct int | |
| type | |
| TWSAData* {.pure, final, importc: "WSADATA", header: "Winsock2.h".} = object | |
| wVersion, wHighVersion: int16 | |
| szDescription: array[0..WSADESCRIPTION_LEN, char] | |
| szSystemStatus: array[0..WSASYS_STATUS_LEN, char] | |
| iMaxSockets, iMaxUdpDg: int16 | |
| lpVendorInfo: cstring | |
| TSockAddr* {.pure, final, importc: "SOCKADDR", header: "Winsock2.h".} = object | |
| sa_family*: int16 # unsigned | |
| sa_data: array[0..13, char] | |
| TInAddr* {.pure, final, importc: "IN_ADDR", header: "Winsock2.h".} = object | |
| s_addr*: int32 # IP address | |
| Tsockaddr_in* {.pure, final, importc: "SOCKADDR_IN", | |
| header: "Winsock2.h".} = object | |
| sin_family*: int16 | |
| sin_port*: int16 # unsigned | |
| sin_addr*: TInAddr | |
| sin_zero*: array[0..7, char] | |
| Tin6_addr* {.pure, final, importc: "IN6_ADDR", header: "Winsock2.h".} = object | |
| bytes*: array[0..15, char] | |
| Tsockaddr_in6* {.pure, final, importc: "SOCKADDR_IN6", | |
| header: "Winsock2.h".} = object | |
| sin6_family*: int16 | |
| sin6_port*: int16 # unsigned | |
| sin6_flowinfo*: int32 # unsigned | |
| sin6_addr*: Tin6_addr | |
| sin6_scope_id*: int32 # unsigned | |
| Tsockaddr_in6_old* {.pure, final.} = object | |
| sin6_family*: int16 | |
| sin6_port*: int16 # unsigned | |
| sin6_flowinfo*: int32 # unsigned | |
| sin6_addr*: Tin6_addr | |
| TServent* {.pure, final.} = object | |
| s_name*: cstring | |
| s_aliases*: cstringArray | |
| when defined(cpu64): | |
| s_proto*: cstring | |
| s_port*: int16 | |
| else: | |
| s_port*: int16 | |
| s_proto*: cstring | |
| Thostent* {.pure, final.} = object | |
| h_name*: cstring | |
| h_aliases*: cstringArray | |
| h_addrtype*: int16 | |
| h_length*: int16 | |
| h_addr_list*: cstringArray | |
| TFdSet* {.pure, final.} = object | |
| fd_count*: cint # unsigned | |
| fd_array*: array[0..FD_SETSIZE-1, TSocketHandle] | |
| TTimeval* {.pure, final.} = object | |
| tv_sec*, tv_usec*: int32 | |
| TAddrInfo* {.pure, final.} = object | |
| ai_flags*: cint ## Input flags. | |
| ai_family*: cint ## Address family of socket. | |
| ai_socktype*: cint ## Socket type. | |
| ai_protocol*: cint ## Protocol of socket. | |
| ai_addrlen*: int ## Length of socket address. | |
| ai_canonname*: cstring ## Canonical name of service location. | |
| ai_addr*: ptr TSockAddr ## Socket address of socket. | |
| ai_next*: ptr TAddrInfo ## Pointer to next in list. | |
| TSockLen* = cuint | |
| var | |
| SOMAXCONN* {.importc, header: "Winsock2.h".}: cint | |
| INVALID_SOCKET* {.importc, header: "Winsock2.h".}: TSocketHandle | |
| SOL_SOCKET* {.importc, header: "Winsock2.h".}: cint | |
| SO_DEBUG* {.importc, header: "Winsock2.h".}: cint ## turn on debugging info recording | |
| SO_ACCEPTCONN* {.importc, header: "Winsock2.h".}: cint # socket has had listen() | |
| SO_REUSEADDR* {.importc, header: "Winsock2.h".}: cint # allow local address reuse | |
| SO_KEEPALIVE* {.importc, header: "Winsock2.h".}: cint # keep connections alive | |
| SO_DONTROUTE* {.importc, header: "Winsock2.h".}: cint # just use interface addresses | |
| SO_BROADCAST* {.importc, header: "Winsock2.h".}: cint # permit sending of broadcast msgs | |
| SO_USELOOPBACK* {.importc, header: "Winsock2.h".}: cint # bypass hardware when possible | |
| SO_LINGER* {.importc, header: "Winsock2.h".}: cint # linger on close if data present | |
| SO_OOBINLINE* {.importc, header: "Winsock2.h".}: cint # leave received OOB data in line | |
| SO_DONTLINGER* {.importc, header: "Winsock2.h".}: cint | |
| SO_EXCLUSIVEADDRUSE* {.importc, header: "Winsock2.h".}: cint # disallow local address reuse | |
| proc `==`*(x, y: TSocketHandle): bool {.borrow.} | |
| proc getservbyname*(name, proto: cstring): ptr TServent {. | |
| stdcall, importc: "getservbyname", dynlib: ws2dll.} | |
| proc getservbyport*(port: cint, proto: cstring): ptr TServent {. | |
| stdcall, importc: "getservbyport", dynlib: ws2dll.} | |
| proc gethostbyaddr*(ip: ptr TInAddr, len: cuint, theType: cint): ptr Thostent {. | |
| stdcall, importc: "gethostbyaddr", dynlib: ws2dll.} | |
| proc gethostbyname*(name: cstring): ptr Thostent {. | |
| stdcall, importc: "gethostbyname", dynlib: ws2dll.} | |
| proc socket*(af, typ, protocol: cint): TSocketHandle {. | |
| stdcall, importc: "socket", dynlib: ws2dll.} | |
| proc closesocket*(s: TSocketHandle): cint {. | |
| stdcall, importc: "closesocket", dynlib: ws2dll.} | |
| proc accept*(s: TSocketHandle, a: ptr TSockAddr, addrlen: ptr TSockLen): TSocketHandle {. | |
| stdcall, importc: "accept", dynlib: ws2dll.} | |
| proc bindSocket*(s: TSocketHandle, name: ptr TSockAddr, namelen: TSockLen): cint {. | |
| stdcall, importc: "bind", dynlib: ws2dll.} | |
| proc connect*(s: TSocketHandle, name: ptr TSockAddr, namelen: TSockLen): cint {. | |
| stdcall, importc: "connect", dynlib: ws2dll.} | |
| proc getsockname*(s: TSocketHandle, name: ptr TSockAddr, | |
| namelen: ptr TSockLen): cint {. | |
| stdcall, importc: "getsockname", dynlib: ws2dll.} | |
| proc getsockopt*(s: TSocketHandle, level, optname: cint, optval: pointer, | |
| optlen: ptr TSockLen): cint {. | |
| stdcall, importc: "getsockopt", dynlib: ws2dll.} | |
| proc setsockopt*(s: TSocketHandle, level, optname: cint, optval: pointer, | |
| optlen: TSockLen): cint {. | |
| stdcall, importc: "setsockopt", dynlib: ws2dll.} | |
| proc listen*(s: TSocketHandle, backlog: cint): cint {. | |
| stdcall, importc: "listen", dynlib: ws2dll.} | |
| proc recv*(s: TSocketHandle, buf: pointer, len, flags: cint): cint {. | |
| stdcall, importc: "recv", dynlib: ws2dll.} | |
| proc recvfrom*(s: TSocketHandle, buf: cstring, len, flags: cint, | |
| fromm: ptr TSockAddr, fromlen: ptr TSockLen): cint {. | |
| stdcall, importc: "recvfrom", dynlib: ws2dll.} | |
| proc select*(nfds: cint, readfds, writefds, exceptfds: ptr TFdSet, | |
| timeout: ptr TTimeval): cint {. | |
| stdcall, importc: "select", dynlib: ws2dll.} | |
| proc send*(s: TSocketHandle, buf: pointer, len, flags: cint): cint {. | |
| stdcall, importc: "send", dynlib: ws2dll.} | |
| proc sendto*(s: TSocketHandle, buf: pointer, len, flags: cint, | |
| to: ptr TSockAddr, tolen: TSockLen): cint {. | |
| stdcall, importc: "sendto", dynlib: ws2dll.} | |
| proc shutdown*(s: TSocketHandle, how: cint): cint {. | |
| stdcall, importc: "shutdown", dynlib: ws2dll.} | |
| proc getnameinfo*(a1: ptr TSockAddr, a2: TSockLen, | |
| a3: cstring, a4: TSockLen, a5: cstring, | |
| a6: TSockLen, a7: cint): cint {. | |
| stdcall, importc: "getnameinfo", dynlib: ws2dll.} | |
| proc inet_addr*(cp: cstring): int32 {. | |
| stdcall, importc: "inet_addr", dynlib: ws2dll.} | |
| proc WSAFDIsSet(s: TSocketHandle, FDSet: var TFdSet): bool {. | |
| stdcall, importc: "__WSAFDIsSet", dynlib: ws2dll.} | |
| proc FD_ISSET*(Socket: TSocketHandle, FDSet: var TFdSet): cint = | |
| result = if WSAFDIsSet(Socket, FDSet): 1'i32 else: 0'i32 | |
| proc FD_SET*(Socket: TSocketHandle, FDSet: var TFdSet) = | |
| if FDSet.fd_count < FD_SETSIZE: | |
| FDSet.fd_array[int(FDSet.fd_count)] = Socket | |
| inc(FDSet.fd_count) | |
| proc FD_ZERO*(FDSet: var TFdSet) = | |
| FDSet.fd_count = 0 | |
| proc wsaStartup*(wVersionRequired: int16, WSData: ptr TWSAData): cint {. | |
| stdcall, importc: "WSAStartup", dynlib: ws2dll.} | |
| proc getaddrinfo*(nodename, servname: cstring, hints: ptr TAddrInfo, | |
| res: var ptr TAddrInfo): cint {. | |
| stdcall, importc: "getaddrinfo", dynlib: ws2dll.} | |
| proc freeaddrinfo*(ai: ptr TAddrInfo) {. | |
| stdcall, importc: "freeaddrinfo", dynlib: ws2dll.} | |
| proc inet_ntoa*(i: TInAddr): cstring {. | |
| stdcall, importc, dynlib: ws2dll.} | |
| const | |
| MAXIMUM_WAIT_OBJECTS* = 0x00000040 | |
| type | |
| TWOHandleArray* = array[0..MAXIMUM_WAIT_OBJECTS - 1, THandle] | |
| PWOHandleArray* = ptr TWOHandleArray | |
| proc waitForMultipleObjects*(nCount: DWORD, lpHandles: PWOHandleArray, | |
| bWaitAll: WINBOOL, dwMilliseconds: DWORD): DWORD{. | |
| stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".} | |
| # for memfiles.nim: | |
| const | |
| GENERIC_READ* = 0x80000000'i32 | |
| GENERIC_ALL* = 0x10000000'i32 | |
| FILE_SHARE_READ* = 1'i32 | |
| FILE_SHARE_DELETE* = 4'i32 | |
| FILE_SHARE_WRITE* = 2'i32 | |
| CREATE_ALWAYS* = 2'i32 | |
| OPEN_EXISTING* = 3'i32 | |
| FILE_BEGIN* = 0'i32 | |
| INVALID_SET_FILE_POINTER* = -1'i32 | |
| NO_ERROR* = 0'i32 | |
| PAGE_READONLY* = 2'i32 | |
| PAGE_READWRITE* = 4'i32 | |
| FILE_MAP_READ* = 4'i32 | |
| FILE_MAP_WRITE* = 2'i32 | |
| INVALID_FILE_SIZE* = -1'i32 | |
| FILE_FLAG_BACKUP_SEMANTICS* = 33554432'i32 | |
| # Error Constants | |
| const | |
| ERROR_ACCESS_DENIED* = 5 | |
| when useWinUnicode: | |
| proc createFileW*(lpFileName: WideCString, dwDesiredAccess, dwShareMode: DWORD, | |
| lpSecurityAttributes: pointer, | |
| dwCreationDisposition, dwFlagsAndAttributes: DWORD, | |
| hTemplateFile: THandle): THandle {. | |
| stdcall, dynlib: "kernel32", importc: "CreateFileW".} | |
| proc deleteFileW*(pathName: WideCString): int32 {. | |
| importc: "DeleteFileW", dynlib: "kernel32", stdcall.} | |
| else: | |
| proc createFileA*(lpFileName: cstring, dwDesiredAccess, dwShareMode: DWORD, | |
| lpSecurityAttributes: pointer, | |
| dwCreationDisposition, dwFlagsAndAttributes: DWORD, | |
| hTemplateFile: THANDLE): THANDLE {. | |
| stdcall, dynlib: "kernel32", importc: "CreateFileA".} | |
| proc deleteFileA*(pathName: cstring): int32 {. | |
| importc: "DeleteFileA", dynlib: "kernel32", stdcall.} | |
| proc setEndOfFile*(hFile: THandle): WINBOOL {.stdcall, dynlib: "kernel32", | |
| importc: "SetEndOfFile".} | |
| proc setFilePointer*(hFile: THandle, lDistanceToMove: LONG, | |
| lpDistanceToMoveHigh: ptr LONG, | |
| dwMoveMethod: DWORD): DWORD {. | |
| stdcall, dynlib: "kernel32", importc: "SetFilePointer".} | |
| proc getFileSize*(hFile: THandle, lpFileSizeHigh: ptr DWORD): DWORD{.stdcall, | |
| dynlib: "kernel32", importc: "GetFileSize".} | |
| proc mapViewOfFileEx*(hFileMappingObject: THandle, dwDesiredAccess: DWORD, | |
| dwFileOffsetHigh, dwFileOffsetLow: DWORD, | |
| dwNumberOfBytesToMap: DWORD, | |
| lpBaseAddress: pointer): pointer{. | |
| stdcall, dynlib: "kernel32", importc: "MapViewOfFileEx".} | |
| proc createFileMappingW*(hFile: THandle, | |
| lpFileMappingAttributes: pointer, | |
| flProtect, dwMaximumSizeHigh: DWORD, | |
| dwMaximumSizeLow: DWORD, | |
| lpName: pointer): THandle {. | |
| stdcall, dynlib: "kernel32", importc: "CreateFileMappingW".} | |
| when not useWinUnicode: | |
| proc createFileMappingA*(hFile: THANDLE, | |
| lpFileMappingAttributes: pointer, | |
| flProtect, dwMaximumSizeHigh: DWORD, | |
| dwMaximumSizeLow: DWORD, lpName: cstring): THANDLE {. | |
| stdcall, dynlib: "kernel32", importc: "CreateFileMappingA".} | |
| proc unmapViewOfFile*(lpBaseAddress: pointer): WINBOOL {.stdcall, | |
| dynlib: "kernel32", importc: "UnmapViewOfFile".} | |
| type | |
| TGUID* {.final, pure.} = object | |
| D1*: int32 | |
| D2*: int16 | |
| D3*: int16 | |
| D4*: array [0..7, int8] | |
| Overlapped* {.final, pure.} = object | |
| Internal*: ptr LONG | |
| InternalHigh*: ptr LONG | |
| Offset*: DWORD | |
| OffsetHigh*: DWORD | |
| hEvent*: THandle | |
| POverlapped* {.final, pure.} = ptr Overlapped | |
| CompletionRoutine* {.final, pure.} = proc ( | |
| dwError, cbTransferred : DWORD, | |
| lpOverlapped: POverlapped, | |
| dwFlags: DWORD | |
| ) | |
| ConnectExProc* {.final, pure.} = proc ( | |
| socket: TSocketHandle, | |
| name: ptr TSockAddr, | |
| namelen: cint, | |
| lpSendBuffer: pointer, dwSendDataLength: DWORD, | |
| lpdwBytesSent: ptr DWORD, | |
| lpOverlapped: POverlapped | |
| ): bool {.stdcall.} | |
| const | |
| IOC_OUT = 0x40000000 | |
| IOC_IN = 0x80000000 | |
| IOC_WS2 = 0x08000000 | |
| IOC_INOUT = IOC_IN or IOC_OUT | |
| template WSAIORW(x,y): expr = (IOC_INOUT or x or y) | |
| const | |
| SIO_GET_EXTENSION_FUNCTION_POINTER* = WSAIORW(IOC_WS2,6).DWORD | |
| var | |
| WSAID_CONNECTEX*: TGUID = TGUID(D1: 0x25a207b9, D2: 0xddf3'i16, D3: 0x4660, D4: [ | |
| 0x8e'i8, 0xe9'i8, 0x76'i8, 0xe5'i8, 0x8c'i8, 0x74'i8, | |
| 0x06'i8, 0x3e'i8]) | |
| proc CreateIoCompletionPort*(FileHandle: THandle, ExistingCompletionPort: THandle, | |
| CompletionKey: ptr LONG, | |
| NumberOfConcurrentThreads: DWORD): THandle{.stdcall, | |
| dynlib: "kernel32", importc: "CreateIoCompletionPort".} | |
| proc GetQueuedCompletionStatus*(CompletionPort: THandle, | |
| lpNumberOfBytesTransferred: ptr DWORD, lpCompletionKey: ptr(ptr LONG), | |
| lpOverlapped: ptr POverlapped, | |
| dwMilliseconds: DWORD): WINBOOL{.stdcall, | |
| dynlib: "kernel32", importc: "GetQueuedCompletionStatus".} | |
| proc WSAIoctl*(s: TSocketHandle, dwIoControlCode: DWORD, lpvInBuffer: pointer, | |
| cbInBuffer: DWORD, lpvOutBuffer: pointer, cbOutBuffer: dword, | |
| lpcbBytesReturned: ptr DWORD, lpOverlapped: POverlapped, | |
| lpCompletionRoutine: CompletionRoutine): cint {.stdcall, importc: "WSAIoctl", dynlib: "Ws2_32.dll".} | |
| proc getConnectEx*(s: TSocketHandle, guid: var TGUID): ConnectExProc = | |
| # Ref: https://github.com/powdahound/twisted/blob/master/twisted/internet/iocpreactor/iocpsupport/winsock_pointers.c | |
| var bytesRet: DWORD | |
| var connectExPtr: pointer = nil | |
| let state = WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, addr guid, | |
| sizeof(TGUID).dword, addr connectExPtr, sizeof(pointer).DWORD, | |
| addr bytesRet, nil, nil) == 0 | |
| if not state: | |
| assert(false) | |
| result = cast[ConnectExProc](connectExPtr) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment