DIY编程器网

 找回密码
 注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 1469|回复: 0
打印 上一主题 下一主题

[待整理] Labwindows 虚拟仪器高级应用-文本、文件类程序设计技术之:十六进制文本文件转换

[复制链接]
跳转到指定楼层
楼主
发表于 2014-10-12 07:21:51 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
1.2 十六进制文本文件转换
        1.2.1 十六进制文本文件转换设计方法
        在LabWindows/CVI 程序设计中,一些参数需要进行初始化,如字符串常量、动态链接库、静态链接库等。如字符串常量内容非常大,通常都会以文本文件的形式存储到磁盘上,动态链接库、静态链接库等也是如此。有没有办法,将这些文件都一同打包到可执行文件中,使其只包含一个可执行文件呢?将常量文本、各种库文件都打包到可执行文件中,便于文件的管理与操作。办法是有的,可以将这些文件导出为十六进制文本文件格式,并以C 语言的.h 头文件形式出现,在.c 源程序中通过#include 方式引用并在实现代码中调用,这些文件就可以通过隐式方式随可执行文件一起装载到内存中,调用简单而且方便。
         
        在本例程中,由于涉及大量数据的转换,而这些转换又是在一个for 循环语句中完成的,因此,程序执行期间不能及时响应外部的操作,如拖拽标题栏、点击面板按钮等,为了提高系统响应的及时性以及算法执行效率,采用多线程技术,将转换算法放入一个新线程中执行,即实现界面逻辑与算法逻辑的分离,效果会更好一些。
         
        一个采用了多线程技术的应用程序可以更好地利用系统资源。其主要优势在于充分利用了CPU 的空闲时间片,可以用尽可能少的时间来对用户的要求做出响应,使得进程的整体运行效率得到较大提高,同时增强了应用程序的灵活性。更为重要的是,由于同一进程的所有线程是共享同一内存的,所以不需要特殊的数据传送机制,不需要建立共享存储区或共享文件,从而使得不同任务之间的协调操作与运行、数据的交互、资源的分配等问题更加易于解决。
         
        对于本例程来说,界面逻辑虽然在算法执行过程中可以实现移动、按钮点击等操作,但如果在转换没有完成时进行第二次转换操作(如点击转换按钮),可能会出现逻辑错误,因此,最好在程序设计时考虑按钮的有效性或按钮自锁功能。
         
        1.2.2 十六进制文本文件转换程序设计
        (1)面板设计
        编写一个十六进制文本文件转换程序,可将各种文件如.txt、.dll、.lib、.obj 、.exe 等转换为十六进制文本格式,如“0x0A3, 0xB4, … ”等,并以.h 或.c 等格式存储,方便在程序运行时载入。点击转换按钮,弹出打开文件对话框,选择要转换的文件,之后会弹出保存对话框,提示保存为何种类型的文件,最后程序自动进行转换,在转换进度条中显示实际的转换进度,进度条到达满刻度时,转换完成。在编辑状态下双击Numeric Slide 控件,弹出Edit Numeric Slide 对话框,设置Data type 为int,Control mode 为Indicator ,点击Range Values… 按钮,弹出Edit Range Values 对话框,设置最小值Minimum 为0,如图1-5 所示,点击Show/Hide Parts… 按钮,弹出Show/Hide Parts 对话框,设置相关属性为No Markers 、No Ticks 等,如图1-6 所示。面板设计如图1-7 所示,面板中主
       

        图1-5 Edit Range Values 对话框要

       

        图1-6 Show/Hide Parts 对话框

       

        图1-7 十六进制文本文件转换面板

         

        表1-5 控件属性设置表
                               
                                        常量名

                       
                               
                                        控件类型

                       
                                                                        控件的主要属性
                       
                               
                                        PANEL

                       
                               
                                        Panel

                       
                                                                        标题:十六进制文本文件转换回调函数:panelCB
                       
                               
                                        PROGRESS

                       
                               
                                        Numeric Slide

                       
                                                                        标题:转换进度
                       
                               
                                        TRANSLATE

                       
                               
                                        Command Button

                       
                                                                        标题:转换回调函数:Translate
                       
         
        (2)程序源代码
        //头文件声明

        #include <ansi_c.h>

        #include <formatio.h>

        #include <utility.h>

        #include <cvirte.h>

        #include <userint.h>

        #include "十六进制文本文件转换.h"

        //全局静态变量

        static int BytesRead;

        static CmtThreadFunctionID ThreadID;

        static int panelHandle;

        static char *buffer;

        char SaveDir[MAX_PATHNAME_LEN];

        //线程回调函数声明
        int CVICALLBACK HextoText (void *functionData);
        //主函数
        int main (int argc, char *argv[])
        {
        if (InitCVIRTE (0, argv, 0) == 0)
        return -1;
        /* out of memory */
        if ((panelHandle = LoadPanel (0, " 十六进制文本文件转换.uir", PANEL)) < 0)
        return -1;
        DisplayPanel (panelHandle);
        RunUserInterface ();
        //释放资源
        free (buffer);
        DiscardPanel (panelHandle);
        return 0;
        }
        //面板回调函数
        int CVICALLBACK panelCB (int panel, int event, void *callbackData,
        int eventData1, int eventData2)
        {
        switch (event)
        {
        case EVENT_CLOSE:
        QuitUserInterface (0);
        break;
        }
        return 0;
        }
        //转换按钮
        int CVICALLBACK Translate (int panel, int control, int event,
        void *callbackData, int eventData1, int eventData2)
        {
        int SaveSel;
        int Present;
        ssize_t FileSize;
        int sel;
        char path[MAX_PATHNAME_LEN];
        int FileHandle;
        switch (event)
        {
        case EVENT_COMMIT:
        // 打开文件,获得文件信息
        sel = FileSelectPopup ("", "*.txt", "*.txt;*.dll;*.lib;*.obj;*.exe", " 打开", VAL_LOAD_BUTTON,
        0, 0, 1, 1, path);
        Present = GetFileInfo (path, &FileSize);
        // 保存为十六进制文本文件
        SaveSel = FileSelectPopup ("", "*.h", "*.h;*.c;*.txt", " 保存", VAL_SAVE_BUTTON, 0, 0, 1, 1,
        SaveDir);
        // 判断文件是否存在
        if ((sel > 0) && (Present == 1) && (SaveSel > 0))
        {
        buffer = malloc (FileSize * sizeof(char) + 1);buffer[0] =
        &#39;\0&#39;;
        // 打开文件,读取数据并关闭文件
        FileHandle = OpenFile (path, VAL_READ_ONLY, VAL_OPEN_AS_IS, VAL_BINARY);
        BytesRead = ReadFile (FileHandle, buffer, FileSize);
        CloseFile (FileHandle);
        // 创建线程
        CmtScheduleThreadPoolFunction
        (DEFAULT_THREAD_POOL_HANDLE,
        HextoText,
        NULL, &ThreadID);
        // 等待线程执行完毕
        CmtWaitForThreadPoolFunctionCompletion
        (DEFAULT_THREAD_POOL_HANDLE,
        ThreadID, OPT_TP_PROCESS_EVENTS_WHILE_WAITING);
        // 释放线程资源
        CmtReleaseThreadPoolFunctionID (DEFAULT_THREAD_POOL_HANDLE, ThreadID);
        }
        break;
        }
        return 0;
        }
        //线程回调函数—将十六进制数据转换为文本形式
        int CVICALLBACK HextoText (void *functionData)
        {
        int i;
        int file;
        int Bytes;
        unsigned char temp;
        unsigned char str[10];
        unsigned char *bin;
        //设置Numeric Slide 控件最大值,用作进度条
        SetCtrlAttribute (panelHandle, PANEL_PROGRESS, ATTR_MAX_VALUE, BytesRead);
        //转换为十六进制
        file = OpenFile (SaveDir, VAL_WRITE_ONLY, VAL_TRUNCATE, VAL_ASCII);
        bin = malloc (BytesRead * sizeof(char) * 6 + 1);
        bin[0] =
        &#39;\0&#39;;
        for (i = 0; i < BytesRead; i ++)
        {
        str[0] = &#39;0&#39;;
        str[1] = &#39;x&#39;;
        //高四位
                
        temp = (buffer >> 4) & 0x0F;
        if (temp >= 10)
        {
        str[2] = temp - 10 + &#39;A&#39;;
        }
        else
        {
        str[2] = temp + &#39;0&#39;;
        }
        //低四位
        temp = (buffer) & 0x0F;
        if (temp >= 10)
        {
        str[3] = temp - 10 + &#39;A&#39;;
        }
        else
        {
        str[3] = temp + &#39;0&#39;;
        }
        str[4] = ',';
        str[5] = &#39;\0&#39;;
        strcat (bin, str);
        //设置Numeric Slide 控件当前值
        SetCtrlVal (panelHandle, PANEL_PROGRESS, i);
        }
        //将数据保存到文件
        Bytes = WriteFile (file, bin, strlen(bin));
        //释放资源
        free (bin);
        CloseFile (file);return 0;
        }
         
        (3)程序注释
        ① CmtScheduleThreadPoolFunction 函数通知线程池创建一个新线程。如果线程池存在空闲线程,则被分配给该线程。如果没有空闲线程并且线程池中的线程没有达到线程池上限,线程池将创建一个新线程。当线程池达到线程上限且没有空闲线程,线程池将等待直到有空闲线程或有可用线程再分配给该线程。如果需要用到定时器回调函数,可以采用异步定时器(在自身线程中执行),不需要用定时器控件再开辟一个新线程。函数原型为:
        int CmtScheduleThreadPoolFunction (int poolHandle, ThreadFunctionPtr threadFunction, void *threadFunctionData, int *threadFunctionID);
         
        poolHandle :线程池句柄。可以采用DEFAULT_THREAD_POOL_HANDLE 常量,表示一个默认的线程池句柄。如果采用RT 应用,不能使用默认线程池句柄,由于默认线程池句柄即使在RTMain 函数退出后仍在运行,使系统运行不稳定,需要创建一个新线程池并且在退出RTMain 函数之前释放线程池句柄。
        threadFunction :线程函数。函数原型为:
        int CVICALLBACK ThreadFunction (void *functionData);
         
        *functionData :线程函数参数传递数据。在任何线程中,可以通过CmtGetThreadPoolFunction-Attribute 函数的ATTR_TP_FUNCTION_RETURN_VALUE 属性获得该线程所要传递的数据。
        *threadFunctionData :线程函数回调数据。不能传递局部变量地址或其他可能在函数执行过程中无效的地址。
        *threadFunctionID :标识线程函数的唯一ID 号。可以通过ID 号来获得线程函数的各种属性,包括线程函数的返回值,并可以将ID 号传递给CmtWaitForThreadPoolFunctionCompletion 函数,等待线程函数执行完毕进行其他操作。如果不需要此参数,输入NULL 。如果该参数值不为NULL, 必须用CmtReleaseThreadPoolFunctionID 函数释放ID 号。值得注意的是,如果该工程使用的版本低于LabWindows/CVI 2009 ,并在LabWindows/CVI 2009 以上的版本中重新编译时,必须在工程中包含头文件cvi2009compat.h 。
         
        ② CmtWaitForThreadPoolFunctionCompletion 函数等待指定线程函数执行完毕。可以使用CmtScheduleThreadPoolFunctionAdv 函数等待指定线程函数执行完毕。如果在线程中调用CmtWaitForThreadPoolFunctionCompletion 函数并且使用了ActiveX 函数,由于在线程初始化时使用了ActiveX 内部线程模式,可能造成两个线程之间的死锁,可以调用CA_InitActiveXThreadStyle-ForCurrentThread 函数为ActiveX 设置单独线程。函数原型为:
        int CmtWaitForThreadPoolFunctionCompletion (int poolHandle, int threadFunctionID, unsigned int options);
         
        options:选项参数。OPT_TP_PROCESS_EVENTS_WHILE_WAITING 指当等待线程执行期间,线程可以响应事件;当参数为0 时指等待线程执行期间,线程不能响应事件。任何线程中所创建的面板或对话框窗口在没有被释放以前,一定会响应一些事件。如果此时线程不能响应事件,可能导致系统“挂起”。为了避免这种情况的产生,应当使用OPT_TP_PROCESS_EVENTS_WHILE_ WAITING 参数来等待响应发送消息事件、显示面板事件及对话框事件。
         
        ③ CmtReleaseThreadPoolFunctionID 函数释放被CmtScheduleThreadPoolFunction 函数或CmtScheduleThreadPoolFunctionAdv 函数创建的线程ID 号,如果 CmtScheduleThreadPoolFunction 函数或CmtScheduleThreadPoolFunctionAdv 函数的threadFunctionID 参数值设置为NULL,系统将自动在线程调用执行完毕之后释放线程ID,可以不必调用此函数。函数不会中断一个将要执行或正在执行的线程函数。调用CmtDiscardThreadPool 函数将自动释放属于指定线程池的任何线程ID 号。函数原型为:
        int CmtReleaseThreadPoolFunctionID (int poolHandle, int threadFunctionID);
         
        ④ 不使用多线程技术的程序处理方法如果不使用多线程技术,只需要将Translate 回调函数中的CmtScheduleThreadPoolFunction 、CmtWaitForThreadPoolFunctionCompletion 和CmtRelease- ThreadPoolFunctionID 函数删除,直接调用HextoText 函数,但此函数需要一个空指针类型数据,可以借用Translate 中的callbackData 参数。采用这种技术能显著降低CPU 的使用率,在系统资源有限的情况下是不错的解决方案,其实现代码如下:
         
        int CVICALLBACK Translate (int panel, int control, int event, void *callbackData, int eventData1, int eventData2)
        {  int SaveSel;  int Present; ssize_t FileSize; int sel;
         char path[MAX_PATHNAME_LEN];
         int FileHandle;
         switch (event)
        {
        case EVENT_COMMIT:
         // 打开文件,获得文件信息
         sel = FileSelectPopup ("", "*.txt", "*.txt;*.dll;*.lib;*.obj;*.exe", " 打开", VAL_LOAD_BUTTON, 0, 0, 1, 1, path);
         Present = GetFileInfo (path, &FileSize);
         // 保存为十六进制文本文件
        SaveSel = FileSelectPopup ("", "*.h", "*.h;*.c;*.txt", " 保存", VAL_SAVE_BUTTON, 0, 0, 1, 1, SaveDir);
         // 判断文件是否存在
        if ((sel > 0) && (Present == 1) && (SaveSel > 0))
         {
        buffer = malloc (FileSize * sizeof(char) + 1);
          buffer[0] = &#39;\0&#39;;
          // 打开文件,读取数据并关闭文件
          FileHandle = OpenFile (path, VAL_READ_ONLY, VAL_OPEN_AS_IS, VAL_BINARY);
        BytesRead = ReadFile (FileHandle, buffer, FileSize);
          CloseFile (FileHandle);
          // 不使用多线程技术
          HextoText (callbackData);
        }
         break;
         }
         return 0;
        }
         
        在HextoText 函数中添加SetSleepPolicy 函数,设置系统的Sleep 策略,使系统不进入Sleep 状态,以加快算法执行速度,提高算法效率,添加ProcessSystemEvents 函数,使系统能及时响应鼠标事件。算法只需要进行少量代码修改,就能完成与多线程方式类似的操作。HextoText 函数实现代码修改如下:
         
        int CVICALLBACK HextoText (void *functionData)
        {
        int i;      
         int file;
         int Bytes;
         unsigned char temp;
        unsigned char str[10];
        unsigned char *bin;
        //设置Numeric Slide 控件最大值,用作进度条
        SetCtrlAttribute (panelHandle, PANEL_PROGRESS, ATTR_MAX_VALUE, BytesRead);
        //转换为十六进制
        file = OpenFile (SaveDir, VAL_WRITE_ONLY, VAL_TRUNCATE, VAL_ASCII);
        bin = malloc (BytesRead * sizeof(char) * 6 + 1);  bin[0] = &#39;\0&#39;; for (i = 0; i < BytesRead; i ++) {
        str[0] = &#39;0&#39;; str[1] = &#39;x&#39;; //高四位temp = (buffer >> 4) & 0x0F; if (temp >= 10){ str[2] = temp - 10 + &#39;A&#39;;
        }
        else
        {
         
         str[2] = temp + &#39;0&#39;; } //低四位temp = (buffer) & 0x0F;if (temp >= 10){
        str[3] = temp - 10 + &#39;A&#39;;
        }
        else
        {
         
         str[3] = temp + &#39;0&#39;; } str[4] = ','; str[5] = &#39;\0&#39;; strcat (bin, str); //设置Numeric Slide 控件当前值SetCtrlVal (panelHandle, PANEL_PROGRESS, i);//处理面板事件SetSleepPolicy (VAL_SLEEP_NONE); ProcessSystemEvents ();
         } //将数据保存到文件Bytes = WriteFile (file, bin, strlen(bin)); //释放资源 free (bin);  CloseFile (file);  return 0;
        }
         
        (4)运行效果图
        点击工具栏中的Debug Project 按钮,程序开始运行,其效果如图1-8 所示。
       

        图1-8 运行效果图
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|文字版|手机版|DIY编程器网 ( 桂ICP备14005565号-1 )

GMT+8, 2025-8-1 20:14 , 耗时 0.119534 秒, 19 个查询请求 , Gzip 开启.

各位嘉宾言论仅代表个人观点,非属DIY编程器网立场。

桂公网安备 45031202000115号

DIY编程器群(超员):41210778 DIY编程器

DIY编程器群1(满员):3044634 DIY编程器1

diy编程器群2:551025008 diy编程器群2

QQ:28000622;Email:libyoufer@sina.com

本站由桂林市临桂区技兴电子商务经营部独家赞助。旨在技术交流,请自觉遵守国家法律法规,一旦发现将做封号删号处理。

快速回复 返回顶部 返回列表