瀏覽代碼

windows: add GetProcAddressByOrdinal

The current GetProcAddress implementation only resolves functions in
DLLs by name. Add GetProcAddressByOrdinal that allows resolving
functions by ordinal number, using the same GetProcAddress call from
kernel32.dll in the background.

This is particularly useful for some functions (e.g. IsOS from
shlwapi.dll in some older versions of Windows) that cannot be found by
name.

Fixes golang/go#16507

Change-Id: Ib5fba7568c365a0aa2491c1261876b3a3929ec3d
Reviewed-on: https://go-review.googlesource.com/70690
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
Run-TryBot: Alex Brainman <alex.brainman@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Hilko Bengen 8 年之前
父節點
當前提交
8dbc5d05d6
共有 2 個文件被更改,包括 35 次插入0 次删除
  1. 20 0
      windows/syscall_test.go
  2. 15 0
      windows/syscall_windows.go

+ 20 - 0
windows/syscall_test.go

@@ -7,6 +7,7 @@
 package windows_test
 
 import (
+	"syscall"
 	"testing"
 
 	"golang.org/x/sys/windows"
@@ -31,3 +32,22 @@ func TestEnv(t *testing.T) {
 	// make sure TESTENV gets set to "", not deleted
 	testSetGetenv(t, "TESTENV", "")
 }
+
+func TestGetProcAddressByOrdinal(t *testing.T) {
+	// Attempt calling shlwapi.dll:IsOS, resolving it by ordinal, as
+	// suggested in
+	// https://msdn.microsoft.com/en-us/library/windows/desktop/bb773795.aspx
+	h, err := windows.LoadLibrary("shlwapi.dll")
+	if err != nil {
+		t.Fatalf("Failed to load shlwapi.dll: %s", err)
+	}
+	procIsOS, err := windows.GetProcAddressByOrdinal(h, 437)
+	if err != nil {
+		t.Fatalf("Could not find shlwapi.dll:IsOS by ordinal: %s", err)
+	}
+	const OS_NT = 1
+	r, _, _ := syscall.Syscall(procIsOS, 1, OS_NT, 0, 0)
+	if r == 0 {
+		t.Error("shlwapi.dll:IsOS(OS_NT) returned 0, expected non-zero value")
+	}
+}

+ 15 - 0
windows/syscall_windows.go

@@ -202,6 +202,21 @@ func NewCallbackCDecl(fn interface{}) uintptr {
 
 // syscall interface implementation for other packages
 
+// GetProcAddressByOrdinal retrieves the address of the exported
+// function from module by ordinal.
+func GetProcAddressByOrdinal(module Handle, ordinal uintptr) (proc uintptr, err error) {
+	r0, _, e1 := syscall.Syscall(procGetProcAddress.Addr(), 2, uintptr(module), ordinal, 0)
+	proc = uintptr(r0)
+	if proc == 0 {
+		if e1 != 0 {
+			err = errnoErr(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
 func Exit(code int) { ExitProcess(uint32(code)) }
 
 func makeInheritSa() *SecurityAttributes {