一、C#调用C++DLL 的普通函数和回调函数(C/C++内回调函数一般通过传递函数指针来实现,函数指针在C#中对应的就是委托)
C++ 代码:
//***********普通函数的导出****************
extern "C" _declspec(dllimport) int __stdcall Add(int num_one, int num_two);
//***********回调函数的导出*****************
typedef void (*callback_t)(int);
extern "C" _declspec(dllimport) bool __stdcall processCallback(callback_t, int param);
C#代码
public delegate void CallbackDelegate(int a); //声明委托
//接口定义
[DllImport(@"E:\IDATABK\DllTest\Debug\DllTest.dll", EntryPoint = "Add")]
public static extern int Add(int b, int a);
[DllImport(@"E:\IDATABK\DllTest\Debug\DllTest.dll", EntryPoint = "_processCallback@8")]
public static extern bool processCallback(CallbackDelegate call,int a);
//调用示例
public CallbackDelegate myDelegate = new CallbackDelegate(CallbackFunc);
int result= Add(1, 2);
processCallback(myDelegate, 3);
C#回调函数
public static void CallbackFunc(int a)
{
Console.WriteLine("参数1: {0}", a);
}
二 、 FLEX 调用C++的函数和回调函数
1、 建立一个C++的DLL ,这里要使用FLEX正对于C++写的一个运行库(FlashRuntimeExtensions.lib,使用方法查看官网文档),可以在FLASH BUILDER 的安装目录里找到
C++的.h 文件
#include "FlashRuntimeExtensions.h"
extern "C"
{
__declspec(dllexport) void initializer(void** extData, FREContextInitializer* ctxInitializer, FREContextFinalizer* ctxFinalizer);
__declspec(dllexport) void finalizer(void* extData);
}
C++ DLL 的CPP 文件
// ANETest.cpp : Defines the initialization routines for the DLL.
//
#include "stdafx.h"
#include <process.h>
#include "ANETest.h"
FREContext context;
//转换中文
void utf8_to_ansi(char* src, char* &dest)
{
int wcsLen = ::MultiByteToWideChar(CP_UTF8, NULL, src, strlen(src), NULL, 0);//测试转换
wchar_t* wszString = new wchar_t[wcsLen + 1];
::MultiByteToWideChar(CP_UTF8, NULL, src, strlen(src), wszString, wcsLen); //utf8 转Unicode
wszString[wcsLen] = '\0';
int ansiLen = ::WideCharToMultiByte(CP_ACP, NULL, wszString, wcslen(wszString), NULL, 0, NULL, NULL);
dest = new char[ansiLen + 1]; //unicode版对应的strlen是wcslen
::WideCharToMultiByte(CP_ACP, NULL, wszString, wcslen(wszString), dest, ansiLen, NULL, NULL);
dest[ansiLen] = '\0';
delete [] wszString;
}
//获取Char*长度
int getCharLength(char *chr)
{
int i = 0;
while (chr[i] != '\0') {
i++;
}
return i;
}
//拼接两个char*
char *addChar(char *a, char *b)
{
char* c;
c = (char*)malloc((getCharLength(a) + getCharLength(b) + 1)*sizeof(char));
int i,j = 0;
for (i = 0;a[i] != '\0';i++) {
c[j] = a[i];
j++;
}
for (i = 0; b[i] != '\0';i++) {
c[j] = b[i];
j++;
}
c[j] = '\0';
return c;
}
//sayHello
FREObject sayHello(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[])
{
uint32_t strLen;
const uint8_t * pName;
FREGetObjectAsUTF8(argv[0], &strLen, &pName);
char* name;
utf8_to_ansi((char*)pName, name);
char* hi = "Hello, ";
char *ret;
ret = addChar(hi, name);
FREObject objectByteArray = argv[1];
FREByteArray byteArray;
FREObject length;
FRENewObjectFromUint32(getCharLength(ret), &length);
FRESetObjectProperty(objectByteArray, (const uint8_t*) "length", length, NULL);
FREAcquireByteArray(objectByteArray, &byteArray);
memcpy(byteArray.bytes, ret, getCharLength(ret));
FREReleaseByteArray(objectByteArray);
return NULL;
}
/***********定义回调函数*****************/
typedef void (*callback_t)();
bool processCallback(callback_t p)
{
p();
return true;
}
/************回调函数的使用*****************/
FREObject callBackHello(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[])
{
FREObject objectByteArray = argv[0];
const uint8_t * pName;
uint32_t strLen;
FREGetObjectAsUTF8(argv[1], &strLen, &pName);
FREObject re;
FREResult es=FRECallObjectMethod(objectByteArray,pName,0,NULL,&re,NULL);
FREObject rest;
FRENewObjectFromInt32((int32_t)es,&rest);
return rest;
}
void __cdecl eventTestThread(void* param) {
_sleep(1000);
const uint8_t* msg1 = (const uint8_t*)"Hello World";
const uint8_t* msg2 = (const uint8_t*)"Message";
FREDispatchStatusEventAsync(context,msg1,msg2);
context = NULL;
}
FREObject eventTest(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[])
{
context = ctx;
_beginthread(eventTestThread, 0, NULL);
return NULL;
}
//方法信息
void contextInitializer(void* extData, const uint8_t* ctxType, FREContext ctx, uint32_t* numFunctions, const FRENamedFunction** functions)
{
*numFunctions = 3;
FRENamedFunction* func = (FRENamedFunction*) malloc(sizeof(FRENamedFunction) * (*numFunctions));
/********对于每一个方法的调用都要在此说明**********/
func[0].name = (const uint8_t*) "sayHello";
func[0].functionData = NULL;
func[0].function = &sayHello;
func[1].name = (const uint8_t*) "eventTest";
func[1].functionData = NULL;
func[1].function = &eventTest;
func[2].name = (const uint8_t*) "callBackHello";
func[2].functionData = NULL;
func[2].function = &callBackHello;
*functions = func;
}
void contextFinalizer(FREContext ctx)
{
return;
}
extern "C"
{
void initializer(void** extData, FREContextInitializer* ctxInitializer, FREContextFinalizer* ctxFinalizer)
{
*ctxInitializer = &contextInitializer;
*ctxFinalizer = &contextFinalizer;
}
void finalizer(void* extData)
{
return;
}
}
FLEX 端的操作
在FLEX中添加一个AIR 的桌面项目,将C++编译的DLL(CTest.dll) 添加到将其拷贝到Air工程extensions\src\windows目录下,打开
打开extensions.xml
<extension xmlns="http://ns.adobe.com/air/extension/3.1">
<id>com.bankcomm.test.CTestDll</id>
<versionNumber>1.0.0</versionNumber>
<platforms>
<platform name="Windows-x86">
<applicationDeployment>
<nativeLibrary>CTest.dll</nativeLibrary>
<initializer>initializer</initializer>
<finalizer>finalizer</finalizer>
</applicationDeployment>
</platform>
</platforms>
</extension>
这里需要注意的是id会映射到Air项目中的一个as类,nativeLibrary是刚才的dll名称,然后创建一个CTESTDLL.AS类
package com.bankcomm.Test
{
import flash.events.StatusEvent;
import flash.external.ExtensionContext;
import flash.utils.ByteArray;
import mx.controls.Alert;
import mx.core.FlexGlobals;
import mx.events.DynamicEvent;
public class CTestDll
{
private var context:ExtensionContext;
private var _callFuntion:Function;
public function CTestDll()
{
try {
context = ExtensionContext.createExtensionContext('com.bankcomm.Test.ANETestDll', 'type');
context.addEventListener(StatusEvent.STATUS,eventHandler);
} catch (e:Error) {
}
}
protected function eventHandler(e:StatusEvent):void
{
FlexGlobals.topLevelApplication.dispatchEvent(e);
}
public function sayHello(name:String, bytes:ByteArray):void
{
context.call('sayHello', name, bytes);
}
public function eventTest(bytes:ByteArray):void
{
var m:Object;
m=context.call("callBackHello",this,"callBuckTest");
context.call('eventTest', bytes);
}
public function callBuckTest():void
{
var my_name:String;
my_name="lvshiyu";
}
}
}
这里创建了一个与C++DLL 连接的上下文
context,调用了普通函数
sayHello 和回调函数
callBackHello。创建好之后建立一个编译文件build.xml,这个文件是要使用ANT才能编译的,具体使用FLASH BUILDER 的ANT 的方法可以参照这篇文章,对于使用ANT 的方法,可以看看官网的这文章
<?xml version="1.0" ?>
<project default="packagenativeextensions">
<!-- SDK properties -->
<property name="SDK_HOME" value="D:\Program Files (x86)\adobe\Adobe Flash Builder 4.6\sdks\4.6.0"/>
<property name="MXMLC.JAR" value="${SDK_HOME}/lib/mxmlc.jar"/>
<property name="COMPC.JAR" value="${SDK_HOME}/lib/compc.jar"/>
<property name="ADL" value="${SDK_HOME}/bin/adl.exe"/>
<property name="ADT.JAR" value="${SDK_HOME}/lib/adt.jar"/>
<!-- Project properties -->
<property name="APP_ROOT_DIR" value="."/>
<property name="APP_NAME" value="ANETest"/>
<property name="APP_ROOT_FILE" value="${APP_NAME}.swf"/>
<property name="APP_SOURCE_DIR" value="${APP_ROOT_DIR}/src"/>
<property name="MAIN_SOURCE" value="${APP_SOURCE_DIR}/${APP_NAME}.mxml"/>
<property name="APP_SOURCE_DESCRIPTOR" value="${APP_SOURCE_DIR}/${APP_NAME}-app.xml"/>
<property name="KEYSTORE" location="${APP_ROOT_DIR}/wvw.p12"/>
<property name="STOREPASS" value="geheim"/>
<!-- Native Extensions -->
<property name="NATIVE_EXTENSION_NAME" value="ANETestDll"/>
<property name="NATIVE_EXTENSION_ACTIONSCRIPT_CLASSES" value="com.bankcomm.test.CTestDll" />
<property name="NATIVE_EXTENSION_TMP_DIR" value="${APP_ROOT_DIR}/extensions/tmp"/>
<property name="NATIVE_EXTENSION_BIN_DIR" value="${APP_ROOT_DIR}/extensions/bin"/>
<property name="NATIVE_EXTENSION_SRC_DIR" value="${APP_ROOT_DIR}/extensions/src"/>
<property name="NATIVE_EXTENSION_UNZIPPED_DIR" value="${APP_ROOT_DIR}/extensions/unzipped"/>
<!-- Debug settings -->
<property name="debug" location="${APP_ROOT_DIR}/bin-debug"/>
<property name="APP_DEBUG_DESCRIPTOR" value="${debug}/${APP_NAME}-app.xml"/>
<target name="init" depends="clean">
<mkdir dir="${debug}"/>
<mkdir dir="${NATIVE_EXTENSION_BIN_DIR}"/>
<mkdir dir="${NATIVE_EXTENSION_UNZIPPED_DIR}"/>
</target>
<target name="compilenativeextensions" depends="init">
<mkdir dir="${NATIVE_EXTENSION_TMP_DIR}"/>
<java jar="${COMPC.JAR}" fork="true" failοnerrοr="true">
<arg value="+flexlib=${SDK_HOME}/frameworks"/>
<arg value="+configname=air"/>
<arg value="-source-path"/>
<arg value="src"/>
<arg value="-include-classes"/>
<arg value="${NATIVE_EXTENSION_ACTIONSCRIPT_CLASSES}"/>
<arg value="-external-library-path"/>
<arg value="${SDK_HOME}/frameworks/libs/air/airglobal.swc"/>
<arg value="-output"/>
<arg value="${NATIVE_EXTENSION_TMP_DIR}/nativeextensions.swc"/>
</java>
<unzip src="${NATIVE_EXTENSION_TMP_DIR}/nativeextensions.swc" dest="${NATIVE_EXTENSION_TMP_DIR}" />
</target>
<target name="packagenativeextensions" depends="compilenativeextensions">
<!-- dll files -->
<pathconvert property="nativeExtensionFiles" pathsep="' '" dirsep="/">
<path>
<fileset dir="${NATIVE_EXTENSION_SRC_DIR}" includes="**/*.dll"/>
</path>
<chainedmapper>
<flattenmapper/>
</chainedmapper>
</pathconvert>
<echo>native extension files: ${nativeExtensionFiles}</echo>
<!-- flatten directory -->
<copy todir="${NATIVE_EXTENSION_TMP_DIR}" flatten="true">
<fileset dir="${NATIVE_EXTENSION_SRC_DIR}" />
</copy>
<java jar="${ADT.JAR}" fork="true" dir="${NATIVE_EXTENSION_TMP_DIR}" failοnerrοr="true">
<arg value="-package"/>
<arg value="-storetype"/>
<arg value="pkcs12"/>
<arg value="-storepass"/>
<arg value="${STOREPASS}"/>
<arg value="-keystore"/>
<arg value="${KEYSTORE}"/>
<arg value="-tsa"/>
<arg value="none"/>
<arg value="-target"/>
<arg value="ane"/>
<arg value="${NATIVE_EXTENSION_NAME}.ane"/>
<arg value="extension.xml"/>
<arg value="-swc"/>
<arg value="nativeextensions.swc"/>
<arg value="-platform"/>
<arg value="Windows-x86"/>
<arg value="library.swf"/>
<arg line="'${nativeExtensionFiles}'" />
</java>
<copy file="${NATIVE_EXTENSION_TMP_DIR}/${NATIVE_EXTENSION_NAME}.ane" tofile="${NATIVE_EXTENSION_BIN_DIR}/${NATIVE_EXTENSION_NAME}.ane" />
<delete dir="${NATIVE_EXTENSION_TMP_DIR}"/>
</target>
<target name="unpacknativeextensions" depends="packagenativeextensions">
<unzip src="${NATIVE_EXTENSION_BIN_DIR}/${NATIVE_EXTENSION_NAME}.ane" dest="${NATIVE_EXTENSION_UNZIPPED_DIR}/${NATIVE_EXTENSION_NAME}.ane" />
</target>
<target name="debugcompile" depends="unpacknativeextensions">
<java jar="${MXMLC.JAR}" fork="true" failοnerrοr="true">
<arg value="-debug=true"/>
<arg value="+flexlib=${SDK_HOME}/frameworks"/>
<arg value="+configname=air"/>
<arg value="-file-specs=${MAIN_SOURCE}"/>
<arg value="-output=${debug}/${APP_ROOT_FILE}"/>
</java>
<copy filtering="true" file="${APP_SOURCE_DESCRIPTOR}" tofile="${APP_DEBUG_DESCRIPTOR}" />
<replace file="${APP_DEBUG_DESCRIPTOR}">
<replacefilter token="[This value will be overwritten by Flash Builder in the output app.xml]" value="${APP_ROOT_FILE}"/>
</replace>
</target>
<target name="test" depends="debugcompile">
<exec executable="${ADL}">
<arg value="${APP_DEBUG_DESCRIPTOR}"/>
<arg value="-extdir"/>
<arg value="${NATIVE_EXTENSION_UNZIPPED_DIR}" />
<arg value="${debug}"/>
</exec>
</target>
<target name="clean" description="clean up">
<delete dir="${debug}"/>
<delete dir="${NATIVE_EXTENSION_BIN_DIR}"/>
<delete dir="${NATIVE_EXTENSION_TMP_DIR}"/>
<delete dir="${NATIVE_EXTENSION_UNZIPPED_DIR}"/>
</target>
</project>
SDK_HOME- 4.6 sdk位置
APP_NAME- Air项目名称
NATIVE_EXTENSION_NAME- 打包后ane的名称
NATIVE_EXTENSION_ACTIONSCRIPT_CLASSES- 映射的as类
成功后会在extensions\bin目录下出现一个ANETestDll.ane
在项目的右键属性里面的构建里面添加本地扩展里面,将ANETESTDLL.ANE打勾,在项目的主文件里面的代码
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
creationComplete="creationCompleteHandler(event)">
<fx:Declarations>
</fx:Declarations>
<fx:Script>
<![CDATA[
import com.bankcomm.Test.ANETestDll;
import mx.controls.Alert;
import mx.events.FlexEvent;
public var aneTestDll:ANETestDll;
protected function creationCompleteHandler(event:FlexEvent):void
{
aneTestDll = new ANETestDll();
addEventListener(StatusEvent.STATUS, statusHandler);
}
public function statusHandler(e:StatusEvent):void
{
var level:String = e.level;
var code:String = e.code;
Alert.show(code);
}
private function sayHello():void
{
var bytes:ByteArray = new ByteArray();
aneTestDll.sayHello(txtName.text, bytes);
var ret:String = bytes.readMultiByte(bytes.length,"chinese");
Alert.show(ret);
}
private function eventTest():void
{
var bytes:ByteArray = new ByteArray();
aneTestDll.eventTest(bytes);
}
]]>
</fx:Script>
<s:VGroup paddingTop="10" paddingLeft="10">
<s:HGroup verticalAlign="baseline">
<s:Label text="My Name is:"/>
<s:TextInput id="txtName"/>
</s:HGroup>
<s:HGroup width="100%" horizontalAlign="right">
<s:Button label="Say Hello" click="sayHello()"/>
</s:HGroup>
<s:Button label="Event Test" click="eventTest()"/>
</s:VGroup>
</s:WindowedApplication>