1 /* 2 * This file is part of gtkD. 3 * 4 * gtkD is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License 6 * as published by the Free Software Foundation; either version 3 7 * of the License, or (at your option) any later version, with 8 * some exceptions, please read the COPYING file. 9 * 10 * gtkD is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public License 16 * along with gtkD; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA 18 */ 19 20 // generated automatically - do not change 21 // find conversion definition on APILookup.txt 22 // implement new conversion functionalities on the wrap.utils pakage 23 24 25 module gio.Subprocess; 26 27 private import gio.AsyncResultIF; 28 private import gio.Cancellable; 29 private import gio.InitableIF; 30 private import gio.InitableT; 31 private import gio.InputStream; 32 private import gio.OutputStream; 33 private import gio.c.functions; 34 public import gio.c.types; 35 private import glib.Bytes; 36 private import glib.ConstructionException; 37 private import glib.ErrorG; 38 private import glib.GException; 39 private import glib.Str; 40 private import glib.c.functions; 41 private import gobject.ObjectG; 42 43 44 /** 45 * #GSubprocess allows the creation of and interaction with child 46 * processes. 47 * 48 * Processes can be communicated with using standard GIO-style APIs (ie: 49 * #GInputStream, #GOutputStream). There are GIO-style APIs to wait for 50 * process termination (ie: cancellable and with an asynchronous 51 * variant). 52 * 53 * There is an API to force a process to terminate, as well as a 54 * race-free API for sending UNIX signals to a subprocess. 55 * 56 * One major advantage that GIO brings over the core GLib library is 57 * comprehensive API for asynchronous I/O, such 58 * g_output_stream_splice_async(). This makes GSubprocess 59 * significantly more powerful and flexible than equivalent APIs in 60 * some other languages such as the `subprocess.py` 61 * included with Python. For example, using #GSubprocess one could 62 * create two child processes, reading standard output from the first, 63 * processing it, and writing to the input stream of the second, all 64 * without blocking the main loop. 65 * 66 * A powerful g_subprocess_communicate() API is provided similar to the 67 * `communicate()` method of `subprocess.py`. This enables very easy 68 * interaction with a subprocess that has been opened with pipes. 69 * 70 * #GSubprocess defaults to tight control over the file descriptors open 71 * in the child process, avoiding dangling-fd issues that are caused by 72 * a simple fork()/exec(). The only open file descriptors in the 73 * spawned process are ones that were explicitly specified by the 74 * #GSubprocess API (unless %G_SUBPROCESS_FLAGS_INHERIT_FDS was 75 * specified). 76 * 77 * #GSubprocess will quickly reap all child processes as they exit, 78 * avoiding "zombie processes" remaining around for long periods of 79 * time. g_subprocess_wait() can be used to wait for this to happen, 80 * but it will happen even without the call being explicitly made. 81 * 82 * As a matter of principle, #GSubprocess has no API that accepts 83 * shell-style space-separated strings. It will, however, match the 84 * typical shell behaviour of searching the PATH for executables that do 85 * not contain a directory separator in their name. 86 * 87 * #GSubprocess attempts to have a very simple API for most uses (ie: 88 * spawning a subprocess with arguments and support for most typical 89 * kinds of input and output redirection). See g_subprocess_new(). The 90 * #GSubprocessLauncher API is provided for more complicated cases 91 * (advanced types of redirection, environment variable manipulation, 92 * change of working directory, child setup functions, etc). 93 * 94 * A typical use of #GSubprocess will involve calling 95 * g_subprocess_new(), followed by g_subprocess_wait_async() or 96 * g_subprocess_wait(). After the process exits, the status can be 97 * checked using functions such as g_subprocess_get_if_exited() (which 98 * are similar to the familiar WIFEXITED-style POSIX macros). 99 * 100 * Since: 2.40 101 */ 102 public class Subprocess : ObjectG, InitableIF 103 { 104 /** the main Gtk struct */ 105 protected GSubprocess* gSubprocess; 106 107 /** Get the main Gtk struct */ 108 public GSubprocess* getSubprocessStruct(bool transferOwnership = false) 109 { 110 if (transferOwnership) 111 ownedRef = false; 112 return gSubprocess; 113 } 114 115 /** the main Gtk struct as a void* */ 116 protected override void* getStruct() 117 { 118 return cast(void*)gSubprocess; 119 } 120 121 /** 122 * Sets our main struct and passes it to the parent class. 123 */ 124 public this (GSubprocess* gSubprocess, bool ownedRef = false) 125 { 126 this.gSubprocess = gSubprocess; 127 super(cast(GObject*)gSubprocess, ownedRef); 128 } 129 130 // add the Initable capabilities 131 mixin InitableT!(GSubprocess); 132 133 134 /** */ 135 public static GType getType() 136 { 137 return g_subprocess_get_type(); 138 } 139 140 /** 141 * Create a new process with the given flags and argument list. 142 * 143 * The argument list is expected to be %NULL-terminated. 144 * 145 * Params: 146 * argv = commandline arguments for the subprocess 147 * flags = flags that define the behaviour of the subprocess 148 * 149 * Returns: A newly created #GSubprocess, or %NULL on error (and @error 150 * will be set) 151 * 152 * Since: 2.40 153 * 154 * Throws: GException on failure. 155 * Throws: ConstructionException GTK+ fails to create the object. 156 */ 157 public this(string[] argv, GSubprocessFlags flags) 158 { 159 GError* err = null; 160 161 auto __p = g_subprocess_newv(Str.toStringzArray(argv), flags, &err); 162 163 if (err !is null) 164 { 165 throw new GException( new ErrorG(err) ); 166 } 167 168 if(__p is null) 169 { 170 throw new ConstructionException("null returned by newv"); 171 } 172 173 this(cast(GSubprocess*) __p, true); 174 } 175 176 /** 177 * Communicate with the subprocess until it terminates, and all input 178 * and output has been completed. 179 * 180 * If @stdin_buf is given, the subprocess must have been created with 181 * %G_SUBPROCESS_FLAGS_STDIN_PIPE. The given data is fed to the 182 * stdin of the subprocess and the pipe is closed (ie: EOF). 183 * 184 * At the same time (as not to cause blocking when dealing with large 185 * amounts of data), if %G_SUBPROCESS_FLAGS_STDOUT_PIPE or 186 * %G_SUBPROCESS_FLAGS_STDERR_PIPE were used, reads from those 187 * streams. The data that was read is returned in @stdout and/or 188 * the @stderr. 189 * 190 * If the subprocess was created with %G_SUBPROCESS_FLAGS_STDOUT_PIPE, 191 * @stdout_buf will contain the data read from stdout. Otherwise, for 192 * subprocesses not created with %G_SUBPROCESS_FLAGS_STDOUT_PIPE, 193 * @stdout_buf will be set to %NULL. Similar provisions apply to 194 * @stderr_buf and %G_SUBPROCESS_FLAGS_STDERR_PIPE. 195 * 196 * As usual, any output variable may be given as %NULL to ignore it. 197 * 198 * If you desire the stdout and stderr data to be interleaved, create 199 * the subprocess with %G_SUBPROCESS_FLAGS_STDOUT_PIPE and 200 * %G_SUBPROCESS_FLAGS_STDERR_MERGE. The merged result will be returned 201 * in @stdout_buf and @stderr_buf will be set to %NULL. 202 * 203 * In case of any error (including cancellation), %FALSE will be 204 * returned with @error set. Some or all of the stdin data may have 205 * been written. Any stdout or stderr data that has been read will be 206 * discarded. None of the out variables (aside from @error) will have 207 * been set to anything in particular and should not be inspected. 208 * 209 * In the case that %TRUE is returned, the subprocess has exited and the 210 * exit status inspection APIs (eg: g_subprocess_get_if_exited(), 211 * g_subprocess_get_exit_status()) may be used. 212 * 213 * You should not attempt to use any of the subprocess pipes after 214 * starting this function, since they may be left in strange states, 215 * even if the operation was cancelled. You should especially not 216 * attempt to interact with the pipes while the operation is in progress 217 * (either from another thread or if using the asynchronous version). 218 * 219 * Params: 220 * stdinBuf = data to send to the stdin of the subprocess, or %NULL 221 * cancellable = a #GCancellable 222 * stdoutBuf = data read from the subprocess stdout 223 * stderrBuf = data read from the subprocess stderr 224 * 225 * Returns: %TRUE if successful 226 * 227 * Since: 2.40 228 * 229 * Throws: GException on failure. 230 */ 231 public bool communicate(Bytes stdinBuf, Cancellable cancellable, out Bytes stdoutBuf, out Bytes stderrBuf) 232 { 233 GBytes* outstdoutBuf = null; 234 GBytes* outstderrBuf = null; 235 GError* err = null; 236 237 auto __p = g_subprocess_communicate(gSubprocess, (stdinBuf is null) ? null : stdinBuf.getBytesStruct(), (cancellable is null) ? null : cancellable.getCancellableStruct(), &outstdoutBuf, &outstderrBuf, &err) != 0; 238 239 if (err !is null) 240 { 241 throw new GException( new ErrorG(err) ); 242 } 243 244 stdoutBuf = new Bytes(outstdoutBuf); 245 stderrBuf = new Bytes(outstderrBuf); 246 247 return __p; 248 } 249 250 /** 251 * Asynchronous version of g_subprocess_communicate(). Complete 252 * invocation with g_subprocess_communicate_finish(). 253 * 254 * Params: 255 * stdinBuf = Input data, or %NULL 256 * cancellable = Cancellable 257 * callback = Callback 258 * userData = User data 259 */ 260 public void communicateAsync(Bytes stdinBuf, Cancellable cancellable, GAsyncReadyCallback callback, void* userData) 261 { 262 g_subprocess_communicate_async(gSubprocess, (stdinBuf is null) ? null : stdinBuf.getBytesStruct(), (cancellable is null) ? null : cancellable.getCancellableStruct(), callback, userData); 263 } 264 265 /** 266 * Complete an invocation of g_subprocess_communicate_async(). 267 * 268 * Params: 269 * result = Result 270 * stdoutBuf = Return location for stdout data 271 * stderrBuf = Return location for stderr data 272 * 273 * Throws: GException on failure. 274 */ 275 public bool communicateFinish(AsyncResultIF result, out Bytes stdoutBuf, out Bytes stderrBuf) 276 { 277 GBytes* outstdoutBuf = null; 278 GBytes* outstderrBuf = null; 279 GError* err = null; 280 281 auto __p = g_subprocess_communicate_finish(gSubprocess, (result is null) ? null : result.getAsyncResultStruct(), &outstdoutBuf, &outstderrBuf, &err) != 0; 282 283 if (err !is null) 284 { 285 throw new GException( new ErrorG(err) ); 286 } 287 288 stdoutBuf = new Bytes(outstdoutBuf); 289 stderrBuf = new Bytes(outstderrBuf); 290 291 return __p; 292 } 293 294 /** 295 * Like g_subprocess_communicate(), but validates the output of the 296 * process as UTF-8, and returns it as a regular NUL terminated string. 297 * 298 * On error, @stdout_buf and @stderr_buf will be set to undefined values and 299 * should not be used. 300 * 301 * Params: 302 * stdinBuf = data to send to the stdin of the subprocess, or %NULL 303 * cancellable = a #GCancellable 304 * stdoutBuf = data read from the subprocess stdout 305 * stderrBuf = data read from the subprocess stderr 306 * 307 * Throws: GException on failure. 308 */ 309 public bool communicateUtf8(string stdinBuf, Cancellable cancellable, out string stdoutBuf, out string stderrBuf) 310 { 311 char* outstdoutBuf = null; 312 char* outstderrBuf = null; 313 GError* err = null; 314 315 auto __p = g_subprocess_communicate_utf8(gSubprocess, Str.toStringz(stdinBuf), (cancellable is null) ? null : cancellable.getCancellableStruct(), &outstdoutBuf, &outstderrBuf, &err) != 0; 316 317 if (err !is null) 318 { 319 throw new GException( new ErrorG(err) ); 320 } 321 322 stdoutBuf = Str.toString(outstdoutBuf); 323 stderrBuf = Str.toString(outstderrBuf); 324 325 return __p; 326 } 327 328 /** 329 * Asynchronous version of g_subprocess_communicate_utf8(). Complete 330 * invocation with g_subprocess_communicate_utf8_finish(). 331 * 332 * Params: 333 * stdinBuf = Input data, or %NULL 334 * cancellable = Cancellable 335 * callback = Callback 336 * userData = User data 337 */ 338 public void communicateUtf8Async(string stdinBuf, Cancellable cancellable, GAsyncReadyCallback callback, void* userData) 339 { 340 g_subprocess_communicate_utf8_async(gSubprocess, Str.toStringz(stdinBuf), (cancellable is null) ? null : cancellable.getCancellableStruct(), callback, userData); 341 } 342 343 /** 344 * Complete an invocation of g_subprocess_communicate_utf8_async(). 345 * 346 * Params: 347 * result = Result 348 * stdoutBuf = Return location for stdout data 349 * stderrBuf = Return location for stderr data 350 * 351 * Throws: GException on failure. 352 */ 353 public bool communicateUtf8Finish(AsyncResultIF result, out string stdoutBuf, out string stderrBuf) 354 { 355 char* outstdoutBuf = null; 356 char* outstderrBuf = null; 357 GError* err = null; 358 359 auto __p = g_subprocess_communicate_utf8_finish(gSubprocess, (result is null) ? null : result.getAsyncResultStruct(), &outstdoutBuf, &outstderrBuf, &err) != 0; 360 361 if (err !is null) 362 { 363 throw new GException( new ErrorG(err) ); 364 } 365 366 stdoutBuf = Str.toString(outstdoutBuf); 367 stderrBuf = Str.toString(outstderrBuf); 368 369 return __p; 370 } 371 372 /** 373 * Use an operating-system specific method to attempt an immediate, 374 * forceful termination of the process. There is no mechanism to 375 * determine whether or not the request itself was successful; 376 * however, you can use g_subprocess_wait() to monitor the status of 377 * the process after calling this function. 378 * 379 * On Unix, this function sends %SIGKILL. 380 * 381 * Since: 2.40 382 */ 383 public void forceExit() 384 { 385 g_subprocess_force_exit(gSubprocess); 386 } 387 388 /** 389 * Check the exit status of the subprocess, given that it exited 390 * normally. This is the value passed to the exit() system call or the 391 * return value from main. 392 * 393 * This is equivalent to the system WEXITSTATUS macro. 394 * 395 * It is an error to call this function before g_subprocess_wait() and 396 * unless g_subprocess_get_if_exited() returned %TRUE. 397 * 398 * Returns: the exit status 399 * 400 * Since: 2.40 401 */ 402 public int getExitStatus() 403 { 404 return g_subprocess_get_exit_status(gSubprocess); 405 } 406 407 /** 408 * On UNIX, returns the process ID as a decimal string. 409 * On Windows, returns the result of GetProcessId() also as a string. 410 * If the subprocess has terminated, this will return %NULL. 411 * 412 * Returns: the subprocess identifier, or %NULL if the subprocess 413 * has terminated 414 * 415 * Since: 2.40 416 */ 417 public string getIdentifier() 418 { 419 return Str.toString(g_subprocess_get_identifier(gSubprocess)); 420 } 421 422 /** 423 * Check if the given subprocess exited normally (ie: by way of exit() 424 * or return from main()). 425 * 426 * This is equivalent to the system WIFEXITED macro. 427 * 428 * It is an error to call this function before g_subprocess_wait() has 429 * returned. 430 * 431 * Returns: %TRUE if the case of a normal exit 432 * 433 * Since: 2.40 434 */ 435 public bool getIfExited() 436 { 437 return g_subprocess_get_if_exited(gSubprocess) != 0; 438 } 439 440 /** 441 * Check if the given subprocess terminated in response to a signal. 442 * 443 * This is equivalent to the system WIFSIGNALED macro. 444 * 445 * It is an error to call this function before g_subprocess_wait() has 446 * returned. 447 * 448 * Returns: %TRUE if the case of termination due to a signal 449 * 450 * Since: 2.40 451 */ 452 public bool getIfSignaled() 453 { 454 return g_subprocess_get_if_signaled(gSubprocess) != 0; 455 } 456 457 /** 458 * Gets the raw status code of the process, as from waitpid(). 459 * 460 * This value has no particular meaning, but it can be used with the 461 * macros defined by the system headers such as WIFEXITED. It can also 462 * be used with g_spawn_check_exit_status(). 463 * 464 * It is more likely that you want to use g_subprocess_get_if_exited() 465 * followed by g_subprocess_get_exit_status(). 466 * 467 * It is an error to call this function before g_subprocess_wait() has 468 * returned. 469 * 470 * Returns: the (meaningless) waitpid() exit status from the kernel 471 * 472 * Since: 2.40 473 */ 474 public int getStatus() 475 { 476 return g_subprocess_get_status(gSubprocess); 477 } 478 479 /** 480 * Gets the #GInputStream from which to read the stderr output of 481 * @subprocess. 482 * 483 * The process must have been created with %G_SUBPROCESS_FLAGS_STDERR_PIPE, 484 * otherwise %NULL will be returned. 485 * 486 * Returns: the stderr pipe 487 * 488 * Since: 2.40 489 */ 490 public InputStream getStderrPipe() 491 { 492 auto __p = g_subprocess_get_stderr_pipe(gSubprocess); 493 494 if(__p is null) 495 { 496 return null; 497 } 498 499 return ObjectG.getDObject!(InputStream)(cast(GInputStream*) __p); 500 } 501 502 /** 503 * Gets the #GOutputStream that you can write to in order to give data 504 * to the stdin of @subprocess. 505 * 506 * The process must have been created with %G_SUBPROCESS_FLAGS_STDIN_PIPE and 507 * not %G_SUBPROCESS_FLAGS_STDIN_INHERIT, otherwise %NULL will be returned. 508 * 509 * Returns: the stdout pipe 510 * 511 * Since: 2.40 512 */ 513 public OutputStream getStdinPipe() 514 { 515 auto __p = g_subprocess_get_stdin_pipe(gSubprocess); 516 517 if(__p is null) 518 { 519 return null; 520 } 521 522 return ObjectG.getDObject!(OutputStream)(cast(GOutputStream*) __p); 523 } 524 525 /** 526 * Gets the #GInputStream from which to read the stdout output of 527 * @subprocess. 528 * 529 * The process must have been created with %G_SUBPROCESS_FLAGS_STDOUT_PIPE, 530 * otherwise %NULL will be returned. 531 * 532 * Returns: the stdout pipe 533 * 534 * Since: 2.40 535 */ 536 public InputStream getStdoutPipe() 537 { 538 auto __p = g_subprocess_get_stdout_pipe(gSubprocess); 539 540 if(__p is null) 541 { 542 return null; 543 } 544 545 return ObjectG.getDObject!(InputStream)(cast(GInputStream*) __p); 546 } 547 548 /** 549 * Checks if the process was "successful". A process is considered 550 * successful if it exited cleanly with an exit status of 0, either by 551 * way of the exit() system call or return from main(). 552 * 553 * It is an error to call this function before g_subprocess_wait() has 554 * returned. 555 * 556 * Returns: %TRUE if the process exited cleanly with a exit status of 0 557 * 558 * Since: 2.40 559 */ 560 public bool getSuccessful() 561 { 562 return g_subprocess_get_successful(gSubprocess) != 0; 563 } 564 565 /** 566 * Get the signal number that caused the subprocess to terminate, given 567 * that it terminated due to a signal. 568 * 569 * This is equivalent to the system WTERMSIG macro. 570 * 571 * It is an error to call this function before g_subprocess_wait() and 572 * unless g_subprocess_get_if_signaled() returned %TRUE. 573 * 574 * Returns: the signal causing termination 575 * 576 * Since: 2.40 577 */ 578 public int getTermSig() 579 { 580 return g_subprocess_get_term_sig(gSubprocess); 581 } 582 583 /** 584 * Sends the UNIX signal @signal_num to the subprocess, if it is still 585 * running. 586 * 587 * This API is race-free. If the subprocess has terminated, it will not 588 * be signalled. 589 * 590 * This API is not available on Windows. 591 * 592 * Params: 593 * signalNum = the signal number to send 594 * 595 * Since: 2.40 596 */ 597 public void sendSignal(int signalNum) 598 { 599 g_subprocess_send_signal(gSubprocess, signalNum); 600 } 601 602 /** 603 * Synchronously wait for the subprocess to terminate. 604 * 605 * After the process terminates you can query its exit status with 606 * functions such as g_subprocess_get_if_exited() and 607 * g_subprocess_get_exit_status(). 608 * 609 * This function does not fail in the case of the subprocess having 610 * abnormal termination. See g_subprocess_wait_check() for that. 611 * 612 * Cancelling @cancellable doesn't kill the subprocess. Call 613 * g_subprocess_force_exit() if it is desirable. 614 * 615 * Params: 616 * cancellable = a #GCancellable 617 * 618 * Returns: %TRUE on success, %FALSE if @cancellable was cancelled 619 * 620 * Since: 2.40 621 * 622 * Throws: GException on failure. 623 */ 624 public bool wait(Cancellable cancellable) 625 { 626 GError* err = null; 627 628 auto __p = g_subprocess_wait(gSubprocess, (cancellable is null) ? null : cancellable.getCancellableStruct(), &err) != 0; 629 630 if (err !is null) 631 { 632 throw new GException( new ErrorG(err) ); 633 } 634 635 return __p; 636 } 637 638 /** 639 * Wait for the subprocess to terminate. 640 * 641 * This is the asynchronous version of g_subprocess_wait(). 642 * 643 * Params: 644 * cancellable = a #GCancellable, or %NULL 645 * callback = a #GAsyncReadyCallback to call when the operation is complete 646 * userData = user_data for @callback 647 * 648 * Since: 2.40 649 */ 650 public void waitAsync(Cancellable cancellable, GAsyncReadyCallback callback, void* userData) 651 { 652 g_subprocess_wait_async(gSubprocess, (cancellable is null) ? null : cancellable.getCancellableStruct(), callback, userData); 653 } 654 655 /** 656 * Combines g_subprocess_wait() with g_spawn_check_exit_status(). 657 * 658 * Params: 659 * cancellable = a #GCancellable 660 * 661 * Returns: %TRUE on success, %FALSE if process exited abnormally, or 662 * @cancellable was cancelled 663 * 664 * Since: 2.40 665 * 666 * Throws: GException on failure. 667 */ 668 public bool waitCheck(Cancellable cancellable) 669 { 670 GError* err = null; 671 672 auto __p = g_subprocess_wait_check(gSubprocess, (cancellable is null) ? null : cancellable.getCancellableStruct(), &err) != 0; 673 674 if (err !is null) 675 { 676 throw new GException( new ErrorG(err) ); 677 } 678 679 return __p; 680 } 681 682 /** 683 * Combines g_subprocess_wait_async() with g_spawn_check_exit_status(). 684 * 685 * This is the asynchronous version of g_subprocess_wait_check(). 686 * 687 * Params: 688 * cancellable = a #GCancellable, or %NULL 689 * callback = a #GAsyncReadyCallback to call when the operation is complete 690 * userData = user_data for @callback 691 * 692 * Since: 2.40 693 */ 694 public void waitCheckAsync(Cancellable cancellable, GAsyncReadyCallback callback, void* userData) 695 { 696 g_subprocess_wait_check_async(gSubprocess, (cancellable is null) ? null : cancellable.getCancellableStruct(), callback, userData); 697 } 698 699 /** 700 * Collects the result of a previous call to 701 * g_subprocess_wait_check_async(). 702 * 703 * Params: 704 * result = the #GAsyncResult passed to your #GAsyncReadyCallback 705 * 706 * Returns: %TRUE if successful, or %FALSE with @error set 707 * 708 * Since: 2.40 709 * 710 * Throws: GException on failure. 711 */ 712 public bool waitCheckFinish(AsyncResultIF result) 713 { 714 GError* err = null; 715 716 auto __p = g_subprocess_wait_check_finish(gSubprocess, (result is null) ? null : result.getAsyncResultStruct(), &err) != 0; 717 718 if (err !is null) 719 { 720 throw new GException( new ErrorG(err) ); 721 } 722 723 return __p; 724 } 725 726 /** 727 * Collects the result of a previous call to 728 * g_subprocess_wait_async(). 729 * 730 * Params: 731 * result = the #GAsyncResult passed to your #GAsyncReadyCallback 732 * 733 * Returns: %TRUE if successful, or %FALSE with @error set 734 * 735 * Since: 2.40 736 * 737 * Throws: GException on failure. 738 */ 739 public bool waitFinish(AsyncResultIF result) 740 { 741 GError* err = null; 742 743 auto __p = g_subprocess_wait_finish(gSubprocess, (result is null) ? null : result.getAsyncResultStruct(), &err) != 0; 744 745 if (err !is null) 746 { 747 throw new GException( new ErrorG(err) ); 748 } 749 750 return __p; 751 } 752 }