返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >UEFI开发基础HII代码示例
  • 351
分享到

UEFI开发基础HII代码示例

2024-04-02 19:04:59 351人浏览 独家记忆
摘要

目录代码示例模块fORMsetformsubtitleoneofstringnumerictextcheckboxGotolabel代码示例 代码 https://gite

代码示例

代码 https://gitee.com/jiangwei0512/edk2-beni

模块

BeniPkg\DynamicCommand\SetupDynamicCommand\SetupDynamicCommand.inf。

这里通过一个命令setup来打开图形界面。图形界面的form在Page.vfr中,还有若干的uni文件存放字符串,并通过如下的代码来初始化:

EFI_HII_HANDLE
InitializeHiiPackage (
  IN  EFI_HANDLE                    ImageHandle
  )
{
  EFI_STATUS                        Status;
  EFI_HII_PACKAGE_LIST_HEADER       *PackageList;
  EFI_HII_HANDLE                    HiiHandle;
  //
  // Retrieve HII package list from ImageHandle.
  //
  Status = gBS->OpenProtocol (
                  ImageHandle,
                  &gEfiHiiPackageListProtocolGuid,
                  (VOID **)&PackageList,
                  ImageHandle,
                  NULL,
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
                  );
  if (EFI_ERROR (Status)) {
    return NULL;
  }
  //
  // Publish HII package list to HII Database.
  //
  Status = gHiiDatabase->NewPackageList (
                           gHiiDatabase,
                           PackageList,
                           NULL,
                           &HiiHandle
                           );
  if (EFI_ERROR (Status)) {
    return NULL;
  }
  return HiiHandle;
}

这里使用了将资源放到二进制中的方式。然后通过如下的代码来显示图形:

VOID
DisplayPage (
  VOID
  )
{
  EFI_STATUS                   Status;
  EFI_BROWSER_ACTioN_REQUEST   ActionRequest;
  Status        = EFI_UNSUPPORTED;
  ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
  Status = gFormBrowser2->SendForm (
                            gFormBrowser2,
                            &mSetupHiiHandle,
                            1,
                            &mFrontPageGuid,
                            0,
                            NULL,
                            &ActionRequest
                            );
  if (EFI_ERROR (Status)) {
    DEBUG ((EFI_D_ERROR, "[BENI]SendForm failed. - %r\n", Status));
  }
}

formset

一开始使用的Page.vfr文件内容:

// {76B732B8-B777-4ECF-A84E-7A8CA2484555}
#define FORMSET_GUID        { 0x76b732b8, 0xb777, 0x4ecf, 0xa8, 0x4e, 0x7a, 0x8c, 0xa2, 0x48, 0x45, 0x55 }
formset
  guid      = BENI_FORMSET_GUID,
  title     = STRING_TOKEN(STR_PAGE_TITLE),
  help      = STRING_TOKEN(STR_EMPTY_STRING),
  classguid = BENI_FORMSET_GUID,
endformset;

form

只有一个formset,此时什么也不会显示出来,还需要在里面加内容,首先是一个form:

// {76B732B8-B777-4ECF-A84E-7A8CA2484555}
#define BENI_FORMSET_GUID   { 0x76b732b8, 0xb777, 0x4ecf, 0xa8, 0x4e, 0x7a, 0x8c, 0xa2, 0x48, 0x45, 0x55 }
#define FRONT_PAGE_FORM_ID  0x1000
formset
  guid      = BENI_FORMSET_GUID,
  title     = STRING_TOKEN(STR_PAGE_TITLE_FORMSET),
  help      = STRING_TOKEN(STR_EMPTY_STRING),
  classguid = BENI_FORMSET_GUID,
  form
    formid  = FRONT_PAGE_FORM_ID,
    title   = STRING_TOKEN(STR_PAGE_TITLE_FORM);
  endform;
endformset;

此时得到的结果:

标题来自STR_PAGE_TITLE_FORM,而Esc=ExitSendForm()自己生成的。

subtitle

之后就可以往form中添加内容。首先增加一个静态的字符串:

  form
    formid  = FRONT_PAGE_FORM_ID,
    title   = STRING_TOKEN(STR_PAGE_TITLE_FORM);
    subtitle text = STRING_TOKEN(STR_PAGE_STATIC_TEXT);
  endform;

得到的结果:

可以看到SendForm()自己还生成了一个↑↓=Move Highlight

oneof

