Aardio-API呼び出し分析

注:以下の内容は私の現在の理解であり、正しいことを保証するものではなく、いつでも更新される可能性があります。

すべてのaardio愛好家を歓迎し、コミュニケーションを取り、aardioを一緒に研究し、何が正しいかを知り、間違いを修正し、一緒に進歩します。

aardioが強くなりますように。

API呼び出しの解決

1.静的データタイプパラメータ

1.静的データタイプ(数値、ポインターなど)は、宣言されているかどうかに関係なく、API呼び出し中に渡される値であり、入力パラメーターとしてのみ使用できます。

2.ポインタ(アドレス)を「出力パラメータ」として渡したい場合は、代わりに構造を使用する必要があります。

3.テーブルを使用して構造構造を定義し、構造に静的型を定義します。

4.構造内のすべてのメンバーに初期値を割り当てる必要があります(検証するには、以下の小さなテストを参照してください)。

といった:

数値ポインタ:{intabc}または{intabc = 123}。

数値配列へのポインタ:{int data [4]}。

バイト配列へのポインタ:{byte data [4]}またはraw.buffer() 

// 通常,我们使用class来定义API函数中需要用到的结构体:

class POINT{
int x = 0; // 结构体成员必须设定初始值
int y = 0; 
}

// 创建一个结构体对象
pt = POINT();

// 每个结构体会创建一个_struct只读字段记录类型定义,语义如下:
pt = { _struct = "int x;int y" }

小規模なテスト:structのすべてのメンバーについて初期値を割り当てる必要があります

テストの結論:structのメンバーに初期値が与えられていなくても、すべて問題ありません。

初期値がなくても、intのような固定長のデータ型は関係ないと思います。

配列の場合、構造の長さを事前に決定する必要があります。

 

簡単な言語のdllコード:

 

 

aardio呼び出しコード:

 

 

structに初期値は指定されません。intタイプの値はデフォルトで0になります。


 

apiに渡された後、変数値も通常どおり変更できます。

 

 

2.動的データタイプパラメータ

      1.動的タイプ(文字列、バッファー)自体がポインターであるため、アドレスを渡すことができなくなります。

            つまり、表面的には、入力パラメータとしてのみ使用でき、出力パラメータとしては使用できません。

            ただし、これにもかかわらず、それ自体がポインターであるため、その値はapiで変更することもできます。

      2. structがAPIを宣言する場合、入力または出力パラメーターとして使用できます。APIが宣言されていない場合、出力パラメーターとして必須です。

            入力パラメータとして使用すると、値が渡され(値で渡され)、APIの戻り値として返されません。

            出力パラメータとして使用される場合、ポインタ(アドレス)が渡され、API戻り値として返されます。

3.宣言なしでAPIを直接呼び出します。

1.パラメータ:

1. APIを宣言せずに直接呼び出すと、必要に応じてパラメータの種類を柔軟に変更できるため、より便利でリソースを節約できます。お勧めします。

2.呼び出し規則は、DLLをロードするパラメーターで指定され、可変数のcdeclパラメーターがサポートされます。

3.nullパラメータは省略できません。

4.すべての数値パラメーターは、32ビットのint整数として扱われます。(整数、列挙型、32ビット未満の8ビットまたは32ビットのbool値はint 32ビット値と互換性があります)

5. 64ビットの整数は、math.size64オブジェクトで表すことができます。(または、2つの数値パラメーターを使用して64ビットの整数値パラメーターを表します。最初のパラメーターは下位32ビット値を表し、2番目のパラメーターは上位32ビット値を表します)

6.数値ポインタ(出力パラメータ)は常に構造で表されます。

7.配列ポインター。代わりに、{int data [4]}などの構造ポインターを使用します。

8.構造は常に出力パラメーターとして処理され、aardioの戻り値で返されます。

9.構造以外の他のタイプは、入力パラメーターとしてのみ使用できます。

0. aardioでは、API呼び出しで渡される構造はすべて構造ポインター(パスアドレス)であることに注意してください(次の単純な数値構造テストコードでは、不合格テストが実行されると、apiが実行されるため、さらに検証されます。実変数の値を変更できませんでした。

      ここでの意味は非常にありそうです。APIの直接呼び出しで渡される構造はすべて構造ポインターです)。

