ما هي قواعد ملحق الإشارة لاستدعاء وظائف Windows API (stdcall)؟يعد هذا ضروريًا لاستدعاء WInAPI من Go، وهو أمر صارم فيما يتعلق بأنواع int

StackOverflow https://stackoverflow.com//questions/24022225

سؤال

عفوًا، كان هناك شيء واحد نسيته عندما قمت بذلك هذه الإجابة, ، وهو شيء لست متأكدًا منه تمامًا بنفسي ويبدو أنه لا يمكنني العثور على معلومات عنه في MSDN وGoogle وبحث Stack Overflow.

هناك عدد من الأماكن في Windows API حيث يمكنك استخدام رقم سالب، أو رقم كبير جدًا بحيث لا يتناسب مع عدد صحيح موقّع؛على سبيل المثال، CW_USEDEFAULT, INVALID_HANDLE_VALUE, GWLP_USERDATA, ، وما إلى ذلك وهلم جرا.في عالم لغة C، كل شيء على ما يرام ورائع:تأتي قواعد الترويج للأعداد الصحيحة للغة للإنقاذ.

ولكن في Go، لا بد لي من تمرير كل ما عندي من الحجج إلى وظائف ك uintptr (وهو ما يعادل C uintptr_t).يتم أيضًا إرجاع القيمة المرجعة من الدالة بهذه الطريقة، وبعد ذلك سأحتاج إلى المقارنة.لا يسمح Go بترويج الأعداد الصحيحة، ولا يسمح لك بتحويل تعبير ثابت موقّع إلى تعبير غير موقّع في وقت الترجمة.

في الوقت الحالي، لدي قليلا من جيري تلاعب تم إعدادها للتعامل مع هذه الثوابت في ملفي مكتبة واجهة المستخدم. (فيما يلي مثال لما يبدو عليه هذا الحل أثناء العمل.) ومع ذلك، أنا لست راضيًا تمامًا عن هذا الحل؛يبدو لي أنها تفترض أشياءً تتعلق بـ ABI، وأريد أن أكون متأكدًا تمامًا مما أفعله.

لذلك سؤالي هو:كيف يتم التعامل مع القيم الموقعة عند تمريرها إلى وظائف Windows API وكيف يتم التعامل معها عند العودة؟

كل ثوابتي هي يستخرج تلقائيا (إخراج المثال).يستخدم المولد التلقائي سي فاي, ، والذي أفضل عدم استخدامه للمشروع الرئيسي حيث يمكنني الاتصال بمكتبات الارتباط الحيوي (DLL) مباشرة (وهذا أيضًا يجعل التجميع المتبادل أسهل على الأقل لبقية العام).إذا كان بإمكاني الاستفادة من ذلك بطريقة أو بأخرى، على سبيل المثال عن طريق تحويل كل شيء إلى متغير الجانب C من النموذج

uintptr_t x_CONST_NAME = (uintptr_t) (CONST_NAME);

سيكون ذلك مفيدًا.لكن لا يمكنني فعل ذلك بدون هذه الإجابة.

شكرًا!

تحديث

لقد صاغها شخص ما على IRC بطريقة مختلفة (تمت إعادة تنسيقها لتجنب التمرير الأفقي):

[19:13] <FraGag> basically, you're asking whether an int with a value of -1
                 will be returned as 0x00000000FFFFFFFF or as 0xFFFFFFFFFFFFFFFF
                 if an int is 4 bytes and an uintptr is 8 bytes

هذا بشكل أساسي، ولكن خصيصًا للتشغيل المتداخل لـ Windows API، وللمعلمات التي تم تمريرها، وبغض النظر عن حجم uintptr.

هل كانت مفيدة؟

المحلول

تعليقات @twotwotwo على سؤالي وجهتني في الاتجاه الصحيح.إذا سمح Stack Overflow بوضع علامة على التعليقات كإجابات ووضع علامة على إجابات متعددة، فسأفعل ذلك.

ليرة تركية؛ نسخة الدكتور:ما لدي الآن هو الصحيح بعد كل شيء.

