Now we can finally register our Package list in the HII database. Here is a description for the NewPackageList
one more time:
EFI_HII_DATABASE_PROTOCOL.NewPackageList()
Summary:
Adds the packages in the package list to the HII database.
Prototype:
typedef
EFI_STATUS
(EFIAPI *EFI_HII_DATABASE_NEW_PACK) (
IN CONST EFI_HII_DATABASE_PROTOCOL *This,
IN CONST EFI_HII_PACKAGE_LIST_HEADER *PackageList,
IN CONST EFI_HANDLE DriverHandle, OPTIONAL
OUT EFI_HII_HANDLE *Handle
);
Parameters:
This A pointer to the EFI_HII_DATABASE_PROTOCOL instance
PackageList A pointer to an EFI_HII_PACKAGE_LIST_HEADER structure
DriverHandle Associate the package list with this EFI handle
Handle A pointer to the EFI_HII_HANDLE instance
Description This function adds the packages in the package list to the database and returns a handle. If there is a
EFI_DEVICE_PATH_PROTOCOL associated with the DriverHandle, then this function will create a
package of type EFI_PACKAGE_TYPE_DEVICE_PATH and add it to the package list.
We've already filled PackageList array, so we can use this function like this:
EFI_HII_HANDLE Handle;
EFI_STATUS Status = gHiiDatabase->NewPackageList(gHiiDatabase, PackageListHdr, NULL, &Handle);
if (EFI_ERROR(Status))
{
Print(L"Can't register HII Package list %g, status = %r\n", gHIIStringsCGuid, Status);
}
Now when we have EFI_HII_HANDLE Handle
for our package list it is time to try to get strings from the HII Database. For this we can utilize GetString
from another of HII Database protocols - EFI_HII_STRING_PROTOCOL
:
EFI_HII_STRING_PROTOCOL.GetString()
Summary:
Returns information about a string in a specific language, associated with a package list.
Prototype:
typedef
EFI_STATUS
(EFIAPI *EFI_HII_GET_STRING) (
IN CONST EFI_HII_STRING_PROTOCOL *This,
IN CONST CHAR8 *Language,
IN EFI_HII_HANDLE PackageList,
IN EFI_STRING_ID StringId,
OUT EFI_STRING String,
IN OUT UINTN *StringSize,
OUT EFI_FONT_INFO **StringFontInfo OPTIONAL
);
Parameters:
This A pointer to the EFI_HII_STRING_PROTOCOL instance.
PackageList The package list in the HII database to search for the specified string.
Language Points to the language for the retrieved string. Callers of interfaces that require RFC
4646 language codes to retrieve a Unicode string must use the RFC 4647 algorithm to
lookup the Unicode string with the closest matching RFC 4646 language code.
StringId The string’s id, which is unique within PackageList.
String Points to the new null-terminated string.
StringSize On entry, points to the size of the buffer pointed to by String, in bytes. On return,
points to the length of the string, in bytes.
StringFontInfo Points to a buffer that will be callee allocated and will have the string's font
information into this buffer. The caller is responsible for freeing this buffer. If the
parameter is NULL a buffer will not be allocated and the string font information will
not be returned.
Description:
This function retrieves the string specified by StringId which is associated with the specified
PackageList in the language Language and copies it into the buffer specified by String.
Once again here is a standard UEFI scheme for getting resources of unknown size. First we call GetString
with a StringSize=0
. The function returns EFI_BUFFER_TOO_SMALL
, but fills the StringSize
with a necessary value. Then we call GetString
one more time, this time with a correct StringSize
.
As we've included UefiHiiServicesLib
in our application we don't need to perform LocateProtocol
to find EFI_HII_STRING_PROTOCOL
but simply can use gHiiString
variable.
Here is a function PrintStringFromHiiHandle
for printing strings from Package list with a EFI_HII_HANDLE
by simply providing string (Id, Language) combination:
EFI_STATUS PrintStringFromHiiHandle(EFI_HII_HANDLE* Handle, CHAR8* Language, UINTN StringId)
{
EFI_STRING String = NULL;
UINTN StringSize = 0;
EFI_STATUS Status = gHiiString->GetString(gHiiString, Language, *Handle, StringId, String, &StringSize, NULL);
if (Status != EFI_BUFFER_TOO_SMALL) {
return Status;
}
String = AllocateZeroPool(StringSize);
if (String == NULL) {
return Status;
}
Status = gHiiString->GetString(gHiiString, Language, *Handle, StringId, String, &StringSize, NULL);
Print(L"Status = %r, %s\n", Status, String);
FreePool(String);
return EFI_SUCCESS;
}
After we've registered our package we can use it as simple as this:
PrintStringFromHiiHandle(&Handle, "en-US", 1);
PrintStringFromHiiHandle(&Handle, "en-US", 2);
PrintStringFromHiiHandle(&Handle, "fr-FR", 1);
PrintStringFromHiiHandle(&Handle, "fr-FR", 2);
Now it is time to combine everything together and build our application.
If we execute it under OVMF we would get:
FS0:\> HIIStringsC.efi
Status = Success, English
Status = Success, Hello
Status = Success, French
Status = Success, Bonjour
So everything works correctly!
We can even see our newly created package if we execute our ShowHII
application:
FS0:\> ShowHII.efi
...
PackageList[20]: GUID=8E0B8ED3-14F7-499D-A224-AEE89DC97FA3; size=0xC0
Package[0]: type=STRINGS; size=0x53
Package[1]: type=STRINGS; size=0x55
Package[2]: type=END; size=0x4
Keep in mind that if we will try to execute the HIIStringsC
app again we would get an errror:
FS0:\> HIIStringsC.efi
Can't register HII Package list 8E0B8ED3-14F7-499D-A224-AEE89DC97FA3, status = Invalid Parameter
It is happening, because it is not possible to register two Package lists with the same GUID.