2.戻り値:

1. APIが直接呼び出された場合、戻り値はデフォルトでint型になります。

2. [APIテール]を使用して、戻り値を他のタイプに変更できます。

3.宣言されていないAPI関数は、通常のaardio関数オブジェクトであり、関数ポインターパラメーターとしてAPIパラメーターに渡すことはできません(宣言されたAPI関数オブジェクトは問題ありません)。

4.構造は常に出力パラメーターとして使用され、api戻り値の後に返されます。

3. APIテール:

1.ステートメントなしでAPIを直接呼び出す場合、API関数名の末尾が大文字でない場合は、特定の大文字(これはAPIの末尾)を使用して、デフォルトのAPI呼び出しルールを変更できます。

2. API関数名の後にテールを追加しても、API関数の検索結果には影響しません。Aardioは、テールが指定されているかどうかに関係なく、実際のAPIを見つけることができます。

3.使用可能なすべての[APIサフィックス]および代表的なルールは次のとおりです。

  • dll.ApiName W()Unicodeバージョンに切り替え、文字列UTF8-UTF16双方向変換
  • dll.ApiName A()ANSIバージョンに切り替えると、文字列は変換されません
  • dll.ApiName L()戻り値は64ビットのLONGタイプです
  • dll.ApiName P()戻り値はポインタポインタタイプです
  • dll.ApiName D()戻り値は二重浮動小数点数です
  • dll.ApiName F()戻り値は浮動小数点浮動小数点数です
  • dll.ApiName B()戻り値はバイトタイプです(C ++では8ビットbool)

4.すでにWテールがあるAPI関数の場合、呼び出し時に他のテールを使用でき、API関数のUnicodeバージョンを正しく検出して切り替えることができます。

第四に、文字列を使用します

1.文字列およびバッファタイプのバイト配列は、通常、文字列ポインタとして使用されます。

2. APIが文字列が指すメモリにデータを書き込む必要がある場合は、raw.buffer()関数を使用して固定長のバイト配列を作成する必要があります。

3.通常のaardio文字列が指すメモリの書き込みは禁止されています(このステートメントはaardioの通常の操作専用です。次のapiテストコードを参照してください。文字列の値を正常に変更できます)、aardioの通常の文字を変更しますStringは、元のメモリのデータを変更する代わりに、新しいstringオブジェクトを返します。

4. APIのAnsiバージョンの場合、文字列文字列は元のデータに直接入力されます(テキストはデフォルトでUTF8でエンコードされます)。

      APIのUnicodeバージョンの場合、文字列文字列は強制的にUnicode(UTF16)に変換されます。

      バッファタイプパラメータは、常に生データを使用して、バイナリモード(テキストエンコーディング変換なし)でAPIと対話します。

ファイブ、アンシとユニコード

1. raw.loadDll()でDLLをロードするときに、呼び出し規則に「、unicode」を追加して、デフォルトでUnicodeAPIを使用するようにすることができます。

2.関数名の後に末尾の「A」または「W」を追加して、APIのAnsiまたはUnicodeバージョンを宣言できます。

      テールバージョンとloadDll合意バージョンの両方が同時に指定された場合、テールバージョンが優先されます。

      aardioがこのバージョンのAPI関数を見つけられない場合、テールを削除しますが、指定されたテールバージョンに従って文字列をエンコードします。

4.一部のAPIが文字列やバイト配列などのパラメータを受け取る場合、通常、次のパラメータでメモリ長を指定する必要があります。aardioで#演算子を使用して文字列とバッファの長さを取得すると、すべてのバイトが返されます。 APIでは、文字数の入力が必要になる場合があります。APIのUnicodeバージョンの場合、1文字は2バイトです。UTF8文字列の場合、string.len()関数を使用して実際の文字長を取得する必要がありますが、Unicode文字列は#バイト長を取得し、2を掛けます。

簡単な数値構造テスト

簡単な言語で書かれたDllコード:

aardio呼び出しコード:

1.入力パラメータとして定義されている場合[アドレスを渡さない]:

// 结构体未定义为输出参数:

import console; 

testdll = raw.loadDll("C:\Users\Administrator\Desktop\test.dll")
test=testdll.api("test","int(struct)","stdcall")