然后增加选择框(checkbox)并伴有变量,如下所示:

  efivarstore BENI_SETUP_DATA,
    attribute = 0x2, // EFI_VARIABLE_BOOTSERVICE_ACCESS
    name  = BeniSetupData,
    guid  = BENI_FORMSET_GUID;
  form
    formid  = FRONT_PAGE_FORM_ID,
    title   = STRING_TOKEN(STR_PAGE_TITLE_FORM);
    subtitle text = STRING_TOKEN(STR_PAGE_STATIC_TEXT);
    oneof varid = BeniSetupData.Data1,
      prompt      = STRING_TOKEN(STR_SELECT_DATA_1_PROMPT),
      help        = STRING_TOKEN(STR_SELECT_DATA_1_HELP),
      flags       = NUMERIC_SIZE_1 | INTERACTIVE | RESET_REQUIRED,
      option text = STRING_TOKEN(STR_SELECT_DATA_0), value = 0, flags = DEFAULT;
      option text = STRING_TOKEN(STR_SELECT_DATA_1), value = 1, flags = 0;
    endoneof;
    oneof varid = BeniSetupData.Data2,
      prompt      = STRING_TOKEN(STR_SELECT_DATA_2_PROMPT),
      help        = STRING_TOKEN(STR_SELECT_DATA_2_HELP),
      flags       = NUMERIC_SIZE_1 | INTERACTIVE | RESET_REQUIRED,
      option text = STRING_TOKEN(STR_SELECT_DATA_0), value = 0, flags = DEFAULT;
      option text = STRING_TOKEN(STR_SELECT_DATA_1), value = 1, flags = 0;
    endoneof;
  endform;

对应的变量结构体:

//
// This is used in name of efivarstore.
//
#define BENI_SETUP_DATA_VAR_NAME    L"BeniSetupData"
typedef struct {
  UINT8    Data1;
  UINT8    Data2;
  UINT8    Rsvd1[2];
} BENI_SETUP_DATA;

显示结果如下:

这里可以修改值,并且保存,但是因为后端没有代码实现,所以会报错:

因此还需要增加后端的代码,这主要包含几个部分:变量的初始化,EFI_HII_CONFIG_ACCESS_PROTOCOL的实现和安装。

这里首先初始化vfr中对应的变量:

EFI_STATUS
PrepareData (
  VOID
  )
{
  EFI_STATUS         Status;
  BENI_SETUP_DATA    *Data;
  UINTN              DataSize;
  Status    = EFI_UNSUPPORTED;
  Data      = NULL;
  DataSize  = sizeof (BENI_SETUP_DATA);
  Data = AllocateZeroPool (DataSize);
  if (NULL == Data) {
    DEBUG ((EFI_D_ERROR, "[BENI]%a %d Out of memory\n", __FUNCTION__, __LINE__));
    return EFI_OUT_OF_RESOURCES;
  }
  Status = gRT->GetVariable (
                  BENI_SETUP_DATA_VAR_NAME,
                  &gBeniSetupFormSetGuid,
                  NULL,
                  &DataSize,
                  Data
                  );
  if (EFI_ERROR (Status)) {
    if (EFI_NOT_FOUND == Status) {
      DEBUG ((EFI_D_ERROR, "[BENI]Initialize Setup data\n"));
      Data->Data1 = 1;
      Data->Data2 = 1;
      DataSize    = sizeof (BENI_SETUP_DATA);
      Status = gRT->SetVariable (
                    BENI_SETUP_DATA_VAR_NAME,
                    &gBeniSetupFormSetGuid,
                    EFI_VARIABLE_BOOTSERVICE_ACCESS,
                    DataSize,
                    Data
                    );
      DEBUG ((EFI_D_ERROR, "[BENI]Status: - %r\n", Status));
    }
  }
  return Status;
}

这个本身意义不大,就是初始化和设置了一个变量而已,变量的值是1(所以显示的不再是Zero,而是One),这在界面中也会体现出来。然后就是安装EFI_HII_CONFIG_ACCESS_PROTOCOL:

  mPrivateData->ConfigAccess.ExtractConfig  = ExtractConfig;
  mPrivateData->ConfigAccess.RouteConfig    = RouteConfig;
  mPrivateData->ConfigAccess.Callback       = DriverCallback;
  //
  // Publish sample formset.
  //
  Status = gBS->InstallMultipleProtocolInterfaces (
                  &mPrivateData->DriverHandle,
                  &gEfiDevicePathProtocolGuid,
                  &mHiiVendorDevicePath,
                  &gEfiHiiConfigAccessProtocolGuid,
                  &mPrivateData->ConfigAccess,
                  NULL
                  );

