github.com/iDigitalFlame/xmt@v0.5.4/cmd/dll.go (about)

     1  // Copyright (C) 2020 - 2023 iDigitalFlame
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU General Public License as published by
     5  // the Free Software Foundation, either version 3 of the License, or
     6  // any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU General Public License
    14  // along with this program.  If not, see <https://www.gnu.org/licenses/>.
    15  //
    16  
    17  package cmd
    18  
    19  import (
    20  	"context"
    21  	"time"
    22  )
    23  
    24  // DLL is a struct that can be used to reflectively load a DLL into the memory
    25  // of a selected process. Similar to the Assembly struct, this struct can only
    26  // be used on Windows devices and will return 'ErrNoWindows' on non-Windows devices.
    27  //
    28  // The 'SetParent*' function will attempt to set the target that loads the DLL.
    29  // If none are specified, the DLL will be loaded into the current process.
    30  type DLL struct {
    31  	Path    string
    32  	t       thread
    33  	Timeout time.Duration
    34  }
    35  
    36  // Run will start the DLL thread and wait until it completes. This function
    37  // will return the same errors as the 'Start' function if they occur or the
    38  // 'Wait' function if any errors occur during thread runtime.
    39  //
    40  // Always returns nil on non-Windows devices.
    41  func (d *DLL) Run() error {
    42  	if err := d.Start(); err != nil {
    43  		return err
    44  	}
    45  	return d.Wait()
    46  }
    47  
    48  // Stop will attempt to terminate the currently running thread.
    49  //
    50  // Always returns nil on non-Windows devices.
    51  func (d *DLL) Stop() error {
    52  	return d.t.Stop()
    53  }
    54  
    55  // Wait will block until the thread completes or is terminated by a call to
    56  // Stop.
    57  //
    58  // This function will return 'ErrNotStarted' if the thread has not been started.
    59  func (d *DLL) Wait() error {
    60  	if !d.t.Running() {
    61  		if err := d.Start(); err != nil {
    62  			return err
    63  		}
    64  	}
    65  	return d.t.Wait()
    66  }
    67  
    68  // NewDLL creates a new DLL instance that uses the supplied string as the DLL
    69  // file path. Similar to '&DLL{Path: p}'.
    70  func NewDLL(p string) *DLL {
    71  	return &DLL{Path: p}
    72  }
    73  
    74  // Running returns true if the current thread is running, false otherwise.
    75  func (d *DLL) Running() bool {
    76  	return d.t.Running()
    77  }
    78  
    79  // Release will attempt to release the resources for this DLL instance,
    80  // including handles.
    81  //
    82  // After the first call to this function, all other function calls will fail
    83  // with errors. Repeated calls to this function return nil and are a NOP.
    84  func (d *DLL) Release() error {
    85  	return d.t.Release()
    86  }
    87  
    88  // SetSuspended will delay the execution of this thread and will put the
    89  // thread in a suspended state until it is resumed using a Resume call.
    90  //
    91  // This function has no effect if the device is not running Windows.
    92  func (d *DLL) SetSuspended(s bool) {
    93  	d.t.SetSuspended(s)
    94  }
    95  
    96  // Done returns a channel that's closed when this DLL completes
    97  //
    98  // This can be used to monitor a DLL's status using a select statement.
    99  func (d *DLL) Done() <-chan struct{} {
   100  	return d.t.Done()
   101  }
   102  
   103  // ExitCode returns the Exit Code of the thread. If the thread is still running or
   104  // has not been started, this function returns an 'ErrNotCompleted' error.
   105  func (d *DLL) ExitCode() (int32, error) {
   106  	return d.t.ExitCode()
   107  }
   108  
   109  // Handle returns the handle of the current running thread. The return is an uintptr
   110  // that can converted into a Handle.
   111  //
   112  // This function returns an error if the thread was not started. The handle is
   113  // not expected to be valid after the thread exits or is terminated.
   114  func (d *DLL) Handle() (uintptr, error) {
   115  	return d.t.Handle()
   116  }
   117  
   118  // NewDLLContext creates a new DLL instance that uses the supplied string as
   119  // the DLL file path.
   120  //
   121  // This function accepts a context that can be used to control the cancellation
   122  // of the thread.
   123  func NewDLLContext(x context.Context, p string) *DLL {
   124  	return &DLL{Path: p, t: threadInit(x)}
   125  }