var i = {int abc=123}

var a,b = test (i)
console.dump("a:",a)
console.dump("b:",b)
console.dump("i:",i)

console.pause(true);

の結果

 

実行結果:渡された値は正常、構造データの変更は失敗、戻り値は正常、構造は戻り値として返されません。

2.出力パラメータとして定義されている場合[アドレス]:

import console; 

testdll = raw.loadDll("C:\Users\Administrator\Desktop\test.dll")
test=testdll.api("test","int(struct&)","stdcall")

var i = {int abc=123}

var a,b = test (i)
console.dump("a:",a)
console.dump("b:",b)
console.dump("i:",i)

console.pause(true);

結果:

実行結果:着信api値は正常です。api内の変更された構造変数データは正常です。戻り値は正常です。構造は戻り値として正常に返されます。

3. API関数を直接呼び出す場合:

import console; 

testdll = raw.loadDll("C:\Users\Administrator\Desktop\test.dll")

var i = {int abc=123}
var a,b = testdll.test(i)

console.dump("a:",a)
console.dump("b:",b)
console.dump("i:",i)

console.pause(true);

結果は上記と同じです。structはアドレスを出力パラメータとして渡すことを強制されるためです。

 単純な文字列アドレステスト

1.簡単な言語で書かれたdllコード:

2. Aardio呼び出しの例(アドレス転送):

import console; 

testdll = raw.loadDll("C:\Users\Administrator\Desktop\test.dll")
test=testdll.api("test","string(string&)","stdcall")

var i =..string.fromto("张三丰")

var a,b = test(i)

console.dump("a:",a)
console.dump("b:",b)
console.dump("i:",i)

console.pause(true);

3.実装結果:

実行結果:着信APIテキストは正常です。APIのテキスト変数データの変更は失敗します。戻り値は正常です。発信パラメーターの変更されたデータは戻り値として返されます。

4. Aardio呼び出しの例(アドレスなし):

実行結果:受信APIテキストは正常です。APIのテキスト変数データの変更は成功しています。戻り値は正常です。追加の戻り値はありません。

私の大胆な推測

1.メモリデータのセキュリティやその他の目的を保護する目的である可能性があります。Aardioは構造以外のデータタイプを保護し、データが不正に改ざんされるのを防ぐためにアドレス指定を禁止します。

2.これらのデータタイプが強制的にアドレス指定されると、aardioはそれらのデータと一致する一時変数を申請し、実行のためにアドレスをapiに渡し、api実行結果と変更された一時変数データを取得してaardioに戻ります。

3. var i = 123などの変数のアドレスを取得するための正確で効果的な方法を提供できないため、いわゆる「読み取り専用」と「変更不可」は相対的な用語にすぎず、変更できないと感じます。

4.この推測を検証するには、lstrcpynテストを実行します。

テスト結果から、apiは渡された数値変数の値を正常に変更して返したことがわかりますが、実際には実際の変数の値は変更されていません。apiは一時変数の値を変更するため、aardioは一時変数の値も取得します。

5.上記のlstrcpynテストとテキストアドレステストに合格すると、結果は最初に上記の推測を満たします。

 

テキストアドレス指定とアドレス指定なしの詳細なテスト:

また、簡単な言語、機能でdllを記述します。

1.渡されたテキスト変数の値を表示します

2.渡されたテキスト変数のアドレスを表示します

3.渡されたテキスト変数のメモリデータを変更します

4.テキスト値を返します

1. [同じ内容]の2つの文字列変数を使用して、[アドレスなし]をテストします。

ステップ1:最初の変数t1を渡すと、apiプロンプトが表示されます。コンテンツは「ZhangSanfeng」で、変数アドレスは36655216です。

ステップ2:apiの変数t1の内容を「I'mfine」に変更します。aardioのコンソールにも同時に表示されます。戻り値は「hahaha」、t1は「I'mfine」です。OK、正解です。

ステップ3:2番目の変数t2を渡すと、apiはプロンプトを表示します。内容は「I'mfine」で、変数アドレスは36655216です。

それで問題は、なぜt2が「張三峰」ではないのかということです。

これは、aardioでは、同じコンテンツのテキスト変数が同じメモリアドレスを共有するためです。

