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,¤t);
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,¤t);
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