大家好,欢迎来到IT知识分享网。
一、VFR、HFR简介
VFR(Visual Forms Representation,可视化窗体描述)是一种用户接口组件,在UEFI中,用户接口组件主要有4中:Font(字体)、Image(图像)、Form(窗体)和String(字符串)。其结构图如下:
String是由UNI文件提供的,Forms由VFR文件提供的。
下面介绍几个UEFI图像显示开发中常用的概念:
HII(Human Interface Infrastructure,人机接口基础架构)是UEFI的一个关键组件,它提供了一套标准化的API和工具,用于创建、管理和显示UEFI图形用户界面。HII数据库主要提供用户安装、卸载以及使用各种字符串、字体和图片等资源的接口。
Forms Browser在固件中充当用户界面管理者的角色,它允许用户与UEFI固件的用户界面进行交互。它负责显示信息和收集输入、输出信息,并将这些信息呈现给用户。
驱动程序和应用程序将元素(如字体、字符串、图像和表单)安装到HII数据库中,该数据库充当整个平台的中央存储库。Forms Browser使用这些元素在显示设备上呈现用户界面,并通过HID设备从用户接收信息。之后,用户在Form Browser所作的修改将保存在其他地方,存储的控制权在Driver,由Driver自己决定。
Hii Database由Packagelist组成,packagelist有一个头部,包含多个package,package由各种类型的二进制文件组成,例如字体、字符串、图像、表单等。
二、VFR文件的简单使用
1、修改FrontPageStings.uni与FrontPageVfr.Vfr
在UEFI开发中,FrontPageStrings.uni文件是一个包含字符串资源的文件,用于UEFI界面的本地化。FrontPageVfr.Vfr文件,用于定义UEFI用户界面的元素。
添加字符串资源到MdeModulePkg/Application/UiApp/FrontPageStrings.uni
//Add CSDN UI resources #string STR_CSDN_BANNER_LEFT #language en-US "Csdn Bannder Left" //将字符串“Csdn Bannder Left”用STR_BANNER_LEFT表示,语言为美国英语 #string STR_CSDN_BANNER_RIGHT #language en-US "Csdn Bannder Right" #string STR_CSDN_STRING #language en-US "CsdnText" #language fr-FR "CsdnText" #string STR_CSDN_STRING_HELP #language en-US "CsdnText the current setting." #language fr-FR "CsdnText the current setting." #string STR_CSDN_RADIO_STRING #language en-US "CsdnRdioBtn" #language fr-FR "CsdnRdioBtn" #string STR_CSDN_RADIO_STRING_HELP #language en-US "CsdnRadio the current setting." #language fr-FR "CsdnRadio the current setting." #string STR_CSDN_STRING_RADIO_1 #language en-US "Csdn Radio Button No 1" #string STR_CSDN_STRING_RADIO_2 #language en-US "Csdn Radio Button No 2" #string STR_CSDN_STRING_RADIO_3 #language en-US "Csdn Radio Button No 3" #string STR_CSDN_STRING_RADIO_4 #language en-US "Csdn Radio Button No 4" #string STR_CSDN_STRING_RADIO_5 #language en-US "Csdn Radio Button No 5" #string STR_CSDN_STRING_RADIO_6 #language en-US "Csdn Radio Button No 6" #string STR_CSDN_STRING_RADIO_7 #language en-US "Csdn Radio Button No 7"
修改 FrontPageVfr.Vfr的Lable
MdeModulePkg/Application/UiApp/FrontPageVfr.Vfr
banner //横幅 title = STRING_TOKEN(STR_CSDN_BANNER_LEFT), //横幅的标题为STR_CSDN_BANNER_LEFT所代表的字符串 line 4, //横幅在屏幕上的垂直距离,在这里横幅位于第4行 align left; //水平方向左对齐 banner title = STRING_TOKEN(STR_CSDN_BANNER_RIGHT), line 4, align right;
2、修改 FrontPageCustomizedUi.c 与 FrontPageCustomizedUiSupport.c
添加Oneof(RadioButton)菜单
MdeModulePkg/Application/UiApp/FrontPageCustomizedUi.c(该文件将提供应用程序具体做什么以及如何定制UI的详细信息)
Oneof是一种用户界面元素,它允许用户从一组预定义的选项中选择一个。它通常用于创建单选按钮组,用户只能选择其中一个选项。
/ Customize menus in the page. @param[in] HiiHandle The HII Handle of the form to update. @param[in] StartOpCodeHandle The context used to insert opcode. @param[in] CustomizePageType The page type need to be customized. / VOID UiCustomizeFrontPage ( IN EFI_HII_HANDLE HiiHandle, IN VOID *StartOpCodeHandle ) { // // Create "Select CSDN" menu with Oneof opcode. // UiCreateCsdnRadioMenu(HiiHandle, StartOpCodeHandle); ... // // Create csdn menu. // UiCreateCsdnMenu(HiiHandle, StartOpCodeHandle); }
其中创造CsdnRatioMenu 和 CsdnMenu的具体实现在FrontPageCustomizedUiSupport.c文件中:
在 MdeModulePkg/Application/UiApp/FrontPageCustomizedUiSupport.c 文件中包含了各个操作的具体步骤。
产生一个EFI_IFR_ACTION_OP操作码,是UEFI固件的用户界面框架(IFR)的一部分。
/* 产生一个EFI_IFR_ACTION_OP操作码,用于定义用户界面的一个问题。当用于与界面元素交互时会被触发 return:返回一个指向UINT8数组的指针,这个数组代表了新创建的操作码。 */ UINT8 * EFIAPI HiiCreateActionOpCode ( IN VOID *OpCodeHandle, //操作码缓冲区的句柄 IN EFI_QUESTION_ID QuestionId, //要定义的问题的ID IN EFI_STRING_ID Prompt, //用于指定问题提示,当问题在用户界面中呈现时,这个提示被显示给用户。 IN EFI_STRING_ID Help, //指定问题帮助信息 IN UINT8 QuestionFlags, //定义问题的各种属性 IN EFI_STRING_ID QuestionConfig //用于指定与问题相关的配置数据 );
可以使用HiiAllocateOpCodeHandle 分配一个新的操作码,最后要用HiiFreeOpCodeHandle()释放掉这个操作码
使用EFI_GET_VARIABLE GetVariable;获取一个变量的值
/* 返回变量的值,EFI变量是固件运行时可以存储和访问的键值对数据 */ typedef EFI_STATUS (EFIAPI *EFI_GET_VARIABLE)( IN CHAR16 *VariableName, //一个以NULL结尾的字符串的指针,它是要检索的变量的名称 IN EFI_GUID *VendorGuid, //指向EFI_GUID的指针,用于标识变量的所有者,这个GUID用于确保正确访问变量 OUT UINT32 *Attributes OPTIONAL, 输出参数、如果不是 NULL,则指向内存位置的指针,以返回变量的属性位掩码。 IN OUT UINTN *DataSize, //输出参数,Data缓冲区的大小 OUT VOID *Data OPTIONAL //输出参数,用于返回变量内容的缓冲区。可以是 NULL 且 DataSize 为零,以便确定所需的缓冲区大小。 );
利用HiiCreateOneOfOptionOpCode创建一个EFI_IFR_ONE_OF_OPTION_OP类型的单选按钮,其代码原型为
/ 创建一个Oneof的操作码(可以理解为单选按钮组) / UINT8 * EFIAPI HiiCreateOneOfOptionOpCode ( IN VOID *OpCodeHandle, //操作码缓冲区的句柄 IN UINT16 StringId, //单选按钮的字符串ID,即单选按钮的名称 IN UINT8 Flags, //单选按钮的属性,是否只读、由默认选择等 IN UINT8 Type, //单选按钮的类型,按钮的不同行为或外观 IN UINT64 Value //单选按钮的值,用于唯一标识单选按钮 );
其中单选按钮组的属性有
/ Create Csdn menu in the front page. 在首页上创建一个DSCN菜单 @param[in] HiiHandle The hii handle for the Uiapp driver. HII表示一个高层接口句柄,是UEFI用于用户处理界面资源的一种机制 @param[in] StartOpCodeHandle The opcode handle to save the new opcode. StartOpCodeHandle是一个特殊的句柄,用于管理UEFI固件中的操作码(OpCode) / VOID UiCreateCsdnMenu( IN EFI_HII_HANDLE HiiHandle, IN VOID *StartOpCodeHandle ) { HiiCreateActionOpCode ( //产生一个操作码 StartOpCodeHandle, //指向已经创建的EFI_HII_HANDLE FRONT_PAGE_KEY_CSDN, //要定义的问题的ID STRING_TOKEN (STR_CSDN_STRING), //问题的提示信息为STR_CSDN_STRING STRING_TOKEN (STR_CSDN_STRING_HELP), //问题的帮助信息 EFI_IFR_FLAG_CALLBACK, //用于定义问题的属性 0 ); } / Create CSDN menu in the front page with oneof opcode. @param[in] HiiHandle The hii handle for the Uiapp driver. @param[in] StartOpCodeHandle The opcode handle to save the new opcode. / VOID UiCreateCsdnRadioMenu ( IN EFI_HII_HANDLE HiiHandle, IN VOID *StartOpCodeHandle ) { CHAR8 *CsdnText; VOID *OptionsOpCodeHandle; UINTN BufferSize; EFI_STATUS Status; CsdnText = AllocatePool (22); //分配EfiBootSerVicesData类型的缓冲区 ASSERT (CsdnText != NULL); Status = gRT->GetVariable (//gRT指向运行时服务 L"CSDNRadioButtonText", //检索一个名为CSDNRadioButtonText的EFI变量 &gEfiIfrFrontPageGuid, //这个GUID是变量的拥有者 NULL, //表示不需要获取变量的属性 &BufferSize, //输出参数,变量值的大小 CsdnText //输出参数,指向一个大小为BufferSize的缓冲区 ); if (!EFI_ERROR (Status)) { DEBUG((EFI_D_INFO,"[csdn] UiCreateCsdnRadioMenu = %a\n",CsdnText)); }else{ DEBUG((EFI_D_INFO,"[csdn] UiCreateCsdnRadioMenu = %r\n",Status)); } OptionsOpCodeHandle = HiiAllocateOpCodeHandle (); //分配一个新的操作码 ASSERT (OptionsOpCodeHandle != NULL); HiiCreateOneOfOptionOpCode ( //创建一个单选按钮组 OptionsOpCodeHandle, //新创建的操作码 STRING_TOKEN (STR_CSDN_STRING_RADIO_1), //按钮组的名称string ID EFI_IFR_OPTION_DEFAULT, //单选按钮的属性 EFI_IFR_NUMERIC_SIZE_1, //单选按钮组的不同行为或外观 0 //单选按钮组的值,唯一标识单选按钮组 ); HiiCreateOneOfOptionOpCode ( OptionsOpCodeHandle, STRING_TOKEN (STR_CSDN_STRING_RADIO_2), EFI_IFR_OPTION_DEFAULT, EFI_IFR_NUMERIC_SIZE_1, 1 ); HiiCreateOneOfOptionOpCode ( OptionsOpCodeHandle, STRING_TOKEN (STR_CSDN_STRING_RADIO_3), EFI_IFR_OPTION_DEFAULT, EFI_IFR_NUMERIC_SIZE_1, 2 ); HiiCreateOneOfOptionOpCode ( OptionsOpCodeHandle, STRING_TOKEN (STR_CSDN_STRING_RADIO_4), EFI_IFR_OPTION_DEFAULT, EFI_IFR_NUMERIC_SIZE_1, 3 ); HiiCreateOneOfOptionOpCode ( OptionsOpCodeHandle, STRING_TOKEN (STR_CSDN_STRING_RADIO_5), EFI_IFR_OPTION_DEFAULT, EFI_IFR_NUMERIC_SIZE_1, 4 ); HiiCreateOneOfOptionOpCode ( OptionsOpCodeHandle, STRING_TOKEN (STR_CSDN_STRING_RADIO_6), EFI_IFR_OPTION_DEFAULT, EFI_IFR_NUMERIC_SIZE_1, 5 ); HiiCreateOneOfOpCode ( StartOpCodeHandle, FRONT_PAGE_KEY_CSDN_RADIIO, 0, 0, STRING_TOKEN (STR_CSDN_RADIO_STRING), STRING_TOKEN (STR_CSDN_RADIO_STRING_HELP), EFI_IFR_FLAG_CALLBACK, EFI_IFR_NUMERIC_SIZE_1, OptionsOpCodeHandle, NULL ); }
使用 EFI_SET_VARIABLE SetVariable设置变量的值
typedef EFI_STATUS (EFIAPI *EFI_SET_VARIABLE)( IN CHAR16 *VariableName, //变量的名称 IN EFI_GUID *VendorGuid, //变量所有者的GUID IN UINT32 Attributes, //定义变量的属性 IN UINTN DataSize, //指定在Data参数中提供的缓冲区的大小 IN VOID *Data //一个指向viod类型的指针,指向包含要设置的数据的缓冲区 );
// 定义 CallBack EFI_STATUS CsdnRadioChangeHandler ( IN EFI_IFR_TYPE_VALUE *Value ) { EFI_STATUS Status; CHAR8 *CsdnText = "Csdn Radio Button No 1"; DEBUG((EFI_D_INFO,"[csdn] CsdnRadioChangeHandler value=%x\n",Value->u8)); Status = gRT->SetVariable ( L"CSDNRadioButtonText", &gEfiIfrFrontPageGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 22, CsdnText ); if (EFI_ERROR (Status)) { DEBUG((EFI_D_INFO,"[csdn] CsdnRadioChangeHandler status=%r\n",Status)); return EFI_DEVICE_ERROR; } return EFI_SUCCESS; } //触发 CallBack BOOLEAN UiSupportLibCallbackHandler ( IN EFI_HII_HANDLE HiiHandle, 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, OUT EFI_STATUS *Status ){ ... switch (QuestionId) { case FRONT_PAGE_KEY_CONTINUE: // // This is the continue - clear the screen and return an error to get out of FrontPage loop // *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT; break; ... //CallBack 触发入口 case FRONT_PAGE_KEY_CSDN_RADIIO: *Status = CsdnRadioChangeHandler(Value); break; default: break; } }
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/128051.html