NSIS: مشكلة مع $ 0- $ 9 ، $ R0- $ R9

تحية لكل من يقرأ :)

المحور المستهدف لا يتوافق مع محتوى المقالة ، ولكن ماذا تفعل ... - لا توجد مواضيع موضوعية لهذا الغرض ، ولكن الأنسب هو "C" ، لأن سيكون قراءه قادرين بسهولة على إدراك ما هو مكتوب.

الغرض من المقال


خيار لحل مشكلة التحكم في المتغيرات العامة عند كتابة المثبت / إلغاء التثبيت باستخدام NSIS .

مقدمة صغيرة


عند كتابة كود nsis ، فإن المبرمج لديه الفرصة لاستخدام المتغيرات العالمية التي يكون نطاقها هو المشروع بأكمله. هناك 20 منهم فقط: $ 0- $ 9 و $ R0- $ R9.
من السهل جدا استخدامها ، لأن هذا يلغي الحاجة إلى إدخال متغيرات إضافية مخصصة رسميًا لحل المشكلات المستهدفة. أقول ، رسميا ، لأنه أي متغيرات nsis لها نطاق عالمي وإذا اختلفت في أي شيء ، فعندئذ فقط مع شرط المؤهل (يتحدث بشروط C / C ++):

!define variable1 ''value 1''

الميزات:

  • المتغير الثابت للنطاق العالمي ؛
  • تم التهيئة عند الإعلان ؛
  • طريقة الاتصال: $ {variable1}

Var variable2

الميزات:

  • المتغير الديناميكي للنطاق العالمي ؛
  • يتم الإعلان عنها في أي مكان بواسطة رمز ، ولكن فوق المكالمة الأولى ؛
  • تتم تهيئته عدة مرات حسب الضرورة ، ولكن فقط داخل كتل الوظائف ووحدات الماكرو ؛
  • طريقة الوصول: $ متغير 2

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

وصف المشكلة


لكن المشكلة هي أن هذا الرمز يولد دائمًا أخطاء:


Function F1
    StrCpy $0 "vladimir"
FunctionEnd

Function F2
    StrCpy $0 "alexei"
    Call F1
    ${If} $0 == "alexei" ; //  $0  "vladimir"
        ; // -  ...
    ${EndIf}
FunctionEnd

ويمكنك الخروج بالعديد من الأمثلة على ذلك ، وقد قام حرفيو برمجة nsis بحل هذه المشكلة بأفضل طريقة ممكنة:

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

على أي حال ، واجهوا جميعًا مشكلة عدم وجود آلية عالمية تحل مشكلة مراقبة حالة المتغيرات العالمية.

هنا أسمح لنفسي أن أقدم لها (المشاكل) حلاً شاملاً.

حل للمشكلة


بادئ ذي بدء ، فإن الرابط إلى NSISList هو مكون إضافي يقدم القدرة على استخدام بنية بيانات من نوع القائمة ، والتي يجب أن تؤخذ بطريقة مماثلة لـ std :: list في C ++.

الخطوة الثانية هي شفرة المصدر لآلية حل المشكلات :


!verbose 3
!include NSISList.nsh	;      *

/*
  Dump, :

!define F1 "!insertmacro _F1"
!macro _F1 [paramIn1 paramIn2 ... paramInN] [paramOut1 paramOut1 ... paramOutM]
    ${Dump}
    [Push ${paramIn1}
	Push ${paramIn2}
	...
	Push ${paramInN}]
    !ifdef __UNINSTALL__
        Call un.F1
    !else
        Call F1
    !endif
    ${Undump}
    [Pop ${paramOut1}
	Pop ${paramOut2}
	...
	Pop ${paramOutM}]
!macroend

!macro Func_F1 un
    Function ${un}F1
        ;  ...
        ;         $0-$9, $R0-$R9.
        ;        .
    FunctionEnd
!macroend
!insertmacro Func_F1 ""
!insertmacro Func_F1 "un."

*/

/**   Dump */
!define InitDump "!insertmacro _InitDump"
!macro _InitDump
    !ifdef __UNINSTALL__
        Call un.InitDump
    !else
        Call InitDump
    !endif
!macroend

!macro Func_InitDump un
    Function ${un}InitDump
        #  $0-$9
        ${List.Create} d0
        ${List.Create} d1
        ${List.Create} d2
        ${List.Create} d3
        ${List.Create} d4
        ${List.Create} d5
        ${List.Create} d6
        ${List.Create} d7
        ${List.Create} d8
        ${List.Create} d9
        #  $R0-$R10
        ${List.Create} dR0
        ${List.Create} dR1
        ${List.Create} dR2
        ${List.Create} dR3
        ${List.Create} dR4
        ${List.Create} dR5
        ${List.Create} dR6
        ${List.Create} dR7
        ${List.Create} dR8
        ${List.Create} dR9
    FunctionEnd
!macroend
!insertmacro Func_InitDump ""
!insertmacro Func_InitDump "un."


