dll_windows.go 7.8 KB

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