1 #include <winsock2.h>
2 #include <mswsock.h>
3 #include <ws2tcpip.h>
4 
5 #include <windows.h>
6 #include <config.h>
7 
8 #include <process.h>
9 #include <stddef.h>
10 
11 #define GC_NO_THREAD_REDIRECTS // we don't need override
12 #include <gc.h>
13 
14 
15 #include "aio_win32.h"
16 
17 #ifndef WSAID_ACCEPTEX
18 #error Your MinGW/Win32 runtime is too old... Try Mingw-w64 with -m32 option.
19 #endif
20 
21 char* errorpos; // FIXME: for debugging
22 
23 #define OSERROR(x) errorpos = x
24 
25 int
win32_process_pipe(HANDLE * ret)26 win32_process_pipe(HANDLE* ret){
27 	SECURITY_ATTRIBUTES sat;
28 	HANDLE tmp;
29 
30 	sat.nLength = sizeof(SECURITY_ATTRIBUTES);
31 	sat.bInheritHandle = TRUE;
32 	sat.lpSecurityDescriptor = NULL;
33 
34 	if(!CreatePipe(&tmp,&ret[0],&sat,0)){
35 		OSERROR("createpipe"); // handle Win32 Error Here
36 		return 0;
37 	}
38 	DuplicateHandle(GetCurrentProcess(),tmp,GetCurrentProcess(),&ret[1],0,FALSE,DUPLICATE_SAME_ACCESS);
39 	CloseHandle(tmp);
40 #if 0 // won't work..
41 	/* make non-inheritable */
42 	if(!SetHandleInformation(ret[1], HANDLE_FLAG_INHERIT, 0)){
43 		OSERROR("sethandleinformation");
44 		return 0;
45 	}
46 #endif
47 
48 	return 1;
49 }
50 
51 uintptr_t
win32_process_redirected_child(wchar_t * spec,wchar_t * dir,HANDLE std_in,HANDLE std_out,HANDLE std_err)52 win32_process_redirected_child(wchar_t* spec,wchar_t* dir, HANDLE std_in, HANDLE std_out, HANDLE std_err){
53 	PROCESS_INFORMATION pi;
54 	STARTUPINFOW si;
55 	BOOL r;
56 
57 	ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
58 	ZeroMemory(&si, sizeof(STARTUPINFOW));
59 
60 	si.cb = sizeof(STARTUPINFO);
61 	si.dwFlags = STARTF_USESTDHANDLES;
62 	if(std_in != 0){
63 		si.hStdInput = std_in;
64 	}else{
65 		si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
66 	}
67 	if(std_out != 0){
68 		si.hStdOutput = std_out;
69 	}else{
70 		si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
71 	}
72 	if(std_err != 0){
73 		si.hStdError = std_err;
74 	}else{
75 		si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
76 	}
77 
78 	r = CreateProcessW(NULL, spec, NULL, NULL, TRUE, 0, NULL, dir, &si, &pi);
79 
80 	if(std_out != 0){
81 		CloseHandle(std_out);
82 	}
83 
84 	if(std_err != 0){
85 		CloseHandle(std_err);
86 	}
87 
88 	if (! r){
89 		OSERROR("CreateProcess");
90 		return 0;
91 	}
92 	CloseHandle(pi.hThread);
93 	return (uintptr_t)pi.hProcess;
94 }
95 
96 // should be moved to handle.c...
97 
98 int
win32_handle_read(HANDLE h,void * p,unsigned int len,unsigned int * res)99 win32_handle_read(HANDLE h,void* p,unsigned int len,unsigned int *res){
100 	BOOL r;
101 	r = ReadFile(h,p,len,res,NULL);
102 	if(!r){
103 		OSERROR("ReadFile");
104 		return 0;
105 	}
106 	return 1;
107 }
108 
109 int
win32_handle_write(HANDLE h,void * p,unsigned int len,unsigned int * res)110 win32_handle_write(HANDLE h,void *p,unsigned int len,unsigned int *res){
111 	BOOL r;
112 	r = WriteFile(h,p,len,res,NULL);
113 	if(!r){
114 		OSERROR("WriteFile");
115 		return 0;
116 	}
117 	return 1;
118 }
119 
120 int
win32_handle_close(HANDLE h)121 win32_handle_close(HANDLE h){
122 	BOOL r;
123 	r = CloseHandle(h);
124 	if(!r){
125 		OSERROR("CloseHandle");
126 		return 0;
127 	}
128 	return 1;
129 }
130 
131 int
win32_process_wait(HANDLE process)132 win32_process_wait(HANDLE process){
133 	BOOL r;
134 	DWORD res;
135 	r = WaitForSingleObject(process,INFINITE);
136 	if(WAIT_FAILED == r){
137 		OSERROR("WaitForSingleObject");
138 		return -1;
139 	}
140 	GetExitCodeProcess(process,&res);
141 	CloseHandle(process);
142 	return res;
143 }
144 
145 int
win32_handle_wait(HANDLE h)146 win32_handle_wait(HANDLE h){
147 	BOOL r;
148 	r = WaitForSingleObject(h,INFINITE);
149 	if(!r){
150 		OSERROR("WaitForSingleObject");
151 		return 0;
152 	}
153 	return 1;
154 }
155 
156 uintptr_t
win32_create_named_pipe(wchar_t * name)157 win32_create_named_pipe(wchar_t* name){
158 	HANDLE h;
159 	h = CreateNamedPipeW(name,PIPE_ACCESS_DUPLEX,PIPE_WAIT,PIPE_UNLIMITED_INSTANCES,4096,4096,0,NULL);
160 	if(h == INVALID_HANDLE_VALUE){
161 		OSERROR("CreateNamedPipeW");
162 		return -1;
163 	}
164 	return (uintptr_t)h;
165 }
166 
167 int
win32_wait_named_pipe(HANDLE h)168 win32_wait_named_pipe(HANDLE h){
169 	BOOL b;
170 	b = ConnectNamedPipe(h,NULL);
171 	if(!b){
172 		return 0;
173 	}
174 	return 1;
175 }
176 
177 uintptr_t
win32_iocp_create(void)178 win32_iocp_create(void){
179 	// FIXME: err?
180 	return (uintptr_t)CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
181 }
182 
183 int
win32_iocp_assoc(uintptr_t iocp,uintptr_t in,uintptr_t key)184 win32_iocp_assoc(uintptr_t iocp,uintptr_t in,uintptr_t key){
185 	HANDLE h = (HANDLE)in;
186 	HANDLE ret;
187 
188 	ret = CreateIoCompletionPort(h,(HANDLE)iocp,key,0);
189 	if(ret == NULL){
190 		// error
191 		return 0;
192 	}
193 	return 1;
194 }
195 
196 int
win32_iocp_pop(uintptr_t iocp,intptr_t timeout_in,uintptr_t ret_bytestrans,uintptr_t ret_key,uintptr_t ret_overlapped)197 win32_iocp_pop(uintptr_t iocp, intptr_t timeout_in,uintptr_t ret_bytestrans, uintptr_t ret_key, uintptr_t ret_overlapped){
198 	BOOL b;
199 	DWORD timeout;
200 	timeout = (timeout_in == -1)?INFINITE:timeout_in;
201 
202 
203 	// GetQueuedCompletionStatus will return status of de-queued I/O ops.
204 	// So we should handle the result even if we get FALSE here..
205 	b = GetQueuedCompletionStatus((HANDLE)iocp,(LPDWORD)ret_bytestrans,(PULONG_PTR)ret_key,(LPOVERLAPPED *)ret_overlapped,timeout);
206 	if(!b){
207 		return 0;
208 	}else{
209 		return 1;
210 	}
211 }
212 
213 // allocate and free OVERLAPPED. OVERLAPPED may passed to non-GC-managed threads.
214 
215 typedef struct{
216     // N.B. should synced with finalization handler and window handler
217 	OVERLAPPED ovl;
218 	void* p;
219 } OVPAIR;
220 
221 void*
win32_overlapped_alloc(void)222 win32_overlapped_alloc(void){
223 	OVPAIR* p;
224 	p = (OVPAIR *)GC_MALLOC_UNCOLLECTABLE(sizeof(OVPAIR));
225 	ZeroMemory(p,sizeof(OVPAIR));
226 	return p; // FIXME: should be aligned ??
227 }
228 
229 void
win32_overlapped_free(void * p)230 win32_overlapped_free(void* p){
231 	GC_FREE(p);
232 }
233 
234 void
win32_overlapped_setmydata(void * p,void * data)235 win32_overlapped_setmydata(void* p,void* data){
236 	OVPAIR* ov = (OVPAIR *)p;
237 	ov->p = data;
238 }
239 
240 void*
win32_overlapped_getmydata(void * p)241 win32_overlapped_getmydata(void* p){
242 	OVPAIR* ov = (OVPAIR *)p;
243 	return (void *)ov->p;
244 }
245 
246 int
win32_handle_read_async(uintptr_t h,uintptr_t offsetL,uintptr_t offsetH,uintptr_t length,uintptr_t buf,uintptr_t ol)247 win32_handle_read_async(uintptr_t h,uintptr_t offsetL,uintptr_t offsetH,uintptr_t length,uintptr_t buf,uintptr_t ol){
248 	BOOL b;
249 	int err;
250 	OVERLAPPED* ovl = (OVERLAPPED *)ol;
251 	ovl->Offset = offsetL;
252 	ovl->OffsetHigh = offsetH;
253 	ovl->hEvent = NULL;
254 	b = ReadFile((HANDLE)h,(void*)buf,length,NULL,ovl);
255 	if(!b){
256 		err = GetLastError();
257 		if(err == ERROR_IO_PENDING){
258 			return 1;
259 		}else{
260 			return 0;
261 		}
262 	}else{
263 		return 1;
264 	}
265 }
266 
267 int
win32_handle_write_async(uintptr_t h,uintptr_t offsetL,uintptr_t offsetH,uintptr_t length,uintptr_t buf,uintptr_t ol)268 win32_handle_write_async(uintptr_t h,uintptr_t offsetL,uintptr_t offsetH,uintptr_t length,uintptr_t buf,uintptr_t ol){
269 	BOOL b;
270 	int err;
271 	OVERLAPPED* ovl = (OVERLAPPED *)ol;
272 	ovl->Offset = offsetL;
273 	ovl->OffsetHigh = offsetH;
274 	ovl->hEvent = NULL;
275 	b = WriteFile((HANDLE)h,(void *)buf,length,NULL,ovl);
276 	if(!b){
277 		err = GetLastError();
278 		if(err == ERROR_IO_PENDING){
279 			return 1;
280 		}else{
281 			return 0;
282 		}
283 	}else{
284 		return 1;
285 	}
286 }
287 
288 static HANDLE
open_for_input(wchar_t * path,int mode)289 open_for_input(wchar_t* path,int mode){
290 	SECURITY_ATTRIBUTES sat;
291 
292 	sat.nLength = sizeof(SECURITY_ATTRIBUTES);
293 	sat.bInheritHandle = TRUE;
294 	sat.lpSecurityDescriptor = NULL;
295 	return CreateFileW(path,GENERIC_READ,FILE_SHARE_READ,&sat,mode,FILE_ATTRIBUTE_READONLY,NULL);
296 }
297 
298 static HANDLE
open_for_output(wchar_t * path,int mode)299 open_for_output(wchar_t* path,int mode){
300 	SECURITY_ATTRIBUTES sat;
301 
302 	sat.nLength = sizeof(SECURITY_ATTRIBUTES);
303 	sat.bInheritHandle = TRUE;
304 	sat.lpSecurityDescriptor = NULL;
305 	return CreateFileW(path,GENERIC_WRITE,mode,&sat,CREATE_ALWAYS,0,NULL);
306 }
307 
308 // mode:
309 //  0 : /dev/null
310 //  1 : stdio
311 //  2 : CREATE_ALWAYS
312 //  3 : OPEN_EXISTING or TRUNCATE_EXISTING
313 //  4 : pass HANDLE
314 uintptr_t
win32_process_redirected_child2(wchar_t * spec,wchar_t * dir,wchar_t * std_in,wchar_t * std_out,wchar_t * std_err,int in_mode,int out_mode,int err_mode)315 win32_process_redirected_child2(wchar_t* spec,wchar_t* dir, wchar_t* std_in, wchar_t* std_out, wchar_t* std_err, int in_mode, int out_mode, int err_mode){
316 	PROCESS_INFORMATION pi;
317 	STARTUPINFOW si;
318 	int err;
319 	BOOL r;
320 	HANDLE h;
321 	HANDLE ex_out, ex_err;
322 	ex_out = 0;
323 	ex_err = 0;
324 
325 	ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
326 	ZeroMemory(&si, sizeof(STARTUPINFOW));
327 
328 	si.cb = sizeof(STARTUPINFO);
329 	si.dwFlags = STARTF_USESTDHANDLES;
330 	switch(in_mode){
331 	case 0:
332 		break;
333 	case 1:
334 		si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
335 		break;
336 	case 3:
337 		h = open_for_input(std_in,OPEN_EXISTING);
338 		if(h == INVALID_HANDLE_VALUE) return 0;
339 		si.hStdInput = h;
340 		break;
341     case 4:
342         si.hStdInput = (HANDLE)std_in;
343         break;
344 	}
345 	switch(out_mode){
346 	case 0:
347 		break;
348 	case 1:
349 		si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
350 		break;
351 	case 2:
352 		h = open_for_output(std_out,CREATE_ALWAYS);
353 		if(h == INVALID_HANDLE_VALUE) return 0;
354 		si.hStdOutput = h;
355 		ex_out = h;
356 		break;
357 	case 3:
358 		h = open_for_output(std_out,TRUNCATE_EXISTING);
359 		err = GetLastError();
360 		if(h == INVALID_HANDLE_VALUE) return 0;
361 		si.hStdOutput = h;
362 		ex_out = h;
363 		break;
364     case 4:
365         si.hStdOutput = (HANDLE)std_out;
366         ex_out = (HANDLE)std_out;
367         break;
368 	}
369 	switch(err_mode){
370 	case 0:
371 		break;
372 	case 1:
373 		si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
374 		break;
375 	case 2:
376 		h = open_for_output(std_err,CREATE_ALWAYS);
377 		if(h == INVALID_HANDLE_VALUE) return 0;
378 		si.hStdError = h;
379 		ex_err = h;
380 		break;
381 	case 3:
382 		h = open_for_output(std_err,TRUNCATE_EXISTING);
383 		if(h == INVALID_HANDLE_VALUE) return 0;
384 		si.hStdError = h;
385 		ex_err = h;
386 		break;
387     case 4:
388         si.hStdError = (HANDLE)std_err;
389         ex_err = (HANDLE)std_err;
390         break;
391 	}
392 
393 	//FIXME: should we use CREATE_NO_WINDOW ?
394 	r = CreateProcessW(NULL, spec, NULL, NULL, TRUE, 0, NULL, dir, &si, &pi);
395 
396 	if(ex_out != 0){
397 		CloseHandle(ex_out);
398 	}
399 
400 	if(ex_err != 0){
401 		CloseHandle(ex_err);
402 	}
403 
404 	if (! r){
405 		OSERROR("CreateProcess");
406 		return 0;
407 	}
408 	CloseHandle(pi.hThread);
409 	return (uintptr_t)pi.hProcess;
410 }
411 
412 uintptr_t
win32_create_named_pipe_async(wchar_t * name)413 win32_create_named_pipe_async(wchar_t* name){
414 	HANDLE h;
415 	h = CreateNamedPipeW(name,PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED,PIPE_WAIT,PIPE_UNLIMITED_INSTANCES,4096,4096,NMPWAIT_WAIT_FOREVER,NULL);
416 	if(h == INVALID_HANDLE_VALUE){
417 		OSERROR("CreateNamedPipeW");
418 		return -1;
419 	}
420 	return (uintptr_t)h;
421 }
422 int
win32_wait_named_pipe_async(uintptr_t h,uintptr_t ovl)423 win32_wait_named_pipe_async(uintptr_t h, uintptr_t ovl){
424 	BOOL b;
425 	int err;
426 	b = ConnectNamedPipe((HANDLE)h,(OVERLAPPED *)ovl);
427 	err = GetLastError();
428 	if(!b){
429 		if (err == ERROR_IO_PENDING){
430 			return 1;
431 		}else if(err == ERROR_PIPE_CONNECTED){
432 			return 1;
433 		}else{
434 			return 0;
435 		}
436 	}
437 	return 1;
438 }
439 
440 typedef struct {
441 	HANDLE h;
442 	HANDLE iocp;
443 	uintptr_t key;
444 	uintptr_t overlapped;
445 } thread_waiter_param;
446 
447 
448 static void
emit_queue_event(HANDLE iocp,uintptr_t key,intptr_t res,uintptr_t overlapped)449 emit_queue_event(HANDLE iocp,uintptr_t key,intptr_t res,uintptr_t overlapped){
450 	PostQueuedCompletionStatus(iocp,res,key,(LPOVERLAPPED)overlapped);
451 }
452 
453 static void
thread_waiter(void * p)454 thread_waiter(void* p){
455 	thread_waiter_param* param = (thread_waiter_param *)p;
456 	BOOL r;
457 	DWORD res;
458 	HANDLE h;
459 	HANDLE iocp;
460 	uintptr_t key;
461 	uintptr_t overlapped;
462 	h = param->h;
463 	iocp = param->iocp;
464 	key = param->key;
465 	overlapped = param->overlapped;
466 	free(param);
467 
468 	r = WaitForSingleObject(h,INFINITE);
469 	if(WAIT_FAILED == r){
470 		OSERROR("WaitForSingleObject");
471 		emit_queue_event(iocp,key,-1,overlapped);
472 	}else{
473 		GetExitCodeProcess(h,&res);
474 		CloseHandle(h);
475 		emit_queue_event(iocp,key,res,overlapped);
476 	}
477 }
478 
479 static void
invoke_thread_waiter(HANDLE h,HANDLE iocp,uintptr_t key,uintptr_t overlapped)480 invoke_thread_waiter(HANDLE h, HANDLE iocp, uintptr_t key,uintptr_t overlapped){
481 	thread_waiter_param* param;
482 	param = (thread_waiter_param *)malloc(sizeof(thread_waiter_param));
483 	param->h = h;
484 	param->iocp = iocp;
485 	param->key = key;
486 	param->overlapped = overlapped;
487 	_beginthread(thread_waiter,0,param);
488 }
489 
490 typedef struct {
491     // N.B. should synced with OVPAIR
492     OVERLAPPED ovl;
493     void* ptr;
494 
495     HANDLE iocp;
496     void* key;
497 } finalization_handler_data;
498 
499 static void
finalizer(void * obj,void * userdata)500 finalizer(void* obj, void* userdata){
501     finalization_handler_data* d=(finalization_handler_data *)userdata;
502     emit_queue_event(d->iocp,(uintptr_t)d->key,0,(uintptr_t)d->ptr);
503 }
504 
505 void*
win32_finalization_handler_get(void)506 win32_finalization_handler_get(void){
507     return finalizer;
508 }
509 
510 void*
win32_finalization_handler_create(void * iocp,void * key,void * ptr)511 win32_finalization_handler_create(void* iocp, void* key, void* ptr){
512     finalization_handler_data* d;
513     d = (finalization_handler_data *)GC_MALLOC_UNCOLLECTABLE(sizeof(finalization_handler_data));
514     ZeroMemory(&d->ovl,sizeof(OVERLAPPED));
515     d->iocp = (HANDLE)iocp;
516     d->key = key;
517     d->ptr = ptr;
518     return d;
519 }
520 
521 int
win32_process_wait_async(uintptr_t h,uintptr_t iocp,uintptr_t key,uintptr_t overlapped)522 win32_process_wait_async(uintptr_t h,uintptr_t iocp,uintptr_t key, uintptr_t overlapped){
523 	invoke_thread_waiter((HANDLE)h,(HANDLE)iocp,key,overlapped);
524 	return 1;
525 }
526 
527 #if 0
528 // Vista or later only...
529 int
530 win32_cancelioex(void* h,void* ovl){
531 	return CancelIoEx((HANDLE)h,(OVERLAPPED *)ovl);
532 }
533 #endif
534 
535 #if 0
536 int
537 win32_process_get_result(void* process){
538 	BOOL r;
539 	DWORD res;
540 	GetExitCodeProcess((HANDLE)process,&res);
541 	CloseHandle((HANDLE)process);
542 	return res;
543 }
544 #endif
545 
546 /* windows sockets */
547 int
win32_sockaddr_storage_size(void)548 win32_sockaddr_storage_size(void){
549 	return sizeof(SOCKADDR_STORAGE);
550 }
551 
552 // mode = 0 .. default
553 //        4 .. IPv4
554 //        6 .. IPv6
555 // proto = 0 .. ERR
556 //         1 .. TCP
557 //         2 .. UDP
558 uintptr_t
win32_socket_create(int mode,int proto,uintptr_t ret_connectex,uintptr_t ret_acceptex)559 win32_socket_create(int mode,int proto,uintptr_t ret_connectex,uintptr_t ret_acceptex){
560 	int aaf;
561 	int atype;
562 	int aproto;
563 	GUID guidConnectEx = WSAID_CONNECTEX;
564 	GUID guidAcceptEx = WSAID_ACCEPTEX;
565 	DWORD bogus;
566 	uintptr_t ret;
567 	switch(mode){
568 	case 0:
569 		aaf = AF_UNSPEC;
570 		break;
571 	case 4:
572 		aaf = AF_INET;
573 		break;
574 	case 6:
575 		aaf = AF_INET6;
576 		break;
577 	}
578 	switch(proto){
579 	case 0: // wrong
580 		atype = 0;
581 		aproto = 0;
582 		break;
583 	case 1:
584 		atype = SOCK_STREAM;
585 		aproto = IPPROTO_TCP;
586 		break;
587 	case 2:
588 		atype = SOCK_DGRAM;
589 		aproto = IPPROTO_UDP;
590 		break;
591 	}
592 	ret = (uintptr_t)socket(aaf,atype,aproto);
593 
594 	if(atype == SOCK_STREAM){
595 		WSAIoctl(ret,SIO_GET_EXTENSION_FUNCTION_POINTER,&guidConnectEx,sizeof(GUID),(void *)ret_connectex,sizeof(void*),&bogus,NULL,NULL);
596 		WSAIoctl(ret,SIO_GET_EXTENSION_FUNCTION_POINTER,&guidAcceptEx,sizeof(GUID),(void *)ret_acceptex,sizeof(void*),&bogus,NULL,NULL);
597 	}
598 
599 	return ret;
600 }
601 
602 int
win32_socket_close(uintptr_t s)603 win32_socket_close(uintptr_t s){
604 	return closesocket((SOCKET)s);
605 }
606 
607 // mode = 0 .. default
608 //        4 .. IPv4
609 //        6 .. IPv6
610 // proto = 0 .. default
611 //         1 .. TCP
612 //         2 .. UDP
613 int
win32_getaddrinfo(wchar_t * name,wchar_t * servicename,uintptr_t ret_addrinfoex,int mode,int proto)614 win32_getaddrinfo(wchar_t* name,wchar_t* servicename,uintptr_t ret_addrinfoex,int mode,int proto){
615 	int ret;
616 	ADDRINFOW aie;
617 	ZeroMemory(&aie,sizeof(aie));
618 	switch(mode){
619 	case 0:
620 		aie.ai_family = AF_UNSPEC;
621 		break;
622 	case 4:
623 		aie.ai_family = AF_INET;
624 		break;
625 	case 6:
626 		aie.ai_family = AF_INET6;
627 		break;
628 	}
629 	switch(proto){
630 	case 0:
631 		aie.ai_socktype = 0;
632 		aie.ai_protocol = 0;
633 		break;
634 	case 1:
635 		aie.ai_socktype = SOCK_STREAM;
636 		aie.ai_protocol = IPPROTO_TCP;
637 		break;
638 	case 2:
639 		aie.ai_socktype = SOCK_DGRAM;
640 		aie.ai_protocol = IPPROTO_UDP;
641 		break;
642 	}
643 
644 
645 	ret = GetAddrInfoW(name,servicename,&aie,(PADDRINFOW*)ret_addrinfoex);
646 	return ret;
647 }
648 
649 void
win32_addrinfoex_free(uintptr_t aie)650 win32_addrinfoex_free(uintptr_t aie){
651 	FreeAddrInfoW((ADDRINFOW *)aie);
652 }
653 
654 void
win32_addrinfoex_read(uintptr_t aie,uintptr_t * ret_family,uintptr_t * ret_sockaddr,uintptr_t * ret_namelen,uintptr_t * ret_next)655 win32_addrinfoex_read(uintptr_t aie,uintptr_t* ret_family,uintptr_t* ret_sockaddr,uintptr_t* ret_namelen,uintptr_t* ret_next){
656 	ADDRINFOW *aiep = (ADDRINFOW *)aie;
657 	switch(aiep->ai_family){
658 	case AF_INET:
659 		*ret_family = 4;
660 		break;
661 	case AF_INET6:
662 		*ret_family = 6;
663 		break;
664 	default:
665 		*ret_family = 0;
666 		break;
667 	}
668 	*ret_sockaddr = (uintptr_t)aiep->ai_addr;
669 	*ret_namelen = (uintptr_t)aiep->ai_addrlen;
670 	*ret_next = (uintptr_t)aiep->ai_next;
671 }
672 
673 int
win32_socket_connect(uintptr_t func,uintptr_t s,uintptr_t saddr,int namelen,uintptr_t overlapped)674 win32_socket_connect(uintptr_t func,uintptr_t s,uintptr_t saddr,int namelen,uintptr_t overlapped){
675 	LPFN_CONNECTEX con = (LPFN_CONNECTEX)func;
676 	BOOL b;
677 	int err;
678 	struct sockaddr_in sin;
679 	int ret;
680 
681 	// FIXME: we need this API...
682 	ZeroMemory(&sin,sizeof(sin));
683 	sin.sin_family = AF_INET;
684 	ret = bind((SOCKET)s,(const struct sockaddr *)&sin,sizeof(sin));
685 	b = con((SOCKET)s,(const struct sockaddr *)saddr,namelen,NULL,0,NULL,(OVERLAPPED *)overlapped);
686 	if(b){
687 		return 1;
688 	}else{
689 		err = WSAGetLastError();
690 		if(err == ERROR_IO_PENDING){
691 			return 1;
692 		}else{
693 			return 0;
694 		}
695 	}
696 }
697 
698 int
win32_socket_accept(uintptr_t func,uintptr_t slisten,uintptr_t saccept,uintptr_t buf,int bufsize,uintptr_t overlapped)699 win32_socket_accept(uintptr_t func,uintptr_t slisten,uintptr_t saccept,uintptr_t buf,int bufsize,uintptr_t overlapped){
700 	BOOL b;
701 	LPFN_ACCEPTEX acc = (LPFN_ACCEPTEX)func;
702 	DWORD len;
703 	int err;
704 	int addrlen = sizeof(SOCKADDR_STORAGE)+16;
705 	int datasize = bufsize - addrlen - addrlen;
706 	b = acc((SOCKET)slisten,(SOCKET)saccept,(void *)buf,datasize,addrlen,addrlen,&len,(OVERLAPPED *)overlapped);
707 	if(!b){
708 		err = WSAGetLastError();
709 		if(err == ERROR_IO_PENDING){
710 			return 1;
711 		}else{
712 			return 0;
713 		}
714 	}else{
715 		return 1;
716 	}
717 }
718 
719 int
win32_socket_bind(uintptr_t s,uintptr_t name,int namelen)720 win32_socket_bind(uintptr_t s,uintptr_t name,int namelen){
721 	int ret;
722 	ret = bind((SOCKET)s,(const struct sockaddr *)name,namelen);
723 	if(ret == SOCKET_ERROR){
724 		return 0;
725 	}else{
726 		return 1;
727 	}
728 }
729 
730 int
win32_socket_listen(uintptr_t s,int l)731 win32_socket_listen(uintptr_t s,int l){
732 	return listen((SOCKET)s,(l == 0)?SOMAXCONN:l);
733 }
734 
735 /* simple GUI elements */
736 
737 // DLGTYPE: 0:OK 1: YESNO 2: YESNOCANCEL
738 // ICONTYPE: 0:OK(INFO), 1:OK(WARN), 2:OK(ERR)
739 int
win32_messagebox(wchar_t * caption,wchar_t * msg,int dlgtype,int icontype)740 win32_messagebox(wchar_t* caption,wchar_t* msg,int dlgtype,int icontype){
741 	unsigned int buttontype;
742 	unsigned int msgtype;
743 
744 	switch(dlgtype){
745 	case 0:
746 	default:
747 		buttontype = MB_OK;
748 		break;
749 	case 1:
750 		buttontype = MB_YESNO;
751 		break;
752 	case 2:
753 		buttontype = MB_YESNOCANCEL;
754 		break;
755 	}
756 	switch(icontype){
757 	default:
758 	case 0:
759 		msgtype = MB_ICONINFORMATION;
760 		break;
761 	case 1:
762 		msgtype = MB_ICONWARNING;
763 		break;
764 	case 2:
765 		msgtype = MB_ICONHAND;
766 		break;
767 	}
768 
769 	return MessageBoxW(NULL,msg,caption,buttontype|msgtype);
770 }
771 
772 // initialize base window classes
773 #define BASECLASS L"nmosh win32"
774 
775 typedef struct{
776     // N.B. should synced with OVPAIR
777     OVERLAPPED ovl;
778     void* ptr;
779 
780     HANDLE iocp;
781     HWND hWnd;
782     HDC hBufferDataDC;
783 	HBITMAP buffer;
784     CRITICAL_SECTION cs;
785     int enable;
786 }window_handler_data;
787 
788 static void
window_handler(void * p)789 window_handler(void* p){
790     MSG msg;
791 	HWND hWnd;
792     window_handler_data* whd = (window_handler_data *)p;
793 
794 	hWnd = CreateWindowExW(
795         0, //exstyle
796         BASECLASS,
797         L"", // title
798         WS_OVERLAPPEDWINDOW, // style
799         0,
800         0,
801         0,
802         0,
803         NULL,
804         NULL,
805         GetModuleHandle(0),
806         p);
807     whd->hWnd = hWnd;
808     whd->enable = 1;
809     while(GetMessageW(&msg,hWnd,0,0)){
810         TranslateMessage(&msg);
811         DispatchMessageW(&msg);
812         if(!whd->enable) return;
813     }
814 }
815 static void
post_window_event(window_handler_data * whd,int id,uintptr_t param)816 post_window_event(window_handler_data* whd,int id,uintptr_t param){
817     emit_queue_event(whd->iocp,(uintptr_t)id,(intptr_t)param,(uintptr_t)&whd->ovl);
818 }
819 
820 static void
clearbuffer(window_handler_data * whd)821 clearbuffer(window_handler_data* whd){
822 	if(whd->buffer){
823 		DeleteObject(whd->buffer);
824 	}
825 	if(whd->hBufferDataDC){
826 		DeleteDC(whd->hBufferDataDC);
827 	}
828 	whd->buffer = 0;
829     whd->hBufferDataDC = 0;
830 }
831 
832 // events:
833 // 0 : create (HWND)
834 // 1 : destroy (0)
835 // 2 : close (0)
836 // 3 : char (c)
837 // 4 : MouseMove (XY)
838 // 5 : MouseEvent (XY)
839 // 6 : VScroll
840 // 7 : HScroll
841 // 8 : Key Modifier ON
842 // 9 : Key Modifier OFF
843 // 11 : Mouse Event (mouse)
844 // 20 : SIZE (WH)
845 // 30 : active
846 // 31 : inactive
847 LRESULT CALLBACK
BaseWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)848 BaseWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){
849     window_handler_data* whd = (window_handler_data *)GetWindowLongPtr(hWnd,GWL_USERDATA);
850 	PAINTSTRUCT ps;
851 	HDC hDC;
852 	RECT r;
853 
854     switch(msg){
855 	case WM_PAINT:
856 		if(whd->hBufferDataDC){
857 			hDC = BeginPaint(hWnd,&ps);
858 			GetClientRect(hWnd,&r);
859             EnterCriticalSection(&whd->cs);
860 			BitBlt(hDC,0,0,r.right,r.bottom,whd->hBufferDataDC,0,0,SRCCOPY);
861             LeaveCriticalSection(&whd->cs);
862 			EndPaint(hWnd,&ps);
863 		}
864 		return 0;
865 	case WM_ERASEBKGND:
866 		return 0;
867     case WM_CREATE:
868         whd = (window_handler_data *)(((CREATESTRUCT *)lParam)->lpCreateParams);
869         SetWindowLongPtrW(hWnd,GWL_USERDATA,(LONG_PTR)whd);
870         post_window_event(whd,0,(uintptr_t)hWnd);
871         return 0;
872     case WM_DESTROY:
873 		clearbuffer(whd);
874         post_window_event(whd,1,0);
875         whd->enable=0;
876         return 0;
877     case WM_CLOSE:
878         post_window_event(whd,2,0);
879         return 0;
880     case WM_CHAR:
881         post_window_event(whd,3,wParam); // UTF-16 keycode
882         return 0;
883     case WM_MOUSEMOVE:
884         post_window_event(whd,4,lParam);
885         return 0;
886     case WM_MOUSEWHEEL:
887         post_window_event(whd,6,GET_WHEEL_DELTA_WPARAM(wParam));
888         return 0;
889     case WM_MOUSEHWHEEL:
890         post_window_event(whd,7,GET_WHEEL_DELTA_WPARAM(wParam));
891         return 0;
892     case WM_SIZE:
893         post_window_event(whd,20,lParam);
894         return 0;
895 	case WM_USER:
896 		DestroyWindow(hWnd);
897 		return 0;
898 	case WM_ACTIVATE:
899 		if(wParam == WA_INACTIVE){
900 			post_window_event(whd,31,0);
901 		}else{
902 			post_window_event(whd,30,0);
903 		}
904 		goto do_default;
905     // mouse keys
906     // keyboard keys
907 do_default:
908     default:
909         return DefWindowProcW(hWnd, msg, wParam, lParam);
910     }
911 }
912 
913 void
win32_window_move(void * hWnd,signed int x,signed int y,signed int w,signed int h)914 win32_window_move(void* hWnd,signed int x,signed int y,signed int w,signed int h){
915     MoveWindow((HWND)hWnd,x,y,w,h,TRUE);
916 }
917 
918 
919 void
win32_window_fitbuffer(void * p)920 win32_window_fitbuffer(void* p){
921 	window_handler_data* whd = (window_handler_data *)p;
922 	RECT r;
923 	HDC hBufferDataDC;
924 	HBITMAP buffer;
925     HWND hWnd = whd->hWnd;
926 	GetClientRect(hWnd,&r);
927 
928 	clearbuffer(whd);
929 	hBufferDataDC = CreateCompatibleDC(NULL);
930 
931 	buffer = CreateCompatibleBitmap(hBufferDataDC,r.right,r.bottom);
932     SelectObject(hBufferDataDC,buffer);
933 
934     whd->hBufferDataDC = hBufferDataDC;
935 	whd->buffer = buffer;
936 }
937 
938 // 0 = not activate, 1 = activate
939 void
win32_window_show(void * hWnd,int cmd)940 win32_window_show(void* hWnd,int cmd){
941     int sw;
942     switch(cmd){
943     case 1:
944         sw = SW_SHOW;
945         break;
946     case 0:
947         sw = SW_SHOWNA;
948     }
949     ShowWindow((HWND)hWnd,sw);
950 	UpdateWindow((HWND)hWnd);
951 }
952 
953 void
win32_window_hide(void * hWnd)954 win32_window_hide(void* hWnd){
955     ShowWindow((HWND)hWnd,SW_HIDE);
956 }
957 
958 void
win32_window_settitle(void * hWnd,wchar_t * text)959 win32_window_settitle(void* hWnd,wchar_t* text){
960     SetWindowTextW((HWND)hWnd,text);
961 }
962 
963 void
win32_window_close(void * hWnd)964 win32_window_close(void* hWnd){
965     CloseWindow((HWND)hWnd);
966 }
967 
968 void
win32_window_destroy(void * hWnd)969 win32_window_destroy(void* hWnd){
970     PostMessage((HWND)hWnd,WM_USER,0,0);
971 }
972 
973 void
win32_registerwindowclass(void)974 win32_registerwindowclass(void){
975     WNDCLASSEXW cls;
976     ZeroMemory(&cls,sizeof(cls));
977     cls.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
978     cls.cbSize = sizeof(cls);
979     cls.lpfnWndProc = BaseWndProc;
980     cls.hInstance = (HINSTANCE)GetModuleHandle(0);
981     cls.lpszClassName = L"nmosh win32";
982     cls.style = CS_HREDRAW|CS_VREDRAW;
983 
984     RegisterClassExW(&cls);
985 }
986 
987 // freed by overlapped_free
988 void*
win32_window_alloc(void)989 win32_window_alloc(void){
990     return GC_MALLOC_UNCOLLECTABLE(sizeof(window_handler_data));
991 }
992 
993 void
win32_window_create(void * iocp,void * overlapped)994 win32_window_create(void* iocp,void* overlapped){
995     window_handler_data *whd = (window_handler_data *)overlapped;
996     whd->iocp = iocp;
997     whd->hBufferDataDC = 0;
998 	whd->buffer = 0;
999     InitializeCriticalSection(&whd->cs);
1000 
1001 	_beginthread(window_handler,0,overlapped);
1002 }
1003 
1004 typedef struct{
1005     int ignorecount;
1006     int cmd;
1007     int valid;
1008     int x0;
1009     int y0;
1010     int x1;
1011     int y1;
1012 }monitor_enum_state;
1013 
1014 static BOOL CALLBACK
monitorenum_handler(HMONITOR hMoni,HDC bogus0,LPRECT lprcMoni,monitor_enum_state * s)1015 monitorenum_handler(HMONITOR hMoni,HDC bogus0,LPRECT lprcMoni,monitor_enum_state* s){
1016     MONITORINFO mi;
1017     mi.cbSize = sizeof(mi);
1018     if(s->ignorecount){
1019         s->ignorecount--;
1020         return TRUE; // continue
1021     }else{
1022         s->valid = 1;
1023         if(s->cmd==0){
1024             s->x0 = lprcMoni->left;
1025             s->y0 = lprcMoni->top;
1026             s->x1 = lprcMoni->right;
1027             s->y1 = lprcMoni->bottom;
1028         }else{
1029             GetMonitorInfo(hMoni,&mi);
1030             s->x0 = mi.rcWork.left;
1031             s->y0 = mi.rcWork.top;
1032             s->x1 = mi.rcWork.right;
1033             s->y1 = mi.rcWork.bottom;
1034         }
1035         return FALSE; // stop
1036     }
1037 }
1038 
1039 // cmd 0 = phys area, 1 = work area (i.e. excludes taskbar)
1040 void
win32_getmonitorinfo(int id,int cmd,signed int * valid,signed int * x0,signed int * y0,signed int * x1,signed int * y1)1041 win32_getmonitorinfo(int id,int cmd,signed int *valid,signed int *x0,signed int* y0,signed int *x1,signed int *y1){
1042     monitor_enum_state s;
1043     s.valid = 0;
1044     s.ignorecount = id;
1045     s.cmd = cmd;
1046     EnumDisplayMonitors(NULL,NULL,(MONITORENUMPROC)monitorenum_handler,(LPARAM)&s);
1047     *valid = s.valid;
1048     *x0 = s.x0;
1049     *y0 = s.y0;
1050     *x1 = s.x1;
1051     *y1 = s.y1;
1052 }
1053 
1054 /* bitmap drawing */
1055 
1056 // FIXME: compose rgn?
1057 
1058 static void
performupdate(HDC hDCBuf,HDC hDCSrc,int x0,int y0,int x1,int y1)1059 performupdate(HDC hDCBuf,HDC hDCSrc,int x0,int y0,int x1,int y1){
1060     BitBlt(hDCBuf,x0,y0,x1,y1,hDCSrc,x0,y0,SRCCOPY);
1061 }
1062 
1063 static void
sendupdate(HWND hWnd,int x0,int y0,int x1,int y1)1064 sendupdate(HWND hWnd,int x0,int y0,int x1,int y1){
1065     RECT r;
1066     r.left = x0;
1067     r.top = y0;
1068     r.right = x1;
1069     r.bottom = y1;
1070 
1071     InvalidateRect(hWnd,&r,FALSE);
1072 }
1073 
1074 // N.B.: dc should select Buffer surface before call this
1075 void
win32_window_updaterects(void * w,void * dc,int * rects,int count)1076 win32_window_updaterects(void* w,void* dc,int* rects, int count){
1077     window_handler_data* whd = (window_handler_data *)w;
1078     HDC hDC = (HDC)dc;
1079     int i,p;
1080     XFORM current;
1081     GetWorldTransform(hDC,&current);
1082     ModifyWorldTransform(hDC,NULL,MWT_IDENTITY);
1083     EnterCriticalSection(&whd->cs);
1084     for(i=0;i!=count;i++){
1085         p = i*4;
1086         performupdate(whd->hBufferDataDC,hDC,rects[p],rects[p+1],rects[p+2],rects[p+3]);
1087     }
1088     LeaveCriticalSection(&whd->cs);
1089     for(i=0;i!=count;i++){
1090         p = i*4;
1091         sendupdate(whd->hWnd,rects[p],rects[p+1],rects[p+2],rects[p+3]);
1092     }
1093     SetWorldTransform(hDC,&current);
1094 }
1095 
1096 void*
win32_window_createbitmap(void * w,int x,int y)1097 win32_window_createbitmap(void *w,int x,int y){
1098     window_handler_data *whd = (window_handler_data *)w;
1099     return CreateCompatibleBitmap(whd->hBufferDataDC,x,y);
1100 }
1101 
1102 int
win32_window_getclientrect_x(void * h)1103 win32_window_getclientrect_x(void* h){
1104     HWND hWnd = (HWND)h;
1105     RECT r;
1106     GetClientRect(hWnd,&r);
1107     return r.right;
1108 }
1109 
1110 int
win32_window_getclientrect_y(void * h)1111 win32_window_getclientrect_y(void* h){
1112     HWND hWnd = (HWND)h;
1113     RECT r;
1114     GetClientRect(hWnd,&r);
1115     return r.bottom;
1116 }
1117 
1118 // Device Context
1119 void*
win32_dc_create(void)1120 win32_dc_create(void){
1121     HDC hDC;
1122     hDC = CreateCompatibleDC(NULL);
1123     SetGraphicsMode(hDC,GM_ADVANCED); // enable matrix op
1124     return hDC;
1125 }
1126 
1127 void
win32_dc_dispose(void * d)1128 win32_dc_dispose(void* d){
1129     HDC hDC = (HDC)d;
1130     DeleteDC(hDC);
1131 }
1132 
1133 void
win32_dc_selectobject(void * d,void * obj)1134 win32_dc_selectobject(void* d,void* obj){
1135     HDC hDC = (HDC)d;
1136     HGDIOBJ hobj = (HGDIOBJ)obj;
1137     SelectObject(hDC,hobj);
1138 }
1139 
1140 void
win32_dc_transform(void * d,void * m)1141 win32_dc_transform(void* d,void* m){
1142     HDC hDC = (HDC)d;
1143     window_handler_data* whd = (window_handler_data *)d;
1144     XFORM* xf = (XFORM *)m;
1145     ModifyWorldTransform(hDC,xf,MWT_RIGHTMULTIPLY);
1146 }
1147 
1148 void
win32_dc_settransform(void * d,void * m)1149 win32_dc_settransform(void* d,void* m){
1150     HDC hDC = (HDC)d;
1151     XFORM* xf = (XFORM *)m;
1152     SetWorldTransform(hDC,xf);
1153 }
1154 
1155 
1156 // Generic GDI Object management(bitmap brush pen font)
1157 void
win32_gdi_deleteobject(void * obj)1158 win32_gdi_deleteobject(void* obj){
1159     HGDIOBJ hobj = (HGDIOBJ)obj;
1160     DeleteObject(hobj);
1161 }
1162 
1163 void*
win32_pen_create(int w,int r,int g,int b)1164 win32_pen_create(int w,int r,int g,int b){
1165     return CreatePen(PS_SOLID,w,RGB(r,g,b));
1166 }
1167 
1168 void*
win32_brush_create(int r,int g,int b)1169 win32_brush_create(int r,int g,int b){
1170     return CreateSolidBrush(RGB(r,g,b));
1171 }
1172 
1173 void*
win32_font_create(int h,int weight,int italicp,wchar_t * face)1174 win32_font_create(int h,int weight,int italicp,wchar_t* face){
1175     return CreateFontW(h,0,0,0,weight,italicp,0,0,DEFAULT_CHARSET,0,0,0,0,face);
1176 }
1177 
1178 // DRAW OPS
1179 // PATH:
1180  // 90 BEGIN_PATH
1181  // 91 CLOSE_PATH
1182  // 1 MOVE [X Y]
1183  // 2 LINE [X Y]
1184  // 3 QCURVE [CPX CPY X Y]
1185  // 4 BCURVE [CP1X CP1Y CP2X CP2Y X Y]
1186  // 5 ARCTO [X1 Y1 X2 Y2 R]
1187  // 6 ARC [X Y R startA endA ACLW?]
1188  // 7 RECT [X Y W H]
1189 // DRAW:
1190  // 8 FILL
1191  // 9 STROKE
1192  // 10 FILLSTROKE
1193  // -- CLIP
1194  // -- ISPOINTINPATH [X Y]
1195 
1196 // bmpdc will only be used if BLT occur. bmpdc shouldn't be transformed.
1197 void
win32_dc_draw(void * dc,void * bmpdc,intptr_t * ops,int len)1198 win32_dc_draw(void* dc,void* bmpdc,intptr_t* ops,int len){
1199     int p = 0;
1200     int* arg;
1201     HDC hDC = (HDC)dc;
1202     HDC hBmpDC = (HDC)bmpdc;
1203     POINT pbuf[3];
1204 
1205     while(p!=len){
1206         arg = &ops[p];
1207         switch(arg[0]){
1208 // Path control
1209  // 90 BEGIN_PATH
1210  // 91 CLOSE_PATH
1211         case 90:
1212             BeginPath(hDC);
1213             p++;
1214             continue;
1215         case 91:
1216             EndPath(hDC);
1217             p++;
1218             continue;
1219 
1220 // Primitives
1221         case 1: //MOVE [X Y]
1222             MoveToEx(hDC,arg[1],arg[2],NULL);
1223             p+=3;
1224             continue;
1225         case 2: //LINE [X Y]
1226             LineTo(hDC,arg[1],arg[2]);
1227             p+=3;
1228             continue;
1229         case 3: //QCURVE [CX CY X Y]
1230             // FIXME: WRONG
1231             pbuf[0].x = arg[1];
1232             pbuf[0].y = arg[2];
1233             pbuf[1].x = arg[1];
1234             pbuf[1].y = arg[2];
1235             pbuf[2].x = arg[3];
1236             pbuf[2].y = arg[4];
1237             PolyBezierTo(hDC,pbuf,3);
1238             p+=5;
1239             continue;
1240         case 4: //BCURVE [C0X C0Y C1X C1Y X Y]
1241             pbuf[0].x = arg[1];
1242             pbuf[0].y = arg[2];
1243             pbuf[1].x = arg[3];
1244             pbuf[1].y = arg[4];
1245             pbuf[2].x = arg[5];
1246             pbuf[2].y = arg[6];
1247             PolyBezierTo(hDC,pbuf,3);
1248             p+=7;
1249             continue;
1250  // 5 ARCTO [X1 Y1 X2 Y2 R]
1251  // 6 ARC [X Y R startA endA ACLW?]
1252  // 7 RECT [X Y W H]
1253 // DRAW:
1254  // 8 FILL
1255         case 8:
1256             FillPath(hDC);
1257             p++;
1258             continue;
1259  // 9 STROKE
1260         case 9:
1261             StrokePath(hDC);
1262             p++;
1263             continue;
1264  // 10 STROKEFILL
1265         case 10:
1266             StrokeAndFillPath(hDC);
1267             p++;
1268             continue;
1269 // Text:
1270  // 20 TEXT [X Y LEN TEXT_PTR] // N.B. Text won't use current point
1271         case 20:
1272             TextOutW(hDC,arg[2],arg[3],(LPCWSTR)arg[1],arg[4]);
1273             p+=5;
1274             continue;
1275 // GDI Local
1276  // 30 SELECT_OBJECT [PTR]
1277         case 30:
1278             SelectObject(hDC,(HGDIOBJ)arg[1]);
1279             p+=2;
1280             continue;
1281 // 31 BLT [HBITMAP XD YD X0 Y0 X1 Y1] // N.B. This cannot COPY on same bitmap
1282         case 31:
1283             SelectObject(hBmpDC,(HGDIOBJ)arg[1]);
1284             BitBlt(hDC,arg[4],arg[5],arg[6],arg[7],hBmpDC,arg[2],arg[3],SRCCOPY);
1285             p+=8;
1286             continue;
1287         }
1288     }
1289 }
1290 
1291 int // BOOL
win32_dc_measure_text(void * d,wchar_t * str,int len,int * x,int * y)1292 win32_dc_measure_text(void* d,wchar_t* str,int len,int* x,int* y){
1293     BOOL b;
1294     HDC hDC = (HDC)d;
1295     SIZE s;
1296     b = GetTextExtentPoint32W(hDC,str,len,&s);
1297     *x=s.cx;
1298     *y=s.cy;
1299     return b;
1300 }
1301 
1302 /* misc */
1303 
1304 
1305 // from http://stackoverflow.com/questions/150355/programmatically-find-the-number-of-cores-on-a-machine
1306 int
win32_get_processor_count(void)1307 win32_get_processor_count(void){
1308     SYSTEM_INFO si;
1309     GetSystemInfo(&si);
1310     return si.dwNumberOfProcessors;
1311 }
1312 
1313 int
win32_get_ansi_codepage(void)1314 win32_get_ansi_codepage(void){
1315     return GetACP();
1316 }
1317 
1318 // 1: success, otherwise: error
1319 // N.B.: Do not feed null strings
1320 int
win32_multibyte_to_widechar(int cp,void * input,int input_count,void * output,int output_count,int * output_size)1321 win32_multibyte_to_widechar(int cp, void* input, int input_count, void* output, int output_count, int* output_size){
1322     int ret;
1323     ret = MultiByteToWideChar(cp,0,(LPCSTR)input,input_count,(LPWSTR)output,output_count);
1324     if(!ret){ // error
1325         *output_size = 0;
1326         return -1;
1327     }else{
1328         *output_size = ret * 2;
1329         return 1;
1330     }
1331 }
1332 
1333 // 0<: success
1334 // N.B.: Do not feed null strings
1335 int
win32_measure_multibyte_to_widechar(int cp,void * input,int input_count)1336 win32_measure_multibyte_to_widechar(int cp, void* input, int input_count){
1337     int ret;
1338     ret = MultiByteToWideChar(cp,0,(LPCSTR)input,input_count,(LPWSTR)NULL,0);
1339     return ret*2;
1340 }
1341 
1342 // 1 = success, otherwise = failure
1343 int
win32_mypath(wchar_t * buf,int len)1344 win32_mypath(wchar_t* buf,int len){
1345     int ret;
1346     ret = GetModuleFileNameW(NULL,buf,len);
1347     if(ret==len||ret==0){
1348         return -1; // fail
1349     }else{
1350         return 1;
1351     }
1352 }
1353