لقد كتبت برنامجًا (أدناه) قام ببساطة بإلقاء جميع الثوابت من package syscall وبحث عن الثوابت التي كانت سالبة، ولكن ليس == -1 (حيث سيكون ذلك مجرد ^0).يعالج الملف القياسي (STD_ERROR_HANDLE, STD_INPUT_HANDLE, ، و STD_OUTPUT_HANDLE) هي (-12، -10، و-11، على التوالي).يقوم الكود الموجود في الحزمة syscall بتمرير هذه الثوابت باعتبارها الوسيطة الوحيدة لـ getStdHandle(h int), ، الذي ينتج مؤشر الملف المطلوب لحزمة os. getStdHandle() يمرر هذا إلى وظيفة تم إنشاؤها تلقائيًا GetStdHandle(stdhandle int) الذي يختتم مكالمة إلى GetStdHandle() مكالمة النظام. GetStdHandle() يأخذ int ويحوله فقط إلى uintptr للمرور الى syscall.Syscall().على الرغم من عدم تقديم أي تفسير في مصدر المولد التلقائي (mksyscall_windows.go)، إذا كان هذا لم يفعل ذلك العمل، ولا شيء من هذا القبيل fmt.Println() = ف

كل ما سبق متطابق في كل من windows/386 وwindows/amd64؛الشيء الوحيد في ملف خاص بالمعالج هو GetStdHandle(), ، لكن الكود ذو الصلة مطابق.

لي negConst() تقوم الوظيفة بنفس الشيء بالفعل، ولكن بطريقة أكثر مباشرة.وعلى هذا النحو، أستطيع أن أفترض بأمان أنه صحيح.

شكرًا!

// 4 june 2014
// based on code from 24 may 2014
package main

import (
    "fmt"
    "os"
    "strings"
    "go/token"
    "go/ast"
    "go/parser"
    "code.google.com/p/go.tools/go/types"
    _ "code.google.com/p/go.tools/go/gcimporter"
)

var arch string

func getPackage(path string) (typespkg *types.Package, pkginfo types.Info) {
    var pkg *ast.Package

    fileset := token.NewFileSet()       // parser.ParseDir() actually writes to this; not sure why it doesn't return one instead
    filter := func(i os.FileInfo) bool {
        if strings.Contains(i.Name(), "_windows") &&
            strings.Contains(i.Name(), "_" + arch) &&
            strings.HasSuffix(i.Name(), ".go") {
            return true
        }
        if i.Name() == "race.go" ||     // skip these
            i.Name() == "flock.go" {
            return false
        }
        return strings.HasSuffix(i.Name(), "_windows.go") ||
            (!strings.Contains(i.Name(), "_"))
    }
    pkgs, err := parser.ParseDir(fileset, path, filter, parser.AllErrors)
    if err != nil {
        panic(err)
    }
    for k, _ := range pkgs {        // get the sole key
        if pkgs[k].Name == "syscall" {
            pkg = pkgs[k]
            break
        }
    }
    if pkg == nil {
        panic("package syscall not found")
    }
    // we can't pass pkg.Files directly to types.Check() because the former is a map and the latter is a slice
    ff := make([]*ast.File, 0, len(pkg.Files))
    for _, v := range pkg.Files {
        ff = append(ff, v)
    }
    // if we don't make() each map, package types won't fill the structure
    pkginfo.Defs = make(map[*ast.Ident]types.Object)
    pkginfo.Scopes = make(map[ast.Node]*types.Scope)
    typespkg, err = new(types.Config).Check(path, fileset, ff, &pkginfo)
    if err != nil {
        panic(err)
    }
    return typespkg, pkginfo
}

func main() {
    pkgpath := "/home/pietro/go/src/pkg/syscall"
    arch = os.Args[1]

    pkg, _ := getPackage(pkgpath)
    scope := pkg.Scope()
    for _, name := range scope.Names() {
        obj := scope.Lookup(name)
        if obj == nil {
            panic(fmt.Errorf("nil object %q from scope %v", name, scope))
        }
        if !obj.Exported() {        // exported names only
            continue
        }
        if _, ok := obj.(*types.Const); ok {
            fmt.Printf("egrep -rh '#define[     ]+%s' ~/winshare/Include/ 2>/dev/null\n", obj.Name())
        }
        // otherwise skip
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top