Android Hotfix 新方案——Amigo 源码解读

Android Hotfix 新方案——Amigo 源码解读
Android Hotfix 新方案——Amigo 源码解读

Android Hotfix 新方案——Amigo 源码解读

首先我们先来看看如何使用这个库。

用法

在project 的build.gradle中

dependencies {

classpath 'me.ele:amigo:0.0.3'

}

在module 的build.gradle中

apply plugin: 'me.ele.amigo'

就这样轻松的集成了Amigo。

生效补丁包

补丁包生效有两种方式可以选择:

?

稍后生效补丁包

?

如果不想立即生效而是用户第二次打开App 时才打入补丁包,则可以将新的Apk 放到/data/data/{your pkg}/files/amigo/demo.apk,第二次打开时就会自动生效。可以通过这个方法

?

File hotfixApk = Amigo.getHotfixApk(context);

?

获取到新的Apk。

同时,你也可以使用Amigo 提供的工具类将你的补丁包拷贝到指定的目录当中。

?

FileUtils.copyFile(yourApkFile, amigoApkFile);

?

?

立即生效补丁包

?

如果想要补丁包立即生效,调用以下两个方法之一,App 会立即重启,

并且打入补丁包。

?

Amigo.work(context);

?

Amigo.work(context, apkFile);

?

删除补丁包

如果需要删除掉已经下好的补丁包,可以通过这个方法

Amigo.clear(context);

提示:如果apk 发生了变化,Amigo 会自动清除之前的apk。

自定义界面

在热修复的过程中会有一些耗时的操作,这些操作会在一个新的进程中的Activity 中执行,所以你可以通过以下方式来自定义这个Activity。

android:name="amigo_layout"

android:value="{your-layout-name}" />

android:name="amigo_theme"

android:value="{your-theme-name}" />

组件修复

Amigo 目前能够支持增加Activity 和BroadcastReceiver。只需要将新的Activity 和BroadcastReceiver 加到新的Apk 包中就可以了。Service 和ContentProvider 将会在未来的版本中支持更新。

集成Amigo 十分简单,但是明白Amigo 的实现更加重要。

源码分析

在Amigo这个类中实现了主要的修复工作。我们一起追追看,到底是怎样的实现。

检查补丁包

Amigo.java

...

if (demoAPk.exists() && isSignatureRight(this, demoAPk)) {

SharedPreferences sp = getSharedPreferences(SP_NAME,

MODE_MULTI_PROCESS);

String demoApkChecksum = checksum(demoAPk);

boolean isFirstRun = !sp.getString(NEW_APK_SIG,

"").equals(demoApkChecksum);...

这段代码中,首先检查是否有补丁包,并且签名正确,如果正确,则通过检验校验和是否与之前的检验和相同,不同则为检测到新的补丁包。

释放Apk

当这是新的补丁包时,首先第一件事就是释放。ApkReleaser.work(this, layoutId, themeId)在这个方法中最终会去开启一个ApkReleaseActivity,而这个Activity 的layout 和theme 就是之前从配置中解析出来,在work 方法中传进来的layoutId 和themeId。

ApkReleaseActivity.java

@Overrideprotected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

...

new Thread() {

@Override

public void run() {

super.run();

DexReleaser.releaseDexes(demoAPk.getAbsolutePath(),

dexDir.getAbsolutePath());

NativeLibraryHelperCompat.copyNativeBinaries(demoAPk, nativeLibraryDir);

dexOptimization();

handler.sendEmptyMessage(WHAT_DEX_OPT_DONE);

}

}.start();

}

在ApkReleaseActivity 的onCreate()方法中会开启一个线程去进行一系列的释放操作,这些操作十分耗时,目前在不同的机子上测试,从几秒到二十几秒之间不等,如果就这样黑屏在用户前面未免太不优雅,所以Amigo 开启了一个新的进程,启动这个Activity。

在这个线程中,做了三件微小的事情:

?释放Dex 到指定目录

?

拷贝so 文件到Amigo 的指定目录下

拷贝so 文件是通过反射去调用NativeLibraryHelper这个类的

nativeCopyNativeBinaries()方法,但这个方法在不同版本上有不同的实现。

?

o

如果版本号在21以下

o

NativeLibraryHelper

o

public static int copyNativeBinariesIfNeededLI(File apkFile, File sharedLibraryDir) {

final String cpuAbi = Build.CPU_ABI;

final String cpuAbi2 = Build.CPU_ABI2;

return nativeCopyNativeBinaries(apkFile.getPath(), sharedLibraryDir.getPath(), cpuAbi,

cpuAbi2);

}

会去反射调用这个方法,其中系统会自动判断出primaryAbi 和secondAbi。

o如果版本号在21以上

copyNativeBinariesIfNeededLI(file, file)这个方法已经被废弃

了,需要去反射调用这个方法

NativeLibraryHelper

public static int copyNativeBinaries(Handle handle, File sharedLibraryDir, String abi) {

for (long apkHandle : handle.apkHandles) {

int res = nativeCopyNativeBinaries(apkHandle, sharedLibraryDir.getPath(), abi,

handle.extractNativeLibs, HAS_NATIVE_BRIDGE);

if (res != I NSTALL_SUCCEEDED) {

return res;

}

}

return I NSTALL_SUCCEEDED;

}

所以首先得去获得一个NativeLibraryHelper$Handle类的实例。之后就是找primaryAbi。Amigo 先对机器的位数做了判断,如果是64位的机子,就只找64位的abi,如果是32位的,就只找32位的abi。然后将Handle 实例当做参数去调用NativeLibraryHelper的findSupportedAbi来获得primaryAbi。最后再去调用copyNativeBinaries去拷贝so 文件。

?

优化dex 文件

?

ApkReleaseActivity.java

?

private void dexOptimization() {

...

for (File dex : validDexes) {

new DexClassLoader(dex.getAbsolutePath(), optimizedDir.getAbsolutePath(), null,

DexUtils.getPathClassLoader());

Log.e(TAG, "dexOptimization finished-->" + dex);

}

}

?DexClassLoader 没有做什么事情,只是调用了父类构造器,他的父类是BaseDexClassLoader。在BaseDexClassLoader 的构造器中又去构造了一个DexPathList 对象。

在DexPathList类中,有一个Element 数组

?DexPathList

?

/** list of dex/resource (class path) elements */private final Element[] dexElements;

?Element 就是对Dex 的封装。所以一个Element 对应一个Dex。这个Element 在后文中会提到。