这里的DriverCallback()等函数可以根据实际情况来实现,目前只是增加了打印信息而已,在操作上述的选择框时会被调用并输出信息。

string

string是一个可编辑的字符串,编辑之后可以保存到变量,下面是一个示例:

    string varid = BeniSetupData.DriverDescriptionData,
      questionid = PAGE_DESCRIPTION_ID,
      prompt     = STRING_TOKEN(STR_STRING_DESC_PROMPT),
      help       = STRING_TOKEN(STR_STRING_HELPER),
      flags      = INTERACTIVE,
      minsize    = 6,
      maxsize    = 30,
    endstring;

DriverDescriptionData是变量BeniSetupData的成员,它也可以预先初始化(本例中初始化成“Hello World”),PAGE_DESCRIPTION_ID可以在EFI_HII_CONFIG_ACCESS_PROTOCOLCallback()中定位,此外还有一些帮助信息、大小和操作限制等等配置。

下面是显示结果:

numeric

没什么好说的,就是数字:

    numeric varid   = BeniSetupData.Id,
            prompt  = STRING_TOKEN(STR_NUMERIC_ID_PROMPT),
            help    = STRING_TOKEN(STR_NUMERIC_ID_HELPER),
            minimum = 0,
            maximum = 1024,
    endnumeric;

下面是显示的结果:

跟string类似,只不过只能输入数字,通过flag的配置,可以选择使用十进制还是十六进制。

text

跟subtitle不同的是,text可以被选中,下面是一个例子:

    text
      help   = STRING_TOKEN(STR_TEXT_PROMPT),
      text   = STRING_TOKEN(STR_TEXT_HELPER),
      flags  = INTERACTIVE,
      key    = PAGE_TEXT_ID;

PAGE_TEXT_IDEFI_HII_CONFIG_ACCESS_PROTOCOLCallback()中使用:

EFI_STATUS
EFIapi
DriverCallback (
  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL    *This,
  IN  EFI_BROWSER_ACTION                      Action,
  IN  EFI_QUESTION_ID                         QuestionId,
  IN  UINT8                                   Type,
  IN  EFI_IFR_TYPE_VALUE                      *Value,
  OUT EFI_BROWSER_ACTION_REQUEST              *ActionRequest
  )
{
  BENI_MODULE_START
  if (Action == EFI_BROWSER_ACTION_CHANGING) {
    switch (QuestionId) {
      case PAGE_TEXT_ID:
        DEBUG ((DEBUG_ERROR, "%a %d PAGE_TEXT_ID\n", __FUNCTION__, __LINE__));
        break;
      default:
        break;
    }
  } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
    switch (QuestionId) {
      case PAGE_TEXT_ID:
        DEBUG ((DEBUG_ERROR, "%a %d PAGE_TEXT_ID\n", __FUNCTION__, __LINE__));
        break;
      default:
        break;
    }
  }
  BENI_MODULE_END
  return EFI_SUCCESS;
}

显示如下:

可以看到text那一行可以被选中,点击之后可以看到打印信息:

[BENI]DriverCallback start...
DriverCallback 138 PAGE_TEXT_ID
[BENI]DriverCallback end...
[BENI]DriverCallback start...
DriverCallback 146 PAGE_TEXT_ID
[BENI]DriverCallback end...

之所以能够操作这一行,原始主要在于flags = INTERACTIVE,,这样就会创建一个EFI_IFR_ACTION的操作码,相当于植入了一个可操作的动作。

checkbox

勾选框,只有TRUE和FALSE,或者0和1两个值。下面是一个示例:

    grayoutif ideqval BeniSetupData.Disabled == 1;
      text
        help   = STRING_TOKEN(STR_TEXT_PROMPT),
        text   = STRING_TOKEN(STR_TEXT_HELPER),
        flags  = INTERACTIVE,
        key    = PAGE_TEXT_ID;
    endif;
    checkbox varid   = BeniSetupData.Disabled,
             prompt   = STRING_TOKEN(STR_CHECKBOXK_PROMPT),
             help     = STRING_TOKEN(STR_CHECKBOXK_HELPER),
             flags    = CHECKBOX_DEFAULT,
    endcheckbox;