1つを変更すると、すべてが変更されます。

これが、これら2つの変数に渡される「変数アドレス」が同じである理由です。

したがって、ここでapiに渡されるのは、文字列変数の「実際のアドレス」です。

4番目のステップ:実行が完了し、サスペンドはありません。

結論は次のとおりです。t1とt2は同じ内容で同じアドレスを持っています。apiが変数のメモリデータを変更する場合、それはすべての変更と同等です。「アドレスなし」の場合、代わりに実際のアドレスがapiに渡されます。

2. [異なる内容]の2つの文字列変数を使用して、[アドレス指定なし]をテストします。

ステップ1:最初の変数t1を渡すと、apiプロンプトが表示されます。コンテンツは「ZhangSanfeng」で、変数アドレスは27875392です。

ステップ2:apiの変数t1の内容を「I'mfine」に変更します。aardioのコンソールにも同時に表示されます。戻り値は「hahaha」、t1は「I'mfine」です。OK、正解です。

ステップ3:2番目の変数t2を渡すと、apiプロンプトが表示されます。コンテンツは「ZhangWuji」で、変数アドレスは27875424です。

ステップ4:実行後、変数t2の内容は「元気です」になります。

実行後の結論は、t1とt2の内容が異なり、アドレスも異なるということです。「アドレス送信なし」の場合、すべての実アドレスがapiに渡され、両方ともapiによって正常に変更されます。

3.同じ内容の2つの文字列変数を使用して、[アドレス転送]テスト実行します

文字列アドレスはaardioによって戻り値として返されるため、apiには複数の戻り値があります。したがって、以下のテストコードでは、apiの実行結果をconsole.logの最後のパラメーターに入れて、すべてになるようにします。表示。

ステップ1:最初の変数t1を渡すと、apiプロンプトが表示されます。コンテンツは「ZhangSanfeng」で、変数アドレスは27423792です。

ステップ2:apiの変数t1の内容が「私は元気です」に正常に変更されておらず、t1の実際の内容は「ZhangSanfeng」のままです。戻り値は「ははは」ですが、戻り値のt1は「元気です」です。 

3番目のステップ:2番目の変数t2を渡すと、apiプロンプト:コンテンツは「ZhangSanfeng」で、変数アドレスは27423792です。

同様に、t1は変更されていないため、t1とt2の内容とアドレスは同じです。したがって、t2は渡され、「ZhangSanfeng」のままです。

したがって、ここでapiに渡されるのは、文字列変数t1の「実際のアドレス」であってはなりません。

しかし、apiは正常に変更され、変更された「正しい」結果が返されました。したがって、ここでは、実際のt1の代わりに一時変数を使用してapiを「チート」したと思います。

さらに、2つの転送の一時変数アドレスは同じですが、最初の転送後、コンテンツは明らかに変更されますが、2番目の転送は復元されます。

これは、次のことを示しています。aardioが一時変数をapiに渡すと、最初に実変数の値が一時変数と同期されます。

ステップ4:実行が完了した後、結論は次のとおりです。「アドレスを渡す」場合は、最初に実変数の値を一時変数にコピーしてから、一時変数をapiに渡します。apiは一時変数の値を変更し、一時変数の値を返します。

4. [異なる]コンテンツを持つ2つの文字列変数を使用して、[アドレス転送]テスト実行します

ステップ1:最初の変数t1を渡すと、apiプロンプトが表示されます。コンテンツは「ZhangSanfeng」で、変数アドレスは36533296です。

ステップ2:apiの変数t1の内容が「私は元気です」に正常に変更されておらず、t1の実際の内容は「ZhangSanfeng」のままです。戻り値は「ははは」ですが、戻り値のt1は「元気です」です。 

ステップ3:2番目の変数t2を渡すと、apiプロンプトが表示されます。コンテンツは「ZhangWuji」で、変数アドレスは36533296です。OK、一時変数の波。

ステップ4:実行後、t2の実際の内容は「ZhangWuji」であり、戻り値は「hahaha」ですが、戻り値のt2は「Iamfine」です。 

結論は次のとおりです。上記と同じように、一時変数は波になります~~~

おすすめ

転載: blog.csdn.net/sdlgq/article/details/112465234