之前提到过,使用 LoadImage 和 StartImage 无法加载 CLib Build出来的 EFI Application。一种变通的方法是通过 ShellLib 下面的 ShellExcute 来调用其他的 EFI Application。
具体定义在 \ShellPkg\Library\UefiShellLib\UefiShellLib.c
** Cause the shell to parse and execute a command line. This function creates a nested instance of the shell and executes the specified command (CommandLine) with the specified environment (Environment). Upon return, the status code returned by the specified command is placed in StatusCode. If Environment is NULL, then the current environment is used and all changes made by the commands executed will be reflected in the current environment. If the Environment is non-NULL, then the changes made will be discarded. The CommandLine is executed from the current working directory on the current device. The EnvironmentVariables pararemeter is ignored in a pre-UEFI Shell 2.0 environment. The values pointed to by the parameters will be unchanged by the ShellExecute() function. The Output parameter has no effect in a UEFI Shell 2.0 environment. @param[in] ParentHandle The parent image starting the operation. @param[in] CommandLine The pointer to a NULL terminated command line. @param[in] Output True to display debug output. False to hide it. @param[in] EnvironmentVariables Optional pointer to array of environment variables in the form "x=y". If NULL, the current set is used. @param[out] Status The status of the run command line. @retval EFI_SUCCESS The operation completed sucessfully. Status contains the status code returned. @retval EFI_INVALID_PARAMETER A parameter contains an invalid value. @retval EFI_OUT_OF_RESOURCES Out of resources. @retval EFI_UNSUPPORTED The operation is not allowed. **/ EFI_STATUS EFIAPI ShellExecute ( IN EFI_HANDLE *ParentHandle, IN CHAR16 *CommandLine OPTIONAL, IN BOOLEAN Output OPTIONAL, IN CHAR16 **EnvironmentVariables OPTIONAL, OUT EFI_STATUS *Status OPTIONAL ) { EFI_STATUS CmdStatus; // // Check for UEFI Shell 2.0 protocols // if (gEfiShellProtocol != NULL) { // // Call UEFI Shell 2.0 version (not using Output parameter) // return (gEfiShellProtocol->Execute(ParentHandle, CommandLine, EnvironmentVariables, Status)); } // // Check for EFI shell // if (mEfiShellEnvironment2 != NULL) { // // Call EFI Shell version. // Due to oddity in the EFI shell we want to dereference the ParentHandle here // CmdStatus = (mEfiShellEnvironment2->Execute(*ParentHandle, CommandLine, Output)); // // No Status output parameter so just use the returned status // if (Status != NULL) { *Status = CmdStatus; } // // If there was an error, we can't tell if it was from the command or from // the Execute() function, so we'll just assume the shell ran successfully // and the error came from the command. // return EFI_SUCCESS; } return (EFI_UNSUPPORTED); }
调用参数如下:
ParentHandle 执行操作的父进程的Handle
CommandLine 要执行的命令行
Output 是否输出 Debug 信息(这里我没有搞明白,如果有清楚的朋友望不吝赐教)
EnvironmentVariables 环境变量
因为已经在头文件中定义过,所以我们可以直接调用。
比如用下面的方式可以执行 ls 命令:
Shell command CHAR16 *S=L"ls"; OpStat = ShellExecute( &MyHandle, S, FALSE, NULL, &CmdStat);
我们再编写一个简单的程序输出当前收到的命令行参数
#include <Uefi.h> #include <Library/UefiLib.h> #include <Library/ShellCEntryLib.h> int EFIAPI main ( IN int Argc, IN char **Argv ) { int i; for (i=0;i<Argc; i++) { Print(L"%S\n",Argv[i]); } return EFI_SUCCESS; }
[Defines] INF_VERSION = 0x00010006 BASE_NAME = Hello1 FILE_GUID = 4ea97c46-7491-4dfd-0048-747010f3ce51 MODULE_TYPE = UEFI_APPLICATION VERSION_STRING = 0.1 ENTRY_POINT = ShellCEntryLib # # VALID_ARCHITECTURES = IA32 X64 IPF # [Sources] Hello1.c [Packages] StdLib/StdLib.dec MdePkg/MdePkg.dec ShellPkg/ShellPkg.dec [LibraryClasses] LibC LibStdio ShellCEntryLib ShellLib BaseLib BaseMemoryLib UefiLib [Protocols] [BuildOptions]
运行结果
我们使用 ShellExecute 的代码
#include <Uefi.h> #include <Library/UefiLib.h> #include <Library/ShellCEntryLib.h> #include <Library/ShellLib.h> extern EFI_BOOT_SERVICES *gBS; extern EFI_SYSTEM_TABLE *gST; extern EFI_RUNTIME_SERVICES *gRT; extern EFI_SHELL_PROTOCOL *gEfiShellProtocol; extern EFI_SHELL_ENVIRONMENT2 *mEfiShellEnvironment2; extern EFI_HANDLE gImageHandle; int EFIAPI main ( IN int Argc, IN char **Argv ) { EFI_STATUS CmdStat; EFI_STATUS OpStat; EFI_HANDLE MyHandle = gImageHandle; CHAR16 *S=L"hello1.efi a1 b2 c3"; OpStat = ShellExecute( &MyHandle, S, FALSE, NULL, &CmdStat); return EFI_SUCCESS; }
可以看到,能够调用hello1.efi 并且正确的传递了参数。
本文提到的完整代码下载:
你好,請問下次可以寫寫Signal a key press event的教學嗎?
你参考一下这个看看 http://www.lab-z.com/regkey/
你好 我想請問一下 要怎麼用shell application 秀出滑鼠的移動值
参考这个 http://www.lab-z.com/stumouse/
ShellExecute 执行Shell指令会清屏,有办法不清吗?
我试验了一下,调用 ls 这样的命令会请屏幕然后再运行应该是 Shell 的动作。就是UEFI 重新启动了一个Shel 然后再执行的ls。如果想达到不清屏幕的目标,恐怕只能修改 Shell 了。
那看来只能先这么用了,另外想请教下,UEFI下比如硬盘信息,内存信息这些硬件信息,有什么办法或者从哪里可以获取到?
你可以看一下 SMBIOS ,有一些基本信息。要想更准确的话需要逐个设备研究了。
請問可以用A.efi 呼叫b.efi 的程式嗎?
抱歉,沒注意看清楚@@
請問這code 可以在UDK2014 上執行嗎?
抱歉,沒注意看清楚@@
請問這code 可以在UDK2014 上執行嗎?
或只是需要做修改?
Hi, 应该可以的。你可以试试哈。
請問如果想抓取執行程式後螢幕的輸出資料,大大可否給個方向~ 感謝你
請問如果要抓取螢幕的輸出結果,大大有推薦的方向嗎? 謝謝你
目前没有例子,不过我想你可以在传递 systemtable 的时候换掉 ConOut->OutputString ,这样有机会截获参数。你可以试试啊。
您好!请问为什么在我的以shellcentry作为入口函数的代码中,利用Print(L”%S\n”,Argv[i]);输出的信息会乱码,而在uefimain入口函数则不会呢?我把您的Hello1.c在我的edk2环境中重新编译了一下,也是会输出错误的信息。
你可以试试以shellcentry作为入口函数的代码中,利用Print(L”%a\n”,Argv[i]);输出的信息是不是乱码?