dll_windows.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  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. // We need to use LoadLibrary and GetProcAddress from the Go runtime, because
  12. // the these symbols are loaded by the system linker and are required to
  13. // dynamically load additional symbols. Note that in the Go runtime, these
  14. // return syscall.Handle and syscall.Errno, but these are the same, in fact,
  15. // as windows.Handle and windows.Errno, and we intend to keep these the same.
  16. //go:linkname syscall_loadlibrary syscall.loadlibrary
  17. func syscall_loadlibrary(filename *uint16) (handle Handle, err Errno)
  18. //go:linkname syscall_getprocaddress syscall.getprocaddress
  19. func syscall_getprocaddress(handle Handle, procname *uint8) (proc uintptr, err Errno)
  20. // DLLError describes reasons for DLL load failures.
  21. type DLLError struct {
  22. Err error
  23. ObjName string
  24. Msg string
  25. }
  26. func (e *DLLError) Error() string { return e.Msg }
  27. // A DLL implements access to a single DLL.
  28. type DLL struct {
  29. Name string
  30. Handle Handle
  31. }
  32. // LoadDLL loads DLL file into memory.
  33. //
  34. // Warning: using LoadDLL without an absolute path name is subject to
  35. // DLL preloading attacks. To safely load a system DLL, use LazyDLL
  36. // with System set to true, or use LoadLibraryEx directly.
  37. func LoadDLL(name string) (dll *DLL, err error) {
  38. namep, err := UTF16PtrFromString(name)
  39. if err != nil {
  40. return nil, err
  41. }
  42. h, e := syscall_loadlibrary(namep)
  43. if e != 0 {
  44. return nil, &DLLError{
  45. Err: e,
  46. ObjName: name,
  47. Msg: "Failed to load " + name + ": " + e.Error(),
  48. }
  49. }
  50. d := &DLL{
  51. Name: name,
  52. Handle: h,
  53. }
  54. return d, nil
  55. }
  56. // MustLoadDLL is like LoadDLL but panics if load operation failes.
  57. func MustLoadDLL(name string) *DLL {
  58. d, e := LoadDLL(name)
  59. if e != nil {
  60. panic(e)
  61. }
  62. return d
  63. }
  64. // FindProc searches DLL d for procedure named name and returns *Proc
  65. // if found. It returns an error if search fails.
  66. func (d *DLL) FindProc(name string) (proc *Proc, err error) {
  67. namep, err := BytePtrFromString(name)
  68. if err != nil {
  69. return nil, err
  70. }
  71. a, e := syscall_getprocaddress(d.Handle, namep)
  72. if e != 0 {
  73. return nil, &DLLError{
  74. Err: e,
  75. ObjName: name,
  76. Msg: "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
  77. }
  78. }
  79. p := &Proc{
  80. Dll: d,
  81. Name: name,
  82. addr: a,
  83. }
  84. return p, nil
  85. }
  86. // MustFindProc is like FindProc but panics if search fails.
  87. func (d *DLL) MustFindProc(name string) *Proc {
  88. p, e := d.FindProc(name)
  89. if e != nil {
  90. panic(e)
  91. }
  92. return p
  93. }
  94. // Release unloads DLL d from memory.
  95. func (d *DLL) Release() (err error) {
  96. return FreeLibrary(d.Handle)
  97. }
  98. // A Proc implements access to a procedure inside a DLL.
  99. type Proc struct {
  100. Dll *DLL
  101. Name string
  102. addr uintptr
  103. }
  104. // Addr returns the address of the procedure represented by p.
  105. // The return value can be passed to Syscall to run the procedure.
  106. func (p *Proc) Addr() uintptr {
  107. return p.addr
  108. }
  109. //go:uintptrescapes
  110. // Call executes procedure p with arguments a. It will panic, if more than 15 arguments
  111. // are supplied.
  112. //
  113. // The returned error is always non-nil, constructed from the result of GetLastError.
  114. // Callers must inspect the primary return value to decide whether an error occurred
  115. // (according to the semantics of the specific function being called) before consulting
  116. // the error. The error will be guaranteed to contain windows.Errno.
  117. func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
  118. switch len(a) {
  119. case 0:
  120. return syscall.Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
  121. case 1:
  122. return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
  123. case 2:
  124. return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
  125. case 3:
  126. return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
  127. case 4:
  128. return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
  129. case 5:
  130. return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
  131. case 6:
  132. return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
  133. case 7:
  134. return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
  135. case 8:
  136. 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)
  137. case 9:
  138. 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])
  139. case 10:
  140. 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)
  141. case 11:
  142. 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)
  143. case 12:
  144. 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])
  145. case 13:
  146. 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)
  147. case 14:
  148. 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)
  149. case 15:
  150. 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])
  151. default:
  152. panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
  153. }
  154. }
  155. // A LazyDLL implements access to a single DLL.
  156. // It will delay the load of the DLL until the first
  157. // call to its Handle method or to one of its
  158. // LazyProc's Addr method.
  159. type LazyDLL struct {
  160. Name string
  161. // System determines whether the DLL must be loaded from the
  162. // Windows System directory, bypassing the normal DLL search
  163. // path.
  164. System bool
  165. mu sync.Mutex
  166. dll *DLL // non nil once DLL is loaded
  167. }
  168. // Load loads DLL file d.Name into memory. It returns an error if fails.
  169. // Load will not try to load DLL, if it is already loaded into memory.
  170. func (d *LazyDLL) Load() error {
  171. // Non-racy version of:
  172. // if d.dll != nil {
  173. if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) != nil {
  174. return nil
  175. }
  176. d.mu.Lock()
  177. defer d.mu.Unlock()
  178. if d.dll != nil {
  179. return nil
  180. }
  181. // kernel32.dll is special, since it's where LoadLibraryEx comes from.
  182. // The kernel already special-cases its name, so it's always
  183. // loaded from system32.
  184. var dll *DLL
  185. var err error
  186. if d.Name == "kernel32.dll" {
  187. dll, err = LoadDLL(d.Name)
  188. } else {
  189. dll, err = loadLibraryEx(d.Name, d.System)
  190. }
  191. if err != nil {
  192. return err
  193. }
  194. // Non-racy version of:
  195. // d.dll = dll
  196. atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll))
  197. return nil
  198. }
  199. // mustLoad is like Load but panics if search fails.
  200. func (d *LazyDLL) mustLoad() {
  201. e := d.Load()
  202. if e != nil {
  203. panic(e)
  204. }
  205. }
  206. // Handle returns d's module handle.
  207. func (d *LazyDLL) Handle() uintptr {
  208. d.mustLoad()
  209. return uintptr(d.dll.Handle)
  210. }
  211. // NewProc returns a LazyProc for accessing the named procedure in the DLL d.
  212. func (d *LazyDLL) NewProc(name string) *LazyProc {
  213. return &LazyProc{l: d, Name: name}
  214. }
  215. // NewLazyDLL creates new LazyDLL associated with DLL file.
  216. func NewLazyDLL(name string) *LazyDLL {
  217. return &LazyDLL{Name: name}
  218. }
  219. // NewLazySystemDLL is like NewLazyDLL, but will only
  220. // search Windows System directory for the DLL if name is
  221. // a base name (like "advapi32.dll").
  222. func NewLazySystemDLL(name string) *LazyDLL {
  223. return &LazyDLL{Name: name, System: true}
  224. }
  225. // A LazyProc implements access to a procedure inside a LazyDLL.
  226. // It delays the lookup until the Addr method is called.
  227. type LazyProc struct {
  228. Name string
  229. mu sync.Mutex
  230. l *LazyDLL
  231. proc *Proc
  232. }
  233. // Find searches DLL for procedure named p.Name. It returns
  234. // an error if search fails. Find will not search procedure,
  235. // if it is already found and loaded into memory.
  236. func (p *LazyProc) Find() error {
  237. // Non-racy version of:
  238. // if p.proc == nil {
  239. if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
  240. p.mu.Lock()
  241. defer p.mu.Unlock()
  242. if p.proc == nil {
  243. e := p.l.Load()
  244. if e != nil {
  245. return e
  246. }
  247. proc, e := p.l.dll.FindProc(p.Name)
  248. if e != nil {
  249. return e
  250. }
  251. // Non-racy version of:
  252. // p.proc = proc
  253. atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
  254. }
  255. }
  256. return nil
  257. }
  258. // mustFind is like Find but panics if search fails.
  259. func (p *LazyProc) mustFind() {
  260. e := p.Find()
  261. if e != nil {
  262. panic(e)
  263. }
  264. }
  265. // Addr returns the address of the procedure represented by p.
  266. // The return value can be passed to Syscall to run the procedure.
  267. // It will panic if the procedure cannot be found.
  268. func (p *LazyProc) Addr() uintptr {
  269. p.mustFind()
  270. return p.proc.Addr()
  271. }
  272. //go:uintptrescapes
  273. // Call executes procedure p with arguments a. It will panic, if more than 15 arguments
  274. // are supplied. It will also panic if the procedure cannot be found.
  275. //
  276. // The returned error is always non-nil, constructed from the result of GetLastError.
  277. // Callers must inspect the primary return value to decide whether an error occurred
  278. // (according to the semantics of the specific function being called) before consulting
  279. // the error. The error will be guaranteed to contain windows.Errno.
  280. func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
  281. p.mustFind()
  282. return p.proc.Call(a...)
  283. }
  284. var canDoSearchSystem32Once struct {
  285. sync.Once
  286. v bool
  287. }
  288. func initCanDoSearchSystem32() {
  289. // https://msdn.microsoft.com/en-us/library/ms684179(v=vs.85).aspx says:
  290. // "Windows 7, Windows Server 2008 R2, Windows Vista, and Windows
  291. // Server 2008: The LOAD_LIBRARY_SEARCH_* flags are available on
  292. // systems that have KB2533623 installed. To determine whether the
  293. // flags are available, use GetProcAddress to get the address of the
  294. // AddDllDirectory, RemoveDllDirectory, or SetDefaultDllDirectories
  295. // function. If GetProcAddress succeeds, the LOAD_LIBRARY_SEARCH_*
  296. // flags can be used with LoadLibraryEx."
  297. canDoSearchSystem32Once.v = (modkernel32.NewProc("AddDllDirectory").Find() == nil)
  298. }
  299. func canDoSearchSystem32() bool {
  300. canDoSearchSystem32Once.Do(initCanDoSearchSystem32)
  301. return canDoSearchSystem32Once.v
  302. }
  303. func isBaseName(name string) bool {
  304. for _, c := range name {
  305. if c == ':' || c == '/' || c == '\\' {
  306. return false
  307. }
  308. }
  309. return true
  310. }
  311. // loadLibraryEx wraps the Windows LoadLibraryEx function.
  312. //
  313. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx
  314. //
  315. // If name is not an absolute path, LoadLibraryEx searches for the DLL
  316. // in a variety of automatic locations unless constrained by flags.
  317. // See: https://msdn.microsoft.com/en-us/library/ff919712%28VS.85%29.aspx
  318. func loadLibraryEx(name string, system bool) (*DLL, error) {
  319. loadDLL := name
  320. var flags uintptr
  321. if system {
  322. if canDoSearchSystem32() {
  323. const LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800
  324. flags = LOAD_LIBRARY_SEARCH_SYSTEM32
  325. } else if isBaseName(name) {
  326. // WindowsXP or unpatched Windows machine
  327. // trying to load "foo.dll" out of the system
  328. // folder, but LoadLibraryEx doesn't support
  329. // that yet on their system, so emulate it.
  330. systemdir, err := GetSystemDirectory()
  331. if err != nil {
  332. return nil, err
  333. }
  334. loadDLL = systemdir + "\\" + name
  335. }
  336. }
  337. h, err := LoadLibraryEx(loadDLL, 0, flags)
  338. if err != nil {
  339. return nil, err
  340. }
  341. return &DLL{Name: name, Handle: h}, nil
  342. }
  343. type errString string
  344. func (s errString) Error() string { return string(s) }