这里还使用了grayoutif,选中之后之前测试用的text会变灰,如下所示:

goto

用于跳转到另外的界面:

    goto PAGE_FORM_ID_2,
      prompt  = STRING_TOKEN(STR_GOTO_PROMPT),
      help    = STRING_TOKEN(STR_GOTO_HELPER);
  endform;
  form
    formid  = PAGE_FORM_ID_2,
    title   = STRING_TOKEN(STR_PAGE_TITLE_FORM_2);
    subtitle text = STRING_TOKEN(STR_PAGE_NETX_PAGE);
  endform;

显示的结果:

label

label相当于一个VFR中的一个占位符,本身不会产生可显示的内容,而是需要通过代码动态的增加显示内容,具体如何增加,就是使用之前介绍的HiiCreateXXX()函数在增加form组件。下面是label的示例:

#define LABEL_START                 0x1004
#define LABEL_END                   0x1005

  form
    formid  = PAGE_FORM_ID_2,
    title   = STRING_TOKEN(STR_PAGE_TITLE_FORM_2);

    subtitle text = STRING_TOKEN(STR_PAGE_NETX_PAGE);
    subtitle text = STRING_TOKEN(STR_EMPTY_STRING);

    label LABEL_START;
    label LABEL_END;

  endform;

可以看到这里只是增加了两个label而已,真正的操作还是在代码中:


VOID
CustomizePage (
  IN  EFI_HII_HANDLE                HiiHandle,
  IN  VOID                          *StartOpCodeHandle
  )
{
  //
  // Add OpCode here.
  //
  HiiCreateSubTitleOpCode (StartOpCodeHandle, STRING_TOKEN (STR_TEXT_IN_CODE), 0, 0, 0);
}

VOID
UpdatePageForm (
  VOID
  )
{
  VOID                        *StartOpCodeHandle;
  VOID                        *EndOpCodeHandle;
  EFI_IFR_GUID_LABEL          *StartGuidLabel;
  EFI_IFR_GUID_LABEL          *EndGuidLabel;
  //
  // Allocate space for creation of UpdateData Buffer
  //
  StartOpCodeHandle = HiiAllocateOpCodeHandle ();
  ASSERT (StartOpCodeHandle != NULL);
  EndOpCodeHandle = HiiAllocateOpCodeHandle ();
  ASSERT (EndOpCodeHandle != NULL);
  //
  // Create Hii Extend Label OpCode as the start opcode
  //
  StartGuidLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
  StartGuidLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
  StartGuidLabel->Number       = LABEL_START;
  //
  // Create Hii Extend Label OpCode as the end opcode
  //
  EndGuidLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
  EndGuidLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
  EndGuidLabel->Number       = LABEL_END;
  CustomizePage (
    mPrivateData->SetupHiiHandle,
    StartOpCodeHandle
    );
  HiiUpdateForm (
    mPrivateData->SetupHiiHandle,
    &gBeniSetupFormSetGuid,
    PAGE_FORM_ID_2,
    StartOpCodeHandle,
    EndOpCodeHandle
    );
  return;
}

得到的结果如下,红色部分就是通过代码生成的:

以上就是UEFI开发基础HII代码示例的详细内容,更多关于UEFI开发HII代码的资料请关注编程网其它相关文章!

--结束END--

本文标题: UEFI开发基础HII代码示例

