使用AIR透過ANE連接原生C++操控滑鼠-Part 1

| Comments

12

大家好我是阿邪。

以前在製作FLASH時,我們可以透過滑鼠的控制來達成許多互動效果。

可是今天如果反過來說:那我們能不能不用滑鼠去控制系統滑鼠座標與點擊動作?

FLASH能辦到的只有透過dispatchEvent()去發送一個假的滑鼠點擊事件,但充其量它還是個模擬出來的假事件!!

改變系統滑鼠座標,單靠目前的FLASH是辦不到的,還是得靠系統原生語言來控制!

好在現在我們可以利用AIR透過ANE(AIR Native Extension)原生擴充功能來與原生語言動態函式庫的聯繫。

目前關於ANE的文章大部分都是以行動裝置ios,android的原生拓展的文章較多

桌面應用程式方面的原生拓展文章則較少著墨。

剛好現在做的專案遇到這樣的問題,順便來筆記一下如何讓AIR透過ANE去跟C++溝通。

本教學原文是參考此篇教學:點我

以下是我的開發環境:

FlashDevelop 4.0.4 RTM
FlexSDK 4.6(目前最新版本為4.6)
AIRSDK 3.3 (目前最新版本為3.4,至少要3.0以上)
M$ Visual Studio Express 2012

Part1 : C++端的程式撰寫

在此聲明!我是個Flasher!!我完完全全的不會寫C++

所以內文有疑慮或是解釋錯的地方煩請高手多多包涵!

首先打開我們的Visual Studio Express 2012

新增專案:

01

選擇Win32專案

並填好專案名稱跟儲存位置

我專案名稱是命名NativeApp

02

應用程式類型選擇為DLL(Dynamic Link Library)動態連結類別庫

03

先到dllmain.cpp,這是dll程式的進入點

將dllmain.cpp預設內容改成

dllmain.cpp
1
2
3
4
5
6
7
8
// dllmain.cpp : 定義 DLL 應用程式的進入點。
#include <windows.h>
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved)
{
      return TRUE;
}

之後將原始程式檔裡的stdafx.cpp跟標頭檔裡兩個stdafx.htargetver.h砍掉

然後到你下載好的flex sdk裡include資料夾

將裡面的FlashRuntimeExtensions.h複製起來

到你NativeApp的專案裡的NativeApp資料夾貼上

04

OK之後再回到Flex SDK>lib找到win資料夾

裡面有一個FlashRuntimeExtensions.lib把它複製起來

一樣把它丟到你NativeApp的專案裡的NativeApp資料夾

05

這個階段OK之後回到Visual Studio Express 2012

在標頭檔的資料夾上按右鍵加入>現有項目>FlashRuntimeExtensions.h

結束後再加入一個新增項目>選擇標頭檔(.h),然後命名NativeApp.h

06

下一個步驟就是將FlashRuntimeExtensions.lib給加進來

在上面的NativeApp按右建>加入>現有項目>FlashRuntimeExtensions.lib

全部改完之後會像這樣

07

接下來因為我們之前去掉stdafx.h,我們需要告訴編譯器不要找到他!不然會一直出錯!!

我們到NativeApp上按右鍵選擇屬性 > C/C++ > 先行編譯標頭檔選擇未使用先行編譯標頭檔!

08

設定差不多了!可以開始coding了!

首先打開NativeApp.h

我們輸入以下程式碼

NativeApp.h
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "FlashRuntimeExtensions.h"  
//用 extern "C"將C++指令轉換成C語言 
//原因是防止C++名稱重整器造成函數名稱的錯位
extern "C"
{
  __declspec(dllexport) void ExtInitializer(void** extDataToSet, FREContextInitializer* ctxInitializerToSet, FREContextFinalizer* ctxFinalizerToSet);

  __declspec(dllexport) void ExtFinalizer(void* extData);

  __declspec(dllexport) FREObject setMousePosition(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]);

  __declspec(dllexport) FREObject mouseClick(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]);
}

這邊宣告四種方法

初始化(ExtInitializer)與終結(ExtFinalizer)這兩個方法是必須的

setMousePosition,mouseClick這兩個方法是用來給AS3調用的

setMousePosition是改變系統滑鼠的座標

mouseClick是觸發系統的滑鼠Click

接下來編寫NativeApp.cpp 輸入以下程式

NativeApp.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include "NativeApp.h"
#include <stdlib.h>
#include <windows.h>

extern "C"
{

   FREObject setMousePosition(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[])
   {
    //AS3傳來的參數會存在argv[]裡
    int32_t x,y;
  
    //將AS3數據轉成C++
    FREGetObjectAsInt32 ( argv[0], &x);
    FREGetObjectAsInt32 ( argv[1], &y);

    //設定系統的座標,為Windows.h裡的方法
    SetCursorPos(x,y);

    //如果不在意回傳數值就回傳第一個參數
    //如果需要回傳經計算過的數值請記得利用FRE Object轉成AS3看得懂的數據
    return argv[0];
   }

   FREObject mouseClick(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[])
   {
    //觸發滑鼠事件,click事件其實就是mousedown跟mouseup的組合
    mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 );
    return argv[0];
   }

   void ContextInitializer(void* extData, const uint8_t* ctxType, FREContext ctx, uint32_t* numFunctions, const FRENamedFunction** functions)
   {
    //在初始化時宣告可以被AS3調用的方法
    *numFunctions = 2;
    FRENamedFunction* func = (FRENamedFunction*)malloc(sizeof(FRENamedFunction)*(*numFunctions));
  
      
    func[0].name = (const uint8_t*)"setMousePosition";
    func[0].functionData = NULL;
    func[0].function = &setMousePosition;

    func[1].name = (const uint8_t*)"mouseClick";
    func[1].functionData = NULL;
    func[1].function = &mouseClick;
      
    *functions = func;
    }


    void ContextFinalizer(FREContext ctx)
    {
  return;
    }

    void ExtInitializer(void** extData, FREContextInitializer* ctxInitializer, FREContextFinalizer* ctxFinalizer)
    {
  
  *ctxInitializer = &ContextInitializer;
  *ctxFinalizer   = &ContextFinalizer;
    }

    void ExtFinalizer(void* extData)
    {
  return;
    }
}

結束後!程式就完成了!可以編譯出dll檔

選擇上方的"建置">建置方案

當然你可以選擇你要編譯debug還是release版本

9

編譯成功下面會輸出

10

關於C++與AS3之間的數據轉換的類別可以參考→點我

Comments