/**     nsis-  Dump */
!define Dump "!insertmacro _Dump"
!macro _Dump
    !ifdef __UNINSTALL__
        Call un.Dump
    !else
        Call Dump
    !endif
!macroend

!macro Func_Dump un
    Function ${un}Dump
        # $0-$9
        ${List.Add} d0 $0
        ${List.Add} d1 $1
        ${List.Add} d2 $2
        ${List.Add} d3 $3
        ${List.Add} d4 $4
        ${List.Add} d5 $5
        ${List.Add} d6 $6
        ${List.Add} d7 $7
        ${List.Add} d8 $8
        ${List.Add} d9 $9
        # R0-R9
        ${List.Add} dR0 $R0
        ${List.Add} dR1 $R1
        ${List.Add} dR2 $R2
        ${List.Add} dR3 $R3
        ${List.Add} dR4 $R4
        ${List.Add} dR5 $R5
        ${List.Add} dR6 $R6
        ${List.Add} dR7 $R7
        ${List.Add} dR8 $R8
        ${List.Add} dR9 $R9
    FunctionEnd
!macroend
!insertmacro Func_Dump ""
!insertmacro Func_Dump "un."


/**     nsis-  Dump */
!define Undump "!insertmacro _Undump"
!macro _Undump
    !ifdef __UNINSTALL__
        Call un.Undump
    !else
        Call Undump
    !endif
!macroend

!macro Func_Undump un
    Function ${un}Undump
        # $0-$9
        ${List.Pop} $0 d0
        ${List.Pop} $1 d1
        ${List.Pop} $2 d2
        ${List.Pop} $3 d3
        ${List.Pop} $4 d4
        ${List.Pop} $5 d5
        ${List.Pop} $6 d6
        ${List.Pop} $7 d7
        ${List.Pop} $8 d8
        ${List.Pop} $9 d9
        # R0-R9
        ${List.Pop} $R0 dR0
        ${List.Pop} $R1 dR1
        ${List.Pop} $R2 dR2
        ${List.Pop} $R3 dR3
        ${List.Pop} $R4 dR4
        ${List.Pop} $R5 dR5
        ${List.Pop} $R6 dR6
        ${List.Pop} $R7 dR7
        ${List.Pop} $R8 dR8
        ${List.Pop} $R9 dR9
    FunctionEnd
!macroend
!insertmacro Func_Undump ""
!insertmacro Func_Undump "un."

والخطوة الثالثة هي وصف صغير لكيفية عملها:

كل وظيفة تم إنشاؤها وتصميمها وفقًا للقاعدة الموضحة في تعليق الكود الرئيسي السابق ستكون محمية تمامًا من وجهة نظر خطر إعادة كتابة المتغيرات العالمية $ 0- $ 9 ، $ R0- $ R9 بداخلها ، وبالتالي - من انتهاك منطق وظيفة الاستدعاء.

يعمل مثل هذا:

  1. لا يتم استدعاء وظيفة F1 نفسها مباشرة ،
    Call F1
    ومن خلال غلاف الماكرو
    ${F1} [paramIn1 [paramIn2]...[paramInN]] [paramOut1 [paramOut2]...[paramOutM]]
  2. حتى قبل استدعاء الوظيفة مباشرة ، سيتم استدعاؤها
    ${Dump}
    ونتيجة لذلك ، يتم حفظ القيم الحالية للمتغيرات $ 0- $ 9 ، $ R0- $ R9 في تفريغ. تحت غطاء المحرك لديه الكثير من القوائم ، كل منها مرتبط بمتغيره المستهدف ؛
  3. تحميل على المكدس جميع المتغيرات المستهدفة للوظيفة
    Push ${paramIn1} Push ${paramIn2} ... Push ${paramInN}
    (إذا لزم الأمر)؛
  4. سيتم استدعاء الوظيفة ؛
  5. ستقوم الوظيفة بتنفيذ منطقها وخروجها ؛
  6. ستحدث المكالمة
    ${Undump}
    ونتيجة لذلك ، سيتم استعادة قيم المتغيرات العالمية المخزنة في المكالمة الأخيرة من $ {Dump} ؛
  7. نتائج تفريغ الوظيفة من المكدس
    Pop ${paramOut1} Pop ${paramOut2} ... Pop ${paramOutM}
    (إذا لزم الأمر)؛
  8. ستكمل أداة تغليف الماكرو في الدالة F1 عملها.

استنتاج


ونتيجة لذلك ، حصلنا على تصميم عالمي للكتابة الآمنة لرمز nsis.

يمكنك حتى القول أنه لا يجلب أي سلبيات ، باستثناء أن التعليمات البرمجية المترجمة ستعمل لمدة 30 مللي ثانية تقريبًا. أبطأ.

أتمنى أن يجعل هذا الحياة أسهل بالنسبة لشخص ما :)

شكرا لك!

Source: https://habr.com/ru/post/undefined/


All Articles