本文链接: https://lsjlt.com/news/150617.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • UEFI开发基础HII代码示例
    目录代码示例模块formsetformsubtitleoneofstringnumerictextcheckboxgotolabel代码示例 代码 https://gite...
    99+
    2024-04-02
  • UEFI开发基础HII代码实例分析
    这篇文章主要介绍“UEFI开发基础HII代码实例分析”,在日常操作中,相信很多人在UEFI开发基础HII代码实例分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”UEFI开发基础HII代码实例分析”的疑惑有所...
    99+
    2023-06-30
  • UEFI开发基础汇编代码的使用
    UEFI中使用汇编代码 EDK代码中包含一部分汇编代码,目前支持的有.S、.asm和.nasm格式的汇编(第一个是AT&T汇编,后两个是Intel汇编,只是使用的汇编样式稍有...
    99+
    2024-04-02
  • UEFI开发基础汇编代码如何使用
    这篇文章主要讲解了“UEFI开发基础汇编代码如何使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“UEFI开发基础汇编代码如何使用”吧!UEFI中使用汇编代码EDK代码中包含一部分汇编代码,...
    99+
    2023-06-30
  • Ruby基础代码的示例分析
    Ruby基础代码的示例分析,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。Ruby语言的学习和其他编程语言一样,首先要从基础开始。在这里我们为大家介绍了一下Ruby基础代码中...
    99+
    2023-06-17
  • UEFI开发实战用户交互界面基础说明
    目录前言启动UiApp模块字体字符串UI Entry前言 本文以vUDK2017: https://github.com/tianocore/edk2.git Tag vUDK201...
    99+
    2024-04-02
  • Xamarin图表开发基础的示例分析
    这篇文章主要介绍Xamarin图表开发基础的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!在Xamarin图表开发中,最常用的框架是OxyPlot和Microcharts。其中,OxyOPlot提供多种多样的...
    99+
    2023-06-04
  • javascript数据类型基础示例代码分析
    这篇文章主要讲解了“javascript数据类型基础示例代码分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“javascript数据类型基础示例代码分析”吧!js中的输入输出语句方法说明归...
    99+
    2023-06-29
  • Java开发基础日期类的示例分析
    这篇文章主要为大家展示了“Java开发基础日期类的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java开发基础日期类的示例分析”这篇文章吧。一、日期工具类package co...
    99+
    2023-05-31
    java
  • Rust Atomics and Locks并发基础实例代码分析
    本文小编为大家详细介绍“Rust Atomics and Locks并发基础实例代码分析”,内容详细,步骤清晰,细节处理妥当,希望这篇“Rust Atomics and Locks...
    99+
    2023-07-05
  • WPF实现基础控件之托盘的示例代码
    WPF 基础控件之托盘 框架使用大于等于.NET40。 Visual Studio 2022。 项目使用 MIT 开源许可协议。 新建NotifyIcon自定义控...
    99+
    2022-11-13
    WPF实现托盘控件 WPF托盘
  • Web前端开发css基础样式的示例分析
    小编给大家分享一下Web前端开发css基础样式的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!颜色和单位的使用 颜色用颜...
    99+
    2024-04-02
  • Android开发基础使用ProgressBar加载进度条示例
    目录前言使用方法总结前言 之前我们用过WebView类,打开网页时就会出现加载网页的情况,为了让我们直观的感受到网页加载到什么程度而不是白白干等着空白页,于是加载进度条就是一个很好...
    99+
    2023-02-05
    Android ProgressBar加载进度条 Android ProgressBar
  • python开发App基础操作API使用示例过程
    目录手机控件查看工具uiautomatorviewer工具简介如何使用 APP元素定位操作通过id定位通过class定位通过xpath定位WebDriverWait 显示等...
    99+
    2024-04-02
  • PHP开发框架laravel代码提示示例解析
    public function getTable() { return $this->table Str::snake(Str::pluralStudly(class_bas...
    99+
    2024-04-02
  • web开发中Tab导航的示例代码
    这篇文章主要介绍web开发中Tab导航的示例代码,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完! 在网页中应用选项卡可以使网页显得更紧凑,结合AJAX技术可以使页面在有限的空间内展现...
    99+
    2024-04-02
  • Android开发之ListView、GridView 详解及示例代码
        ListView与GridView是Android开发中的常用控件,它们和Adapter配合使用能够实现很多界面效果。下面分别以实例说明L...
    99+
    2022-06-06
    示例 listview android开发 gridview Android
  • Android开发使用WebView打造webapp示例代码
    目录前言代码如下前言 博主最近想做一款app,因为内容已经有了,故想到了使用WebView来做 ,现将代码贴出如下,供有同样需求的人参考,少走弯路 代码如下 public ...
    99+
    2024-04-02
  • Python初学者必须了解的五个基础代码示例
    Python初学者必知的5个入门代码示例 Python是一种简洁而强大的编程语言,适合初学者入门。在学习Python的过程中,掌握几个基本的入门代码示例对于建立基础知识和提高编程能力非常重要。下面给出了5个初学者必知的入门代码示...
    99+
    2024-01-13
    变量 循环 条件判断
  • Android开发基础实现最简单的视频播放示例
    目录正篇使用方法最终效果展示总结正篇 视频播放是很平常的一件事情,但如何在APP中实现呢,其实蛮简单的,方法也很多,但作为基础的就是使用VideoView了,下面我们来看看如何使...
    99+
    2023-02-05
    Android开发简单视频播放 Android 视频播放
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作