?

优化dex 只需要在构造DexClassLoader 对象的时候将dex 的路径传进去,系统会在最后会通过DexFile的

?DexFile.java

?

native private static int openDexFile(String sourceName, String outputName,

int flags) throws IOException;

?

来这个方法来加载dex,加载的同时会对其做优化处理。

?

这三项操作完成之后,通知优化完毕,之后就关闭这个进程,将补丁包的校验和保存下来。这样第一步释放Apk 就完成了。之后就是重头戏替换修复。

替换修复

替换classLoader

Amigo 先行构造一个AmigoClassLoader对象,这个AmigoClassLoader是一个继承于PathClassLoader的类,把补丁包的Apk 路径作为参数来构造AmigoClassLoader对象,之后通过反射替换掉LoadedApk 的ClassLoader。这一步是Amigo 的关键所在。

替换Dex

之前提到,每个dex 文件对应于一个PathClassLoader,其中有一个Element[],Element 是对于dex 的封装。

Amigo.java

private void setDexElements(ClassLoader classLoader) throws NoSuchFieldException, IllegalAccessException {

Object dexPathList = getPathList(classLoader);

File[] listFiles = dexDir.listFiles();

List validDexes = new ArrayList<>();

for (File listFile : listFiles) {

if (listFile.getName().endsWith(".dex")) {

validDexes.add(listFile);

}

}

File[] dexes = validDexes.toArray(new File[validDexes.size()]);

Object originDexElements = readField(dexPathList, "dexElements"); Class localClass =

originDexElements.getClass().getComponentType();

int length = dexes.length;

Object dexElements = Array.newInstance(localClass, length);

for (int k = 0; k < length; k++) {

Array.set(dexElements, k, getElementWithDex(dexes[k], optimizedDir));

}

writeField(dexPathList, "dexElements", dexElements);

}

在替换dex时,Amigo 将补丁包中每个dex 对应的Element 对象拿出来,之后组成新的Element[],通过反射,将现有的Element[] 数组替换掉。

在QZone 的实现方案中,他们是通过将新的dex 插到Element[] 数组的第一个位置,这样就会先加载新的dex ,微信的方案是下发一个DiffDex,然后在运行时与旧的dex 合成一个新的dex。但是Amigo 是下发一个完整的dex直接替换掉了原来的dex。与其他的方案相比,Amigo 因为直接替换原来的dex ,兼容性更好,能够支持修复的方面也更多。但是这也导致了Amigo 的补丁包会较大,当然,也可以发一个利用BsDiff 生成的差分包,在本地合成新的apk 之后再放到Amigo 的指定目录下。

替换动态链接库

Amigo.java

private void setNativeLibraryDirectories(AmigoClassLoader hackClassLoader)

throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, NoSuchFieldException { injectSoAtFirst(hackClassLoader,

nativeLibraryDir.getAbsolutePath());

nativeLibraryDir.setReadOnly();

File[] libs = nativeLibraryDir.listFiles();

if (libs != null && libs.length > 0) {

for (File lib : libs) {

lib.setReadOnly();

}

}

}

so 文件的替换跟QZone 替换dex 原理相差不多,也是利用ClassLoader 加载library 的时候,将新的library 加到数组前面,保证先加载的是新的library。但是这里会有几个小坑。

DexUtils.java

public static void injectSoAtFirst(ClassLoader hackClassLoader, String soPath) throws NoSuchFieldException, IllegalAccessException,

NoSuchMethodException, InvocationTargetException, InstantiationException {

Object[] baseDexElements =

getNativeLibraryDirectories(hackClassLoader);

Object newElement;

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

Constructor constructor =

baseDexElements[0].getClass().getConstructors()[0];

constructor.setAccessible(true);

Class[] parameterTypes = constructor.getParameterTypes(); Object[] args = new Object[parameterTypes.length];

for (int i = 0; i < parameterTypes.length; i++) {

if (parameterTypes[i] == File.class) {

args[i] = new File(soPath);

} else if (parameterTypes[i] == boolean.class) {

args[i] = true;

}

}

newElement = constructor.newInstance(args);

} else {

newElement = new File(soPath);

}

Object newDexElements =

Array.newInstance(baseDexElements[0].getClass(), 1);

Array.set(newDexElements, 0, newElement);

Object allDexElements = combineArray(newDexElements, baseDexElements);

Object pathList = getPathList(hackClassLoader);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

writeField(pathList, "nativeLibraryPathElements", allDexElements);

} else {

writeField(pathList, "nativeLibraryDirectories", allDexElements);

}

}

注入so 文件到数组时,会发现在不同的版本上封装so 文件的是不同的类,在版本23以下,是File

DexPathList.java

/** list of native library directory elements */private final File[] nativeLibraryDirectories;

在23以上却是改成了Element

DexPathList.java

/** List of native library path elements. */private final Element[] nativeLibraryPathElements;

因此在23以上,Amigo 通过反射去构造一个Element 对象。之后就是将so 文件插到数组的第一个位置就行了。

第二个小坑是nativeLibraryDir要设置成readOnly。

DexPathList.java

public String findNativeLibrary(String name) {

maybeInit();

if (isDirectory) {

String path = new File(dir, name).getPath();

if (IoUtils.canOpenReadOnly(path)) {

return path;

}

} else if (zipFile != null) {

String entryName = new File(dir, name).getPath();

if (isZipEntryExistsAndStored(zipFile, entryName)) {

return zip.getPath() + zipSeparator + entryName;

}

}

return null;

}

在ClassLoader 去寻找本地库的时候,如果so 文件没有设置成ReadOnly的话是会不会返回路径的,这样就会报错了。

替换资源文件

Amigo.java

...AssetManager assetManager = AssetManager.class.newInstance();Method addAssetPath = getDeclaredMethod(AssetManager.class, "addAssetPath", String.class);

addAssetPath.setAccessible(true);

addAssetPath.invoke(assetManager, demoAPk.getAbsolutePath()); setAPKResources(assetManager)

...

想要更新资源文件,只需要更新Resource中的AssetManager 字段。AssetManager提供了一个方法addAssetPath。将新的资源文件路径加到AssetManager中就可以了。在不同的configuration 下,会对应不同的Resource 对象,所以通过ResourceManager 拿到所有的configuration 对应的resource 然后替换其assetManager。

替换原有 Application

Amigo.java

...

Class acd = classLoader.loadClass("me.ele.amigo.acd");String applicationName = (String) readStaticField(acd, "n");

Application application = (Application)

classLoader.loadClass(applicationName).newInstance();Method attach = getDeclaredMethod(Application.class, "attach", Context.class);

attach.setAccessible(true);

attach.invoke(application, getBaseContext());

setAPKApplication(application);

application.onCreate();

...

在编译过程中,Amigo 的插件将app 的application 替换成了Amigo,并且将原来的application 的name 保存在了一个名为acd的类中,该修复的都修复完了是时候将原来的application 替换回来了。拿到原有Application 名字之后先调用application 的attach(context),然后将application 设回到loadedApk 中,最后调用oncreate(),执行原有Application 中的逻辑。

这之后,一个修复完的app 就出现在用户面前。优秀的库~

Amigo 插件

前文提到Amigo 在编译期利用插件替换了app 原有的application,那这一个操作是怎么实现的呢?

AmigoPlugin.groovy

File manifestFile = output.processManifest.manifestOutputFile

def manifest =new XmlParser().parse(manifestFile)

def androidTag =new

Namespace("https://www.360docs.net/doc/001390714.html,/apk/res/android", 'androi d')

applicationName =

manifest.application[0].attribute(https://www.360docs.net/doc/001390714.html,)

manifestFile.text =

manifestFile.text.replace(applicationName, "me.ele.amigo.Amigo")

首先,Amigo Plugin 将AndroidManifest.xml 文件中的applicationName 替换成Amigo。

AmigoPlugin.groovy

Node node = (new XmlParser()).parse(manifestFile)Node appNode = nullfor (Node n : node.children()) {

if (https://www.360docs.net/doc/001390714.html,().equals("application")) {

appNode = n;

break

}

}Node hackAppNode = new Node(appNode, "activity")

hackAppNode.attributes().put("android:name", applicationName) manifestFile.text = XmlUtil.serialize(node)

之后,Amigo Plugin 做了很hack 的一步,就是在AndroidManifest.xml 中将原来的application 做为一个Activity 。我们知道MultiDex 分包的规则中,一定会将Activity 放到主dex 中,Amigo Plugin 为了保证原来的application 被替换后仍然在主dex 中,就做了这个十分hack 的一步。机智的少年。

接下来会再去判断是否开启了混淆,如果有混淆的话,查找mapping 文件,将applicationName 字段换成混淆后的名字。

下一步会去执行GenerateCodeTask,在这个task 中会生成一个Java 文件,这个文件就是上文提到过得acd.java,并且将模板中的appName 替换成applicationName。

然后执行javaCompile task,编译Java 代码。

最后还要做一件事,就是修改maindexlist.txt。被定义在这个文件中的类会被加到主dex 中,所以Amigo plugin 在collectMultiDexInfo方法中扫描加到主dex 的类,然后再在扫描的结果中加上acd.class,把这些内容全部加到maindexlist.txt。到此Amigo plugin 的任务就完成了。

Amigo plugin 的主要目的是在编译期用amigo 替换掉原来的application,但是还得保存下来这个application,因为之后还得在运行时将这个application 替换回来。

总结

Amigo 几乎实现了全方位的修复,通过替换ClassLoader,直接全量替换dex 的思路,保证了兼容性,成功率,但是可能下发的补丁包会比较大。还有一点Amigo

的精彩之处就是利用Amigo 替换了app 原有的application,这一点保证了Amigo 连application 都能修复。以后可能唯一不能修复的就是Amigo 自身了。

最后我们比较下目前几个hotfix 方案:

Amigo Tinker nuwa/QZone AndFix Dexposed

类替换yes yes yes no no

lib替换yes yes no no no

资源替换yes yes yes no no

全平台支持yes yes yes yes no

即时生效optional no no yes yes

性能损耗无较小较大较小较小

补丁包大小较大较小较大一般一般

开发透明yes yes yes no no

复杂度无较低较低复杂复杂

gradle支持yes yes yes no no

接口文档丰富丰富一般一般较少

占Rom体积较大较大较小较小较小

成功率100%较好很高一般一般

经典的串口调试工具源代码(一)

经典的串口调试助手源代码(一) Dim OutputAscii As Boolean Dim InputString As String Dim OutputString As String '============================================================================== ======= ' 变量定义 '============================================================================== ======= Option Explicit ' 强制显式声明 Dim ComSwitch As Boolean ' 串口开关状态判断 Dim FileData As String ' 要发送的文件暂存Dim SendCount As Long ' 发送数据字节计数器 Dim ReceiveCount As Long ' 接收数据字节计数器Dim InputSignal As String ' 接收缓冲暂存 Dim OutputSignal As String ' 发送数据暂存 Dim DisplaySwitch As Boolean ' 显示开关 Dim ModeSend As Boolean ' 发送方式判断

Dim Savetime As Single ' 时间数据暂存延时用Dim SaveTextPath As String ' 保存文本路径 ' 网页超链接申明 Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long Private Sub CloseCom() '关闭串口 On Error GoTo Err If MSComm.PortOpen = True Then MSComm.PortOpen = False ' 先判断串口是否打 开,如果打开则先关闭 txtstatus.Text = "STATUS:COM Port Cloced" ' 串口状态显示 mnuconnect.Caption = "断开串口" cmdswitch.Caption = "打开串口" 'ImgSwitch.Picture = LoadPicture("f:\我的VB\串口调试软件\图片\guan.jpg") ' 显示串口已经关闭 的图标 ImgSwitchoff.Visible = True ImgSwitchon.Visible = False Err: End Sub Private Sub UpdateStatus() If MSComm.PortOpen Then StatusBar1.Panels(1).Text = "Connected" mnuautosend.Caption = "自动发送" mnuconnect.Caption = "断开串口" Else StatusBar1.Panels(1).Text = "断开串口" mnuautosend.Caption = "disautosend" mnuconnect.Caption = "打开串口" End If StatusBar1.Panels(2).Text = "COM" & https://www.360docs.net/doc/001390714.html,mPort StatusBar1.Panels(3).Text = MSComm.Settings If (OutputAscii) Then StatusBar1.Panels(4) = "ASCII" Else StatusBar1.Panels(4) = "HEX" End If ' On Error GoTo Err If ChkAutoSend.Value = 1 Then ' 如果有效则,自动发送

Android Hotfix 新方案——Amigo 源码解读

Android Hotfix 新方案——Amigo 源码解读 首先我们先来看看如何使用这个库。 用法 在project 的build.gradle中 dependencies { classpath 'me.ele:amigo:0.0.3' } 在module 的build.gradle中 apply plugin: 'me.ele.amigo' 就这样轻松的集成了Amigo。 生效补丁包 补丁包生效有两种方式可以选择: ? 稍后生效补丁包 ? 如果不想立即生效而是用户第二次打开App 时才打入补丁包,则可以将新的Apk 放到/data/data/{your pkg}/files/amigo/demo.apk,第二次打开时就会自动生效。可以通过这个方法 ? File hotfixApk = Amigo.getHotfixApk(context); ?

获取到新的Apk。 同时,你也可以使用Amigo 提供的工具类将你的补丁包拷贝到指定的目录当中。 ? FileUtils.copyFile(yourApkFile, amigoApkFile); ? ? 立即生效补丁包 ? 如果想要补丁包立即生效,调用以下两个方法之一,App 会立即重启, 并且打入补丁包。 ? Amigo.work(context); ? Amigo.work(context, apkFile); ? 删除补丁包 如果需要删除掉已经下好的补丁包,可以通过这个方法 Amigo.clear(context); 提示:如果apk 发生了变化,Amigo 会自动清除之前的apk。 自定义界面 在热修复的过程中会有一些耗时的操作,这些操作会在一个新的进程中的Activity 中执行,所以你可以通过以下方式来自定义这个Activity。

(通信企业管理)经典串口调试助手源程序及串口通信设置精编

(通信企业管理)经典串口调试助手源程序及串口通 信设置

串口调试助手源程序 及编程详细过程 作者:龚建伟2001.6.20 能够任意转载,但必须注明作者和说明来自https://www.360docs.net/doc/001390714.html,,不得作为商用 目次: 1.建立项目 2.于项目中插入MSComm控件 3.利用ClassWizard定义CMSComm类控制变量 4.于对话框中添加控件 5.添加串口事件消息处理函数OnComm() 6.打开和设置串口参数 7.发送数据 如果你仍没有下载源程序,又对本文有兴趣,请立即下载 于众多网友的支持下,串口调试助手从2001年5月21日发布至今,短短壹个月,于全国各地累计下载量近5000人次,于近200多个电子邮件中,20多人提供了使用测试意见,更有50多位朋友提出要串口调试助手的源代码,为了答谢谢朋友们的支持,公开推出我最初用VC控件MSComm编写串口通信程序的源代码,且写出详细的编程过程,姑且叫串口调试助手源程序V1.0或VC串口通讯源程序吧,我相信,如果你用VC编程,那么有了这个代码,就能够轻而易举地完成串口编程任务了。(也许本文过于详细,高手就不用见) 开始吧: 1.建立项目:打开VC++6.0,建立壹个基于对话框的MFC应用程序SCommTest(和我源代码壹致,等会你会方便壹点); 2.于项目中插入MSComm控件选择Project菜单下AddToProject子菜单中的ComponentsandControls…选项,于弹出的对话框中双击RegisteredActiveXControls项(稍等壹会,这个过程较慢),则所有注册过的ActiveX控件出当下列表框中。选择MicrosoftCommunicationsControl,version6.0,,单击Insert按钮将它插入到我们的Project中来,接受缺省的选项。(如果你于控件列表中见不到MicrosoftCommunicationsControl,version6.0,那可能是你于安装VC6时没有把ActiveX壹项选上,重新安装VC6,选上ActiveX就能够了),

Android源码下载方法详解

Android: Android源码下载方法详解 分类:Android平台 安卓源码下载地址:https://www.360docs.net/doc/001390714.html,/source/downloading.html 相信很多下载过内核的人都对这个很熟悉 git clone git://https://www.360docs.net/doc/001390714.html,/kernel/common.git kernel 但是这是在以前,现在如果这么执行的话,会显示如下内容 Initialized empty Git repository in /home/star/working/kernel/.git/ https://www.360docs.net/doc/001390714.html,[0: 149.20.4.77]: errno=Connection refused fatal: unable to connect a socket (Connection refused) 通过浏览器输入https://www.360docs.net/doc/001390714.html,/,发现该网站已经被重定向为 https://www.360docs.net/doc/001390714.html,/source/downloading.html 可以在该页面的最后发现内核的下载方法。 下面我们介绍一下Android源码下载的步骤。 工作环境: 操作系统:Ubuntu 10.04 或Ubuntu10.10 git程序:1.7.0.4 或1.7.1 转载请注明出处:https://www.360docs.net/doc/001390714.html,/pku_android 方法一: 1.1 初始化安装环境 参考网页https://www.360docs.net/doc/001390714.html,/source/initializing.html 主要要做的就是安装jdk和安装一些软件包 $ sudo apt-get install git-core gnupg flex bison gperf build-essential \ zip curl zlib1g-dev libc6-dev libncurses5-dev x11proto-core-dev \ libx11-dev libreadline6-dev libgl1-mesa-dev tofrodos python-markdown \ libxml2-utils 如果已经安装了,就不许要这步了 1.2 无论下载内核和源码,都需要进行如下操作 参考网页https://www.360docs.net/doc/001390714.html,/source/downloading.html $ mkdir ~/bin $ PATH=~/bin:$PATH $ curl https://https://www.360docs.net/doc/001390714.html,/dl/googlesource/git-repo/repo > ~/bin/repo 如果出现: repo init error: could not verify the tag 'v1.12.7',

串口调试助手VC++6.0程序

串口调试助手源程序 及编程详细过程 作者:龚建伟 2001.6.20 可以任意转载,但必须注明作者和说明来自https://www.360docs.net/doc/001390714.html,,不得作为商用 目次: 1.建立项目 2.在项目中插入MSComm控件 3.利用ClassWizard定义CMSComm类控制变量 4.在对话框中添加控件 5.添加串口事件消息处理函数OnComm() 6.打开和设置串口参数 7.发送数据 在众多网友的支持下,串口调试助手从2001年5月21日发布至今,短短一个月,在全国各地累计下载量近5000人次,在近200多个电子邮件中,20多人提供了使用测试意见,更有50多位朋友提出要串口调试助手的源代码,为了答谢谢朋友们的支持,公开推出我最初用VC控件MSComm编写串口通信程序的源代码,并写出详细的编程过程,姑且叫串口调试助手源程序V1.0或VC串口通讯源程序吧,我相信,如果你用VC编程,那么有了这个代码,就可以轻而易举地完成串口编程任务了。(也许本文过于详细,高手就不用看) 开始吧: 1.建立项目:打开VC++6.0,建立一个基于对话框的MFC应用程序SCommTest(与我源代码一致,等会你会方便一点); 2.在项目中插入MSComm控件选择Project菜单下Add To Project子菜单中的 Components and Controls…选项,在弹出的对话框中双击Registered ActiveX Controls项(稍等一会,这个过程较慢),则所有注册过的ActiveX控件出现在列表框中。选择Microsoft Communications Control, version 6.0,,单击Insert按钮将它插入到我们的Project中来,接受缺省的选项。(如果你在控件列表中看不到Microsoft Communications Control, version 6.0,

Android源代码结构分析

目录 一、源代码结构 (2) 第一层次目录 (2) bionic目录 (3) bootloader目录 (5) build目录 (7) dalvik目录 (9) development目录 (9) external目录 (13) frameworks目录 (19) Hardware (20) Out (22) Kernel (22) packages目录 (22) prebuilt目录 (27) SDK (28) system目录 (28) Vendor (32)

一、源代码结构 第一层次目录 Google提供的Android包含了原始Android的目标机代码,主机编译工具、仿真环境,代码包经过解压缩后,第一级别的目录和文件如下所示: . |-- Makefile (全局的Makefile) |-- bionic (Bionic含义为仿生,这里面是一些基础的库的源代码) |-- bootloader (引导加载器),我们的是bootable, |-- build (build目录中的内容不是目标所用的代码,而是编译和配置所需要的脚本和工具) |-- dalvik (JAVA虚拟机) |-- development (程序开发所需要的模板和工具) |-- external (目标机器使用的一些库) |-- frameworks (应用程序的框架层) |-- hardware (与硬件相关的库) |-- kernel (Linux2.6的源代码) |-- packages (Android的各种应用程序) |-- prebuilt (Android在各种平台下编译的预置脚本) |-- recovery (与目标的恢复功能相关) `-- system (Android的底层的一些库)

VBNET开发全功能串口调试助手

https://www.360docs.net/doc/001390714.html, 开发全功能串口调试助手(含完整工程) 小记:https://www.360docs.net/doc/001390714.html, 的串口通信用了很长时间了,也只用 Write 和Read 这样的方 法,以前都是用这种方式做上位机软件, 如此足矣。而前几天研究GSM 模块时对 串口返回的数据总是把握不好,参考开发板附送的例程,发现采用 SerialPort 的DataReceived 事件,可以实现中断触发式的数据接收。于是想到要自己做一 个串口调试助手,在实现基本功能的前提下增加一些方便自己调试的功能。 经过 断断续续的编写,就做成了下面这个小软件: 这个软件能够实现串口调试助手的全部功能,经过通信测试,数据接收性能 不亚于呼啸工作室的SComAssistant2.2,通过加大输入缓冲区,可以满足大量 数据接收。 https://www.360docs.net/doc/001390714.html, 的串口通信主要使用 VS 自带的SerialPort 控件,而不是早先的 MSComm 更具有兼容性,这也是很久以前就放弃 VB 改用.NET 的直接原因。该控 件的主要方法、属性如下(该数据来自 VS 的MSD 帮助库):

想要通过串口收发数据,就需要对串口进行配置,包括设置端口、波特率、数据格式(如COM端口、9600bps、8位数据位、无校验位、1位停止位)等属性,之后通过Open方法打开串口。打开串口可通过手动指定,也可以使用GetPortNames 方法获取计算机中存在的串口。如果打开出错,则可能是串口不存在或者已被占用。下面是相应代码: Private SubSerialPortOpen() On Error GoToErr If SerialPort.IsOpen = True ThenSerialPort.Close() '避免重复打开端 口 SerialPort.Ope n() LabelCOMStatus.Text ="串口已打开" Exit Sub Err: MsgBox(‘ 串口不存在或已被占用!" + vbNewLine + ErrorToString()) ' 出现错误,显示错误信息 En dSub 如果想要在串口中支持中文字符收发,则可在初始化时设置串口控件的编码: SerialPort.E ncodi ng = System.Text.E ncodi ng.Default 发送数据通过Write方法来完成,由于串口调试助手需要支持文本和16进制, 需要加入转换代码: Private SubButtonSendData_Click( ByVal sender AsSystem.Object, ByVal e AsSystem.EventArgs) Handles ButtonSendData.Click On Error GoToErr

Android USB 驱动分析

Android USB 驱动分析 一、USB驱动代码架构和使用 1、代码简介 USB驱动代码在/drivers/usb/gadget下,有三个文件:android.c, f_adb.c, f_mass_storage.c;g_android.ko 是由这三个文件编译而来,其中android.c 依赖于 f_adb.c 和 f_mass_storage.c(这两个文件之间无依赖关系)。 可在android.c中看到: static int __init android_bind_config(struct usb_configuration *c) { struct android_dev *dev = _android_dev; int ret; printk(KERN_DEBUG "android_bind_config\n"); ret = mass_storage_function_add(dev->cdev, c, dev->nluns); if (ret) return ret; return adb_function_add(dev->cdev, c); } 2、驱动使用 要使USB mass storage连接到主机: 打开/sys/devices/platform/usb_mass_storage/lun0/file文件,向 file文件写入一个存储 设备的路径,例如/dev/block/vold/179:0 (major:minor)路径; 这里的usb_mass_storage根据实际应用可以改的,由 platform_device_register函数的参数决 定。 例如: static struct platform_device fsg_platform_device = { .name = "usb_mass_storage", .id = -1, }; static void __init tegra_machine_init(void) { .... (void) platform_device_register(&fsg_platform_device); .... }

串口调试助手c开发

1.建立项目: 打开VC+ + 6.0,建立一个基于对话框的MFC应用程序SCommTest(与我 源代码一致,等会你会方便一点); 2.在项目中插入MSComm控件 选择Project菜单下Add To Project子菜单中的Componentsand Controls,选项,在弹出的对话框中双击Registered ActiveXControls项(稍等一会,这个过程较慢),则所有注册过的ActiveX控件出现在列表框中。选择Microsoft Communications Control,version6.0,,单击Insert 按钮将它插入到我们的Project 中来,接受缺省的选项。(如果你在控件列表中看不到Microsoft Communications Control, version 6.0,那可能是你在安装VC6时没有把ActiveX 一项选上,重新安装VC6,选上ActiveX就可以了),这时在ClassView 视窗中就可以看到CMSComm类了,(注意:此类在ClassWizard中看不到,重构clw文件也一样),并且在控件工具栏Controls中出现了电话图标(如图1所示),现在要做的是用鼠标将此图标拖到对话框中,程序运行后,这个图标是看不到的。3.利用ClassWizard定义CMSComm类控制对象 打开ClassWizard- >Member Viariables 选项卡,选择CSCommTestDlg^,为IDC_MSCOMM1添加控制变量:m_ctrlCom m,这时你可以看一看,在对话框头文件中自动加入了//{{AFX_INCLUDES()#include "mscomm.h" //}}AFX_INCLUDES (这时运行程序,如果有错,那就再从头开始)。 4 .在对话框中添加控件 向主对话框中添加两个编辑框,一个用于接收显示数据ID为 IDC_EDIT_RXDATA另一个用于输入发送数据,ID为IDC_EDIT_TXDAT A再添加一个按钮,功能是按一次就把发送编辑框中的内容发送一次,将其ID设为 IDC_BUTTON_MANUALSEND别忘记了将接收编辑框的Prop erties->Styles 中把Miltiline和Vertical Scroll属性选上,发送编辑框若你想输入多行文字,也可选上Miltiline。

Android 串口编程原理和实现方式附源码

提到串口编程,就不得不提到JNI,不得不提到JavaAPI中的文件描述符类:。下面我分别对JNI、以及串口的一些知识点和实现的源码进行分析说明。这里主要是参考了开源项目android-serialport-api。 串口编程需要了解的基本知识点:对于串口编程,我们只需对串口进行一系列的设置,然后打开串口,这些操作我们可以参考串口调试助手的源码进行学习。在Java中如果要实现串口的读写功能只需操作文件设备类:即可,其他的事都由驱动来完成不用多管!当然,你想了解,那就得看驱动代码了。这里并不打算对驱动进行说明,只初略阐述应用层的实现方式。 (一)JNI: 关于JNI的文章网上有很多,不再多做解释,想详细了解的朋友可以查看云中漫步的技术文章,写得很好,分析也很全面,那么在这篇拙文中我强调3点: 1、如何将编译好的SO文件打包到APK中?(方法很简单,直接在工程目录下新建文件夹libs/armeabi,将SO文件Copy到此目录即可) 2、命名要注意的地方?(在编译好的SO文件中,将文件重命名为:lib即可。其中是编译好后生成的文件) 3、MakeFile文件的编写(不用多说,可以直接参考package/apps目录下用到JNI的相关项目写法) 这是关键的代码: [cpp]view plaincopy

(二):

文件描述符类的实例用作与基础机器有关的某种结构的不透明句柄,该结构表示开放文件、开放套接字或者字节的另一个源或接收者。文件描述符的主要实际用途是创建一个包含该结构的或。这是API的描述,不太好理解,其实可简单的理解为:就是对一个文件进行读写。 (三)实现串口通信细节 1) 建工程:SerialDemo包名:org.winplus.serial,并在工程目录下新建jni和libs两个文件夹和一个org.winplus.serial.utils,如下图: 2) 新建一个类:SerialPortFinder,添加如下代码: [java]view plaincopy 1.package org.winplus.serial.utils; 2. 3.import java.io.File; 4.import java.io.; 5.import java.io.IOException; 6.import java.io.LineNumberReader; 7.import java.util.Iterator; 8.import java.util.Vector; 9. 10.import android.util.Log; 11. 12.public class SerialPortFinder { 13. 14.private static final String TAG = "SerialPort"; 15.

串口调试助手代码分析42

第5章串口调试助手代码分析 1、建立基于对话框的工程SCOMM 2、绘制界面,如下图: 接收区 串口组合框:IDC_COMBO_COMSELECT,m_Com 波特率组合框:IDC_COMBO_SPEED,m_Speed 停止位组合框:IDC_COMBO_STOPBITS,m_StopBits 数据位组合框:IDC_COMBO_DATABITS,m_DataBits 校验位组合框:IDC_COMBO_PARITY,m_Parity 十六进制显示(接收):IDC_CHECK_HEXRECIEVE,m_ctrlHexReceieve 接收编辑框:IDC_EDIT_RECIVE ,m_ReceiveData m_ctrlReceiveData Style:Vertical Scroll MultiLine 打开串口IDC_BUTTON_OPENPORT,m_ctrlOpenPort 串口开关标志图标IDC _STATIC_OPENOFF,m_ctrlIconOpenoff 数据文件保存路径IDC _EDIT_SA VEPATH,m_strCurPath 保存显示数据文件路径IDC _EDIT_SA VEPATH, m_ctrlSavePath 接收计数IDC_STATIC_RXCOUNT ,m_ctrlRXCOUNT 发送区 …。。。。。。。。。。。。。。 3、添加CSeraiPort类文件 将类文件SerialPort.h SerialPort.cpp 复制到工程所在文件夹中(选择改进

后的类),然后单击VC 6.0菜单Projrct -> Add to Projrct ->Files… ,再在打开的文件选择对话框中选择SerialPort.h 和SerialPort.cpp ,点击OK,就把类文件加入当前工程,并在SCOMMDlg.h 中加入头文件,#include "SerialPort.h",通过上述步骤就在当前工程中加入了CSeraiPort类。 4、完成串口消息处理函数OnCommunicatiom 在CserailPort 类中有多个串口事件可以响应。在一般串口编程中,只需要处理WM_COMM_RXCHAR消息就可以了,该类所有的消息均需要人工添加消息处理函数。我们将处理函数名定义为OnComm()。首先在SCOMMDlg.h 中添加串口字符接收消息WM_COMM_RXCHAR(串口接收缓冲区内有一个字符)响应函数的声明:如下图 然后,在SCOMMDlg.cpp文件中进行WM_COMM_RXCHAR消息映射: 如下图; 接着,在SCOMMDlg.cpp 文件中加入函数OnCommunication(WPARAM ch, LPARAM port)的实现,暂不添加代码。 LONG CSCOMMDlg::OnCommunication(WPARAM ch, LPARAM port) { return 0; } 以上步骤需要手工完成。 至此完成了程序的对话框模板,在工程中插入了串口操作类CserailPort类。5、添加串口初始化及关闭 程序中有两种方法大开串口,一是程序启动,调用OnInitDialog()函数,就可以打开串口,缺省的串口号为COM1,如果COM1不存在或占用,就会给出提示;另外,单击“打开串口”按钮也可以打开串口。 //在初始化中打开串口 BOOL CSCOMMDlg::OnInitDialog() { m_nBaud=9600;//波特率 m_nCom=1;//串口号 m_cParity='N';//奇偶校验

App工程结构搭建:几种常见Android代码架构分析

App工程结构搭建:几种常见Android代码架构分析 关于Android架构,因为手机的限制,目前我觉得也确实没什么大谈特谈的,但是从开发的角度,看到整齐的代码,优美的分层总是一种舒服的享受的。 从艺术的角度看,其实我们是在追求一种美。 本文先分析几个当今比较流行的android软件包,最后我们汲取其中觉得优秀的部分,搭建我们自己的通用android工程模板。 1. 微盘 微盘的架构比较简单,我把最基本,最主干的画了出来: 第一层:com.sina.VDisk:com.sina(公司域名)+app(应用程序名称) 。 第二层:各模块名称(主模块VDiskClient和实体模块entities)第三层:各模块下具体子包,实现类。 从图中我们能得出上述分析中一个最简单最经典的结构,一般在应用程序包下放一些全局的包或者类,如果有多个大的模块,可以分成多个包,其中包括一个主模块。 在主模块中定义基类,比如BaseActivity等,如果主模块下还有子模块,可以在主模块下建立子模块相应的包。说明一点,有的时候如果只有一个主模块,我们完全可以省略掉模

块这一层,就是BaseActivity.java及其子模块直接提至第二层。 在实体模块中,本应该定义且只定义相应的实体类,供全局调用(然而实际情况可能不是这样,后面会说到)。在微盘应用中,几乎所有的实体类是以xxx+info命名的,这种命名也是我赞成的一种命名,从语义上我觉得xxxModel.java这种命名更生动更真实,xxxModel给我一种太机械太死板的感觉,这点完全是个人观点,具体操作中以个人习惯为主。还有一点,在具体的xxxInfo,java中有很多实体类中是没有get/set的方法,而是直接使用public的字段名。这一点,我是推荐这种方式的,特别是在移动开发中,get/set方法很多时候是完全没有必要的,而且是有性能消耗的。当然如果需要对字段设置一定的控制,get/set方法也是可以酌情使用的。 2. 久忆日记 相比于微盘的工程结构,久忆日记的结构稍微复杂了一些。如下图: 1).第一层和前面微盘一样的. 2).第二层则没有模块分类,直接把需要的具体实现类都放在下面,主要日记的一些日记相关的Activity。 3).第二层的实体包命令为model包,里面不仅存放了实体类

串口调试助手C++开发

1.建立项目: 打开VC++6.0,建立一个基于对话框的MFC应用程序SCommTest(与我源代码一致,等会你会方便一点); 2.在项目中插入MSComm控件 选择Project菜单下Add To Project子菜单中的 Components and Controls…选项,在弹出的对话框中双击Registered ActiveX Controls项(稍等一会,这个过程较慢),则所有注册过的ActiveX 控件出现在列表框中。选择Microsoft Communications Control, version 6.0,,单击Insert按钮将它插入到我们的Project中来,接受缺省的选项。(如果你在控件列表中看不到Microsoft Communications Control, version 6.0,那可能是你在安装VC6时没有把ActiveX一项选上,重新安装VC6,选上ActiveX就可以了),这时在ClassView视窗中就可以看到CMSComm类了,(注意:此类在ClassWizard中看不到,重构clw文件也一样),并且在控件工具栏Controls中出现了电话图标(如图1所示),现在要做的是用鼠标将此图标拖到对话框中,程序运行后,这个图标是看不到的。

3.利用ClassWizard定义CMSComm类控制对象 打开ClassWizard->Member Viariables选项卡,选择CSCommTestDlg类,为IDC_MSCOMM1添加控制变量:m_ctrlComm,这时你可以看一看,在对话框头文件中自动加入了//{{AFX_INCLUDES() #include "mscomm.h" //}}AFX_INCLUDES (这时运行程序,如果有错,那就再从头开始)。 4.在对话框中添加控件 向主对话框中添加两个编辑框,一个用于接收显示数据ID为IDC_EDIT_RXDATA,另一个用于输入发送数据,ID为IDC_EDIT_TXDATA,再添加一个按钮,功能是按一次就把发送编辑框中的内容发送一次,将其ID设为IDC_BUTTON_MANUALSEND。别忘记了将接收编辑框的Properties->Styles中把Miltiline和Vertical Scroll属性选上,发送编辑框若你想输入多行文字,也可选上Miltiline。 再打开ClassWizard->Member Viariables选项卡,选择CSCommTestDlg 类,为IDC_EDIT_RXDATA添加CString变量m_strRXData,为

C++课程设计 串口调试助手

目录 【内容摘要】 (2) 【关键词】 (2) 1 开发语言及开发平台简介 (3) 1.1 开发语言 (3) 1.1.1 C语言 (3) 1.1.2 C++语言 (3) 1.2 开发平台 (4) 1.2.1 Microsoft Visual C++ (4) 1.2.2 C++ Builder (5) 2 软件开发过程 (6) 2.1 开发所需要的控件 (6) 2.1.1 按钮控件 (6) 2.1.2 文本控件 (6) 2.1.3 串口控件 (6) 2.1.4 选择控件 (7) 2.2 数据发送设计 (7) 2.3 数据接收设计 (9) 3 软件使用说明 (11) 4 软件测试 (13) 4.1 辅助工具 (13) 4.2 发送测试 (13) 4.3 接收测试 (13) 5 总结 (15) 致谢 (16) 参考文献 (17) 附录主要程序 (18) 串口发送程序 (18) 串口接收程序 (19) 【Abstract】 (21) 【Key Words】 (21)

串口调试助手设计 专业:电子科学与技术学号:XXXXXXXXXXX 学生姓名:X X X 指导老师姓名:X X X 【内容摘要】串口调试助手是串口调试相关工具,网络上有很多串口调试助手,界面不同,功能各异,使用的开发语言和开发平台也不相同。有的使用C语言开发,有的使用C++语言开发,还有的即使用C语言也使用C++语言;开发平台有的使用Visual C++,有的使用C++ Builder等。本软件使用C语言和C++语言,开发平台使用C++Builder软件。该串口调试助手串口调试助手版支持常用的110 ~ 256000bps波特率,能设置校验、数据位和停止位,能以ASCII码或十六进制接收或发送数据或字符(包括中文),能发送文本文件(*.txt 文本),可以任意设定自动发送周期,并能将接收数据保存成文本文件(*.txt),是做项目开发调试串口的好工具。 【关键词】串口;C++;C++ Builder;控件;测试;

最全的Android源码目录结构详解

最全的Android源码目录结构详解 Android 2.1 |-- Makefile |-- bionic (bionic C库) |-- bootable (启动引导相关代码) |-- build (存放系统编译规则及generic等基础开发包配置) |-- cts (Android兼容性测试套件标准) |-- dalvik (dalvik JAVA虚拟机) |-- development (应用程序开发相关) |-- external (android使用的一些开源的模组) |-- frameworks (核心框架——java及C++语言) |-- hardware (部分厂家开源的硬解适配层HAL代码) |-- out (编译完成后的代码输出与此目录) |-- packages (应用程序包) |-- prebuilt (x86和arm架构下预编译的一些资源) |-- sdk (sdk及模拟器) |-- system (底层文件系统库、应用及组件——C语言) `-- vendor (厂商定制代码) bionic 目录 |-- libc (C库) | |-- arch-arm (ARM架构,包含系统调用汇编实现) | |-- arch-x86 (x86架构,包含系统调用汇编实现) | |-- bionic (由C实现的功能,架构无关) | |-- docs (文档) | |-- include (头文件) | |-- inet (?inet相关,具体作用不明) | |-- kernel (Linux内核中的一些头文件) | |-- netbsd (?nesbsd系统相关,具体作用不明) | |-- private (?一些私有的头文件) | |-- stdio (stdio实现) | |-- stdlib (stdlib实现) | |-- string (string函数实现) | |-- tools (几个工具) | |-- tzcode (时区相关代码) | |-- unistd (unistd实现) | `-- zoneinfo (时区信息) |-- libdl (libdl实现,dl是动态链接,提供访问动态链接库的功能)|-- libm (libm数学库的实现,) | |-- alpha (apaha架构) | |-- amd64 (amd64架构) | |-- arm (arm架构) | |-- bsdsrc (?bsd的源码)

VB串口调试助手源代码

VB串口调试助手源代码 Dim OutputAscii As Boolean Dim InputString As String Dim OutputString As String '============================================================================== ======= ' 变量定义 '============================================================================== ======= Option Explicit ’强制显式声明 Dim ComSwitch As Boolean ’串口开关状态判断 Dim FileData As String ’要发送的文件暂存 Dim SendCount As Long ’发送数据字节计数器 Dim ReceiveCount As Long ’接收数据字节计数器 Dim InputSignal As String ’接收缓冲暂存 Dim OutputSignal As String ’发送数据暂存 Dim DisplaySwitch As Boolean ’显示开关 Dim ModeSend As Boolean ’发送方式判断 Dim Savetime As Single ’时间数据暂存延时用 Dim SaveTextPath As String ’保存文本路径 ' 网页超链接申明 Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long Private Sub CloseCom() '关闭串口 On Error GoTo Err If MSComm.PortOpen = True Then MSComm.PortOpen = False’先判断串口是否打开,如果打开则先关闭

基于MSComm控件的串口调试程序及源代码

这是龚建伟老师提供的一个基于MSComm控件的串口调试程序,下面给出了在Visual C++环境下详细的制作过程。附件的源代码是我根据这些步骤编写出来的,可以供大家参考哦! 目录: 1.建立项目 2.在项目中插入MSComm控件 3.利用ClassWizard定义CMSComm类控制变量 4.在对话框中添加控件 5.添加串口事件消息处理函数OnComm() 6.打开和设置串口参数 7.发送数据 8.发送十六进制字符 9.在接收框中以十六进制显示 10.如何设置自动发送 11.什么是VARIANT数据类型?如何使用VARIANT数据类型? 1.建立项目:打开VC++6.0,建立一个基于对话框的MFC应用程序SCommTest(与我源代码一致,等会你会方便一点); 2.在项目中插入MSComm控件选择Project菜单下Add To Project子菜单中的 Components and Controls…选项,在弹出的对话框中双击Registered ActiveX Controls项(稍等一会,这个过程较慢),则所有注册过的ActiveX控件出现在列表框中。选择Microsoft Communications Control, version 6.0,,单击Insert按钮将它插入到我们的Project中来,接受缺省的选项。(如果你在控件列表中看不到Microsoft Communications Control, version 6.0,那可能是你在安装VC6时没有把ActiveX一项选上,重新安装VC6,

选上ActiveX就可以了), 这时在ClassView视窗中就可以看到CMSComm类了,(注意:此类在ClassWizard中看不到,重构clw文件也一样),并且在控件工具栏Controls 中出现了电话图标(如图1所示),现在要做的是用鼠标将此图标拖到对话框中,程序运行后,这个图标是看不到的。 3.利用ClassWizard定义CMSComm类控制对象打开ClassWizard ->Member Viariables选项卡,选择CSCommTestDlg类,为IDC_MSCOMM1添加控制变量:m_ctrlComm,这时你可以看一看,在对话框头文件中自动加入了//{{AFX_INCLUDES() #include "mscomm.h" //}}AFX_INCLUDES (这时运行程序,如果有错,那就再从头开始)。 4.在对话框中添加控件 向主对话框中添加两个编辑框,一个用于接收显示数据ID为IDC_EDIT_RXDATA,另一个用于输入发送数据,ID为IDC_EDIT_TXDATA,再添加一个按钮,功能是按一次就把发送编辑框中的内容发送一次,将其ID设为IDC_BUTTON_MANUALSEND。别忘记了将接收编辑框的Properties->Styles中把Miltiline和Vertical Scroll属性选上,发送编辑框若你想输入多行文字,也可选上Miltiline。 再打开ClassWizard->Member Viariables选项卡,选择CSCommTestDlg 类, 为IDC_EDIT_RXDATA添加CString变量m_strRXData, 为IDC_EDIT_TXDATA添加CString变量m_strTXData。说明: m_strRXData和m_strTXData分别用来放入接收和发送的字符数据。 5.添加串口事件消息处理函数OnComm() 打开ClassWizard->Message Maps,选择类CSCommTestDlg,选择IDC_MSCOMM1,双击消息OnComm,将弹出的对话框中将函数名改为OnComm,(好记而已)OK。

相关文档
最新文档