dll_windows.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. // Copyright 2011 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package windows
  5. import (
  6. "sync"
  7. "sync/atomic"
  8. "unsafe"
  9. )
  10. // DLLError describes reasons for DLL load failures.
  11. type DLLError struct {
  12. Err error
  13. ObjName string
  14. Msg string
  15. }
  16. func (e *DLLError) Error() string { return e.Msg }
  17. // Implemented in runtime/syscall_windows.goc.
  18. func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
  19. func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
  20. func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
  21. func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2 uintptr, err Errno)
  22. func Syscall15(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2 uintptr, err Errno)
  23. func loadlibrary(filename *uint16) (handle uintptr, err Errno) // TODO: must be exported.
  24. func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno) // TODO: must be exported.
  25. // A DLL implements access to a single DLL.
  26. type DLL struct {
  27. Name string
  28. Handle Handle
  29. }
  30. // LoadDLL loads DLL file into memory.
  31. func LoadDLL(name string) (dll *DLL, err error) {
  32. namep, err := UTF16PtrFromString(name)
  33. if err != nil {
  34. return nil, err
  35. }
  36. h, e := loadlibrary(namep)
  37. if e != 0 {
  38. return nil, &DLLError{
  39. Err: e,
  40. ObjName: name,
  41. Msg: "Failed to load " + name + ": " + e.Error(),
  42. }
  43. }
  44. d := &DLL{
  45. Name: name,
  46. Handle: Handle(h),
  47. }
  48. return d, nil
  49. }
  50. // MustLoadDLL is like LoadDLL but panics if load operation failes.
  51. func MustLoadDLL(name string) *DLL {
  52. d, e := LoadDLL(name)
  53. if e != nil {
  54. panic(e)
  55. }
  56. return d
  57. }
  58. // FindProc searches DLL d for procedure named name and returns *Proc
  59. // if found. It returns an error if search fails.
  60. func (d *DLL) FindProc(name string) (proc *Proc, err error) {
  61. namep, err := BytePtrFromString(name)
  62. if err != nil {
  63. return nil, err
  64. }
  65. a, e := getprocaddress(uintptr(d.Handle), namep)
  66. if e != 0 {
  67. return nil, &DLLError{
  68. Err: e,
  69. ObjName: name,
  70. Msg: "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
  71. }
  72. }
  73. p := &Proc{
  74. Dll: d,
  75. Name: name,
  76. addr: a,
  77. }
  78. return p, nil
  79. }
  80. // MustFindProc is like FindProc but panics if search fails.
  81. func (d *DLL) MustFindProc(name string) *Proc {
  82. p, e := d.FindProc(name)
  83. if e != nil {
  84. panic(e)
  85. }
  86. return p
  87. }
  88. // Release unloads DLL d from memory.
  89. func (d *DLL) Release() (err error) {
  90. return FreeLibrary(d.Handle)
  91. }
  92. // A Proc implements access to a procedure inside a DLL.
  93. type Proc struct {
  94. Dll *DLL
  95. Name string
  96. addr uintptr
  97. }
  98. // Addr returns the address of the procedure represented by p.
  99. // The return value can be passed to Syscall to run the procedure.
  100. func (p *Proc) Addr() uintptr {
  101. return p.addr
  102. }
  103. // Call executes procedure p with arguments a. It will panic, if more then 15 arguments
  104. // are supplied.
  105. //
  106. // The returned error is always non-nil, constructed from the result of GetLastError.
  107. // Callers must inspect the primary return value to decide whether an error occurred
  108. // (according to the semantics of the specific function being called) before consulting
  109. // the error. The error will be guaranteed to contain windows.Errno.
  110. func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
  111. switch len(a) {
  112. case 0:
  113. return Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
  114. case 1:
  115. return Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
  116. case 2:
  117. return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
  118. case 3:
  119. return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
  120. case 4:
  121. return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
  122. case 5:
  123. return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
  124. case 6:
  125. return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
  126. case 7:
  127. return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
  128. case 8:
  129. return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0)
  130. case 9:
  131. return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8])
  132. case 10:
  133. return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], 0, 0)
  134. case 11:
  135. return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], 0)
  136. case 12:
  137. return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11])
  138. case 13:
  139. return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], 0, 0)
  140. case 14:
  141. return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], 0)
  142. case 15:
  143. return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14])
  144. default:
  145. panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
  146. }
  147. return
  148. }
  149. // A LazyDLL implements access to a single DLL.
  150. // It will delay the load of the DLL until the first
  151. // call to its Handle method or to one of its
  152. // LazyProc's Addr method.
  153. type LazyDLL struct {
  154. mu sync.Mutex
  155. dll *DLL // non nil once DLL is loaded
  156. Name string
  157. }
  158. // Load loads DLL file d.Name into memory. It returns an error if fails.
  159. // Load will not try to load DLL, if it is already loaded into memory.
  160. func (d *LazyDLL) Load() error {
  161. // Non-racy version of:
  162. // if d.dll == nil {
  163. if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) == nil {
  164. d.mu.Lock()
  165. defer d.mu.Unlock()
  166. if d.dll == nil {
  167. dll, e := LoadDLL(d.Name)
  168. if e != nil {
  169. return e
  170. }
  171. // Non-racy version of:
  172. // d.dll = dll
  173. atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll))
  174. }
  175. }
  176. return nil
  177. }
  178. // mustLoad is like Load but panics if search fails.
  179. func (d *LazyDLL) mustLoad() {
  180. e := d.Load()
  181. if e != nil {
  182. panic(e)
  183. }
  184. }
  185. // Handle returns d's module handle.
  186. func (d *LazyDLL) Handle() uintptr {
  187. d.mustLoad()
  188. return uintptr(d.dll.Handle)
  189. }
  190. // NewProc returns a LazyProc for accessing the named procedure in the DLL d.
  191. func (d *LazyDLL) NewProc(name string) *LazyProc {
  192. return &LazyProc{l: d, Name: name}
  193. }
  194. // NewLazyDLL creates new LazyDLL associated with DLL file.
  195. func NewLazyDLL(name string) *LazyDLL {
  196. return &LazyDLL{Name: name}
  197. }
  198. // A LazyProc implements access to a procedure inside a LazyDLL.
  199. // It delays the lookup until the Addr method is called.
  200. type LazyProc struct {
  201. mu sync.Mutex
  202. Name string
  203. l *LazyDLL
  204. proc *Proc
  205. }
  206. // Find searches DLL for procedure named p.Name. It returns
  207. // an error if search fails. Find will not search procedure,
  208. // if it is already found and loaded into memory.
  209. func (p *LazyProc) Find() error {
  210. // Non-racy version of:
  211. // if p.proc == nil {
  212. if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
  213. p.mu.Lock()
  214. defer p.mu.Unlock()
  215. if p.proc == nil {
  216. e := p.l.Load()
  217. if e != nil {
  218. return e
  219. }
  220. proc, e := p.l.dll.FindProc(p.Name)
  221. if e != nil {
  222. return e
  223. }
  224. // Non-racy version of:
  225. // p.proc = proc
  226. atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
  227. }
  228. }
  229. return nil
  230. }
  231. // mustFind is like Find but panics if search fails.
  232. func (p *LazyProc) mustFind() {
  233. e := p.Find()
  234. if e != nil {
  235. panic(e)
  236. }
  237. }
  238. // Addr returns the address of the procedure represented by p.
  239. // The return value can be passed to Syscall to run the procedure.
  240. func (p *LazyProc) Addr() uintptr {
  241. p.mustFind()
  242. return p.proc.Addr()
  243. }
  244. // Call executes procedure p with arguments a. It will panic, if more then 15 arguments
  245. // are supplied.
  246. //
  247. // The returned error is always non-nil, constructed from the result of GetLastError.
  248. // Callers must inspect the primary return value to decide whether an error occurred
  249. // (according to the semantics of the specific function being called) before consulting
  250. // the error. The error will be guaranteed to contain windows.Errno.
  251. func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
  252. p.mustFind()
  253. return p.proc.Call(a...)
  254. }