dll_windows.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  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. // FindProcByOrdinal searches DLL d for procedure by ordinal and returns *Proc
  95. // if found. It returns an error if search fails.
  96. func (d *DLL) FindProcByOrdinal(ordinal uintptr) (proc *Proc, err error) {
  97. a, e := GetProcAddressByOrdinal(d.Handle, ordinal)
  98. name := "#" + itoa(int(ordinal))
  99. if e != nil {
  100. return nil, &DLLError{
  101. Err: e,
  102. ObjName: name,
  103. Msg: "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
  104. }
  105. }
  106. p := &Proc{
  107. Dll: d,
  108. Name: name,
  109. addr: a,
  110. }
  111. return p, nil
  112. }
  113. // MustFindProcByOrdinal is like FindProcByOrdinal but panics if search fails.
  114. func (d *DLL) MustFindProcByOrdinal(ordinal uintptr) *Proc {
  115. p, e := d.FindProcByOrdinal(ordinal)
  116. if e != nil {
  117. panic(e)
  118. }
  119. return p
  120. }
  121. // Release unloads DLL d from memory.
  122. func (d *DLL) Release() (err error) {
  123. return FreeLibrary(d.Handle)
  124. }
  125. // A Proc implements access to a procedure inside a DLL.
  126. type Proc struct {
  127. Dll *DLL
  128. Name string
  129. addr uintptr
  130. }
  131. // Addr returns the address of the procedure represented by p.
  132. // The return value can be passed to Syscall to run the procedure.
  133. func (p *Proc) Addr() uintptr {
  134. return p.addr
  135. }
  136. //go:uintptrescapes
  137. // Call executes procedure p with arguments a. It will panic, if more than 15 arguments
  138. // are supplied.
  139. //
  140. // The returned error is always non-nil, constructed from the result of GetLastError.
  141. // Callers must inspect the primary return value to decide whether an error occurred
  142. // (according to the semantics of the specific function being called) before consulting
  143. // the error. The error will be guaranteed to contain windows.Errno.
  144. func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
  145. switch len(a) {
  146. case 0:
  147. return syscall.Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
  148. case 1:
  149. return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
  150. case 2:
  151. return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
  152. case 3:
  153. return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
  154. case 4:
  155. return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
  156. case 5:
  157. return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
  158. case 6:
  159. return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
  160. case 7:
  161. return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
  162. case 8:
  163. 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)
  164. case 9:
  165. 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])
  166. case 10:
  167. 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)
  168. case 11:
  169. 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)
  170. case 12:
  171. 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])
  172. case 13:
  173. 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)
  174. case 14:
  175. 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)
  176. case 15:
  177. 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])
  178. default:
  179. panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
  180. }
  181. }
  182. // A LazyDLL implements access to a single DLL.
  183. // It will delay the load of the DLL until the first
  184. // call to its Handle method or to one of its
  185. // LazyProc's Addr method.
  186. type LazyDLL struct {
  187. Name string
  188. // System determines whether the DLL must be loaded from the
  189. // Windows System directory, bypassing the normal DLL search
  190. // path.
  191. System bool
  192. mu sync.Mutex
  193. dll *DLL // non nil once DLL is loaded
  194. }
  195. // Load loads DLL file d.Name into memory. It returns an error if fails.
  196. // Load will not try to load DLL, if it is already loaded into memory.
  197. func (d *LazyDLL) Load() error {
  198. // Non-racy version of:
  199. // if d.dll != nil {
  200. if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) != nil {
  201. return nil
  202. }
  203. d.mu.Lock()
  204. defer d.mu.Unlock()
  205. if d.dll != nil {
  206. return nil
  207. }
  208. // kernel32.dll is special, since it's where LoadLibraryEx comes from.
  209. // The kernel already special-cases its name, so it's always
  210. // loaded from system32.
  211. var dll *DLL
  212. var err error
  213. if d.Name == "kernel32.dll" {
  214. dll, err = LoadDLL(d.Name)
  215. } else {
  216. dll, err = loadLibraryEx(d.Name, d.System)
  217. }
  218. if err != nil {
  219. return err
  220. }
  221. // Non-racy version of:
  222. // d.dll = dll
  223. atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll))
  224. return nil
  225. }
  226. // mustLoad is like Load but panics if search fails.
  227. func (d *LazyDLL) mustLoad() {
  228. e := d.Load()
  229. if e != nil {
  230. panic(e)
  231. }
  232. }
  233. // Handle returns d's module handle.
  234. func (d *LazyDLL) Handle() uintptr {
  235. d.mustLoad()
  236. return uintptr(d.dll.Handle)
  237. }
  238. // NewProc returns a LazyProc for accessing the named procedure in the DLL d.
  239. func (d *LazyDLL) NewProc(name string) *LazyProc {
  240. return &LazyProc{l: d, Name: name}
  241. }
  242. // NewLazyDLL creates new LazyDLL associated with DLL file.
  243. func NewLazyDLL(name string) *LazyDLL {
  244. return &LazyDLL{Name: name}
  245. }
  246. // NewLazySystemDLL is like NewLazyDLL, but will only
  247. // search Windows System directory for the DLL if name is
  248. // a base name (like "advapi32.dll").
  249. func NewLazySystemDLL(name string) *LazyDLL {
  250. return &LazyDLL{Name: name, System: true}
  251. }
  252. // A LazyProc implements access to a procedure inside a LazyDLL.
  253. // It delays the lookup until the Addr method is called.
  254. type LazyProc struct {
  255. Name string
  256. mu sync.Mutex
  257. l *LazyDLL
  258. proc *Proc
  259. }
  260. // Find searches DLL for procedure named p.Name. It returns
  261. // an error if search fails. Find will not search procedure,
  262. // if it is already found and loaded into memory.
  263. func (p *LazyProc) Find() error {
  264. // Non-racy version of:
  265. // if p.proc == nil {
  266. if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
  267. p.mu.Lock()
  268. defer p.mu.Unlock()
  269. if p.proc == nil {
  270. e := p.l.Load()
  271. if e != nil {
  272. return e
  273. }
  274. proc, e := p.l.dll.FindProc(p.Name)
  275. if e != nil {
  276. return e
  277. }
  278. // Non-racy version of:
  279. // p.proc = proc
  280. atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
  281. }
  282. }
  283. return nil
  284. }
  285. // mustFind is like Find but panics if search fails.
  286. func (p *LazyProc) mustFind() {
  287. e := p.Find()
  288. if e != nil {
  289. panic(e)
  290. }
  291. }
  292. // Addr returns the address of the procedure represented by p.
  293. // The return value can be passed to Syscall to run the procedure.
  294. // It will panic if the procedure cannot be found.
  295. func (p *LazyProc) Addr() uintptr {
  296. p.mustFind()
  297. return p.proc.Addr()
  298. }
  299. //go:uintptrescapes
  300. // Call executes procedure p with arguments a. It will panic, if more than 15 arguments
  301. // are supplied. It will also panic if the procedure cannot be found.
  302. //
  303. // The returned error is always non-nil, constructed from the result of GetLastError.
  304. // Callers must inspect the primary return value to decide whether an error occurred
  305. // (according to the semantics of the specific function being called) before consulting
  306. // the error. The error will be guaranteed to contain windows.Errno.
  307. func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
  308. p.mustFind()
  309. return p.proc.Call(a...)
  310. }
  311. var canDoSearchSystem32Once struct {
  312. sync.Once
  313. v bool
  314. }
  315. func initCanDoSearchSystem32() {
  316. // https://msdn.microsoft.com/en-us/library/ms684179(v=vs.85).aspx says:
  317. // "Windows 7, Windows Server 2008 R2, Windows Vista, and Windows
  318. // Server 2008: The LOAD_LIBRARY_SEARCH_* flags are available on
  319. // systems that have KB2533623 installed. To determine whether the
  320. // flags are available, use GetProcAddress to get the address of the
  321. // AddDllDirectory, RemoveDllDirectory, or SetDefaultDllDirectories
  322. // function. If GetProcAddress succeeds, the LOAD_LIBRARY_SEARCH_*
  323. // flags can be used with LoadLibraryEx."
  324. canDoSearchSystem32Once.v = (modkernel32.NewProc("AddDllDirectory").Find() == nil)
  325. }
  326. func canDoSearchSystem32() bool {
  327. canDoSearchSystem32Once.Do(initCanDoSearchSystem32)
  328. return canDoSearchSystem32Once.v
  329. }
  330. func isBaseName(name string) bool {
  331. for _, c := range name {
  332. if c == ':' || c == '/' || c == '\\' {
  333. return false
  334. }
  335. }
  336. return true
  337. }
  338. // loadLibraryEx wraps the Windows LoadLibraryEx function.
  339. //
  340. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx
  341. //
  342. // If name is not an absolute path, LoadLibraryEx searches for the DLL
  343. // in a variety of automatic locations unless constrained by flags.
  344. // See: https://msdn.microsoft.com/en-us/library/ff919712%28VS.85%29.aspx
  345. func loadLibraryEx(name string, system bool) (*DLL, error) {
  346. loadDLL := name
  347. var flags uintptr
  348. if system {
  349. if canDoSearchSystem32() {
  350. const LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800
  351. flags = LOAD_LIBRARY_SEARCH_SYSTEM32
  352. } else if isBaseName(name) {
  353. // WindowsXP or unpatched Windows machine
  354. // trying to load "foo.dll" out of the system
  355. // folder, but LoadLibraryEx doesn't support
  356. // that yet on their system, so emulate it.
  357. systemdir, err := GetSystemDirectory()
  358. if err != nil {
  359. return nil, err
  360. }
  361. loadDLL = systemdir + "\\" + name
  362. }
  363. }
  364. h, err := LoadLibraryEx(loadDLL, 0, flags)
  365. if err != nil {
  366. return nil, err
  367. }
  368. return &DLL{Name: name, Handle: h}, nil
  369. }
  370. type errString string
  371. func (s errString) Error() string { return string(s) }