HOWTO:使用 Win32 API 枚举应用程序

简介:
一个常见的编程任务是枚举所有运行的"应用程序"。Windows 任务管理器就是一个很好的例子。它用两种方式列出"应用程序"。任务管理器的第一个选项卡列出桌面上的所有"应用程序窗口"。第二个选项卡列出系统中的所有"进程"。本文提供了如何执行这些任务的详细信息。

更多信息

枚举顶层窗口

如果将枚举进程与枚举桌面上的顶层窗口进行比较,那么枚举顶层窗口可能更容易一些。要枚举顶层窗口,请使用  EnumWindows() 函数。不要使用  GetWindow() 创建自己的窗口列表,因为它可能受 z 轴次序更改和丢失窗口的干扰。

EnumWindows() 将指向某个回调函数的指针以及用户定义的  LPARAM 值作为其参数。它对桌面上的每个窗口(或顶层窗口)分别调用一次回调函数。然后,回调函数可以对此窗口句柄进行某种处理,如将其添加到一个列表中。此方法可以保证不受窗口 z 轴次序更改等项的干扰。在获取窗口句柄后,可以通过调用  GetWindowText() 来获取其标题。

枚举进程

在系统中创建进程列表比枚举窗口要稍微复杂一些。这主要是因为执行此操作的 API 函数因所使用的 Win32 操作系统而异。在 Windows 95、Windows 98、Windows Millennium Edition、Windows 2000 和 Windows XP 中,可以使用 ToolHelp32 API 库中的函数。但是,在 Windows NT 中,必须使用 PSAPI API 库中的函数(Platform SDK 中包含该库)。本文将讨论这两种技术,另外还提供一个称为  EnumProcs() 的示例包装函数,该函数可以在 Win32 操作系统中运行。

使用 ToolHelp32 库枚举进程

首先讨论 ToolHelp32 方法。KERNEL32.dll 中的 ToolHelp32 函数是标准的 API 函数。注意,在 Windows NT 4.0 中不提供这些 API。

可以使用 ToolHelp32 提供的各种函数,枚举系统中的进程和线程以及获取内存和模块信息。但是,在枚举进程时,仅需要使用以下三个函数: CreateToolhelp32Snapshot()Process32First()  Process32Next()

使用 ToolHelp32 函数的第一步是创建系统信息的"快照"。可以使用  CreateToolhelp32Snapshot() 函数完成这一步。此函数允许选择在快照中存储的信息类型。如果您需要进程信息,则一定要包括  TH32CS_SNAPPROCESS 标志。 CreateToolhelp32Snapshot() 函数返回一个句柄,在使用完该句柄后,必须将其传递到 CloseHandle()

下一步,为了检索快照中的进程列表,可以调用一次  Process32First,然后重复调用多次  Process32Next。执行此操作,直到其中的一个函数返回 FALSE 为止。这将逐个获得快照进程列表中的进程。这两个函数都将"快照"句柄和指向 PROCESSENTRY32 结构的指针作为其参数。

在调用  Process32First  Process32Next 后,PROCESSENTRY32 结构将包含系统中某个进程的有用信息。进程 ID 在该结构的 th32ProcessID 成员中。可以将它传递到  OpenProcess() 以获取该进程的句柄。该进程的可执行文件和路径存储在结构的 szExeFile 成员中。还可以在此结构中找到其他有用的信息。

备注:切记,在调用  Process32First() 之前,将 PROCESSENTRY32 结构的 dwSize 成员设置为  sizeof(PROCESSENTRY32)

使用 PSAPI 库枚举进程

在 Windows NT 中创建进程列表的方法是使用 PSAPI.dll 中的 PSAPI 函数。此文件是随 Platform SDK 分发的,可以从以下 Microsoft Web 站点下载该文件:
Microsoft Platform SDK 
http://www.microsoft.com/msdownload/platformsdk/sdkupdate/  (http://www.microsoft.com/msdownload/platformsdk/sdkupdate/)
所需的 PSAPI.h 和 PSAPI.lib 文件也包含在 Platform SDK 中。

要使用 PSAPI 库中的函数,请将 PSAPI.lib 文件添加到您的项目中,并将 PSAPI.h 文件包含到任何调用 PSAPI API 的模块中。切记,要将 PSAPI.dll 文件与使用它的任何可执行文件一起分发,因为没有随 Windows NT 4.0 分发该文件。可以从以下位置下载可重新分发的 PSAPI.dll 版本(如果没有完整的 Platform SDK 的话):
Platform SDK 可重新分发的版本:用于 Windows NT 的 PSAPI
http://www.microsoft.com/downloads/release.asp?releaseid=30337  (http://www.microsoft.com/downloads/release.asp?releaseid=3 0337)
与 ToolHelp32 函数一样,PSAPI 也包含很多其他的有用函数。但是,本文只讨论与枚举进程有关的函数: EnumProcesses()EnumProcessModules()GetModuleFileNameEx()  GetModuleBaseName()

创建进程列表的第一步是调用  EnumProcesses()。以下是其声明:
BOOL EnumProcesses( DWORD *lpidProcess, DWORD cb, DWORD *cbNeeded );
需要给  EnumProcesses()  传入三个参数:指向 DWORD 数组的指针 (lpidProcess)、该数组的大小 ( cb ) 以及另一个指向 DWORD 的指针 ( cbNeeded )(用于获取返回数据的长度)。使用当前所运行进程的进程 ID 数组来填充 DWORD 数组。 cbNeeded  参数返回所使用数组的大小。以下计算告诉您返回了多少个进程 ID:nReturned = cbNeeded / sizeof(DWORD)。

备注: 虽然本文将返回的 DWORD 命名为"cbNeeded",但实际上无法确定在数组中传递的进程到底有多少。 EnumProcesses()   cbNeeded  中返回的值绝不会大于在  cb  参数中传递的数组值。因此,要确保成功使用  EnumProcesses()  函数,唯一的方法是分配一个 DWORD 数组,如果返回时  cbNeeded  等于  cb ,则分配较大的数组并重试,直到  cbNeeded  小于  cb  时为止。

现在,数组包含系统中的每个进程 ID。如果您的目标是获取进程名,则必须先获取句柄。要从进程 ID 中获取句柄,请使用  OpenProcess()

在获取句柄后,需要获取进程的第一个模块。要获取进程的第一个模块,请使用以下参数调用  EnumProcessModules()  API: 
EnumProcessModules( hProcess, &hModule,  sizeof(hModule), &cbReturned );
这将把进程第一个模块的句柄放在 hModule 变量中。切记,进程实际上并没有名称,但进程中的第一个模块是该进程的可执行文件。现在,可以将返回的模块句柄 (hModule) 用于  GetModuleFileNameEx()   GetModuleBaseName()  API,以获取进程可执行文件的完整路径名或简单模块名。这两个函数需要传入进程句柄、模块句柄以及返回名称的缓冲区指针,后面是缓冲区的大小。

通过对  EnumProcesses()  API 返回的每个进程 ID 重复上述步骤,即可创建 Windows NT 中进程的列表。

16 位进程

在 Windows 95、Windows 98 和 Windows Millennium Edition 上,对 ToolHelp32 而言,所有 16 位应用程序是平等的。与 Win32 应用程序一样,16 位应用程序也具有进程 ID 等。但是,在 Windows NT、Windows 2000 或 Windows XP 中,则不是这样。在这些操作系统上,16 位应用程序运行在 DOS 虚拟机 (VDM) 中。

要在 Windows NT、Windows 2000 和 Windows XP 中枚举 16 位应用程序,必须使用名为  VDMEnumTaskWOWEx()  的函数。必须在源模块中包含 VDMDBG.h,并且 VDMDBG.lib 文件必须与项目链接在一起。这两个文件包含在 Platform SDK 中。

此函数的声明如下: 
INT WINAPI VDMEnumTaskWOWEx( DWORD dwProcessId, TASKENUMPROCEX fp,
LPARAM lparam );
其中,dwProcessId 是要枚举其 16 位任务的 NTVDM 进程的标识符。 fp  参数是指向回调枚举函数的指针。 lparam  参数是要传递给枚举函数的用户定义值。

枚举函数应当定义如下: 
BOOL WINAPI Enum16( DWORD dwThreadId, WORD hMod16, WORD hTask16, PSZ
pszModName, PSZ pszFileName, LPARAM lpUserDefined );
对于传递到  VDMEnumTaskWOWEx()  的 NTVDM 进程中运行的每个 16 位任务,分别调用一次该函数。如果要继续枚举,则应该返回 FALSE,如果要结束枚举,则应该返回 TRUE。注意,这与  EnumWindows()  正好相反。

示例代码

下示例代码将 PSAPI 和 ToolHelp32 函数封装在名为  EnumProcs()  的函数中。此函数与  EnumWindows()  类似,因为它也接受指向某个函数的指针并重复调用它(对系统中的每个进程分别调用一次)。以下是该函数的声明: 
BOOL WINAPI EnumProcs( PROCENUMPROC lpProc, LPARAM lParam );
如果使用该函数,则将回调函数声明如下:
BOOL CALLBACK Proc( DWORD dw, WORD w16, LPCSTR lpstr, LPARAM lParam );
其中, dw  参数将包含 ID;"w16"是 16 位任务编号或 0(如果是 32 位进程,则在 Windows 95 下始终为零); lpstr  参数将指向文件名; lParam  是传递给  EnumProcs()  的用户定义的  lParam

EnumProcs()  函数通过显式链接使用 ToolHelp32 和 PSAPI 函数,而不是通过更常用的隐式链接。通过使用这种技术,可以使代码在所有 Win32 操作系统中二进制兼容。
//
//  EnumProc.c
//
#include <windows.h>
#include <stdio.h>
#include <tlhelp32.h>
#include <vdmdbg.h>

typedef BOOL (CALLBACK *PROCENUMPROC)(DWORD, WORD, LPSTR, LPARAM);

typedef  struct  {
DWORD          dwPID;
PROCENUMPROC   lpProc;
DWORD          lParam;
BOOL           bEnd;
}
 EnumInfoStruct;

BOOL WINAPI EnumProcs(PROCENUMPROC lpProc, LPARAM lParam);

BOOL WINAPI Enum16(DWORD dwThreadId, WORD hMod16, WORD hTask16,
PSZ pszModName, PSZ pszFileName, LPARAM lpUserDefined);

//
//  The EnumProcs function takes a pointer to a callback function
//  that will be called once per process with the process filename
//  and process ID.
//
//  lpProc -- Address of callback routine.
//
//  lParam -- A user-defined LPARAM value to be passed to
//            the callback routine.
//
//  Callback function definition:
//  BOOL CALLBACK Proc(DWORD dw, WORD w, LPCSTR lpstr, LPARAM lParam);
//
BOOL WINAPI EnumProcs(PROCENUMPROC lpProc, LPARAM lParam)  {

OSVERSIONINFO  osver;
HINSTANCE      hInstLib  = NULL;
HINSTANCE      hInstLib2 = NULL;
HANDLE         hSnapShot = NULL;
LPDWORD        lpdwPIDs  = NULL;
PROCESSENTRY32 procentry;
BOOL           bFlag;
DWORD          dwSize;
DWORD          dwSize2;
DWORD          dwIndex;
HMODULE        hMod;
HANDLE         hProcess;
char           szFileName[MAX_PATH];
EnumInfoStruct sInfo;

// ToolHelp Function Pointers.
HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD, DWORD);
BOOL (WINAPI *lpfProcess32First)(HANDLE, LPPROCESSENTRY32);
BOOL (WINAPI *lpfProcess32Next)(HANDLE, LPPROCESSENTRY32);

// PSAPI Function Pointers.
BOOL (WINAPI *lpfEnumProcesses)(DWORD *, DWORD, DWORD *);
BOOL (WINAPI *lpfEnumProcessModules)(HANDLE, HMODULE *, DWORD,
LPDWORD);
DWORD (WINAPI *lpfGetModuleBaseName)(HANDLE, HMODULE, LPTSTR, DWORD);

// VDMDBG Function Pointers.
INT (WINAPI *lpfVDMEnumTaskWOWEx)(DWORD, TASKENUMPROCEX, LPARAM);

// Retrieve the OS version
osver.dwOSVersionInfoSize = sizeof(osver);
if (!GetVersionEx(&osver))
return FALSE;

// If Windows NT 4.0
if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT
&& osver.dwMajorVersion == 4) {

__try {

// Get the procedure addresses explicitly.We do
// this so we don't have to worry about modules
// failing to load under OSes other than Windows NT 4.0
// because references to PSAPI.DLL can't be resolved.
hInstLib = LoadLibraryA("PSAPI.DLL");
if (hInstLib == NULL)
__leave;

hInstLib2 = LoadLibraryA("VDMDBG.DLL");
if (hInstLib2 == NULL)
__leave;

// Get procedure addresses.
lpfEnumProcesses = (BOOL (WINAPI *)(DWORD *, DWORD, DWORD*))
GetProcAddress(hInstLib, "EnumProcesses");

lpfEnumProcessModules = (BOOL (WINAPI *)(HANDLE, HMODULE *,
DWORD, LPDWORD)) GetProcAddress(hInstLib,
"EnumProcessModules");

lpfGetModuleBaseName = (DWORD (WINAPI *)(HANDLE, HMODULE,
LPTSTR, DWORD)) GetProcAddress(hInstLib,
"GetModuleBaseNameA");

lpfVDMEnumTaskWOWEx = (INT (WINAPI *)(DWORD, TASKENUMPROCEX,
LPARAM)) GetProcAddress(hInstLib2, "VDMEnumTaskWOWEx");

if (lpfEnumProcesses == NULL
|| lpfEnumProcessModules == NULL
|| lpfGetModuleBaseName == NULL
|| lpfVDMEnumTaskWOWEx == NULL)
__leave;

         //
// Call the PSAPI function EnumProcesses to get all of the
// ProcID's currently in the system.
         
//
// NOTE:In the documentation, the third parameter of
// EnumProcesses is named cbNeeded, which implies that you
// can call the function once to find out how much space to
// allocate for a buffer and again to fill the buffer.
// This is not the case.The cbNeeded parameter returns
// the number of PIDs returned, so if your buffer size is
// zero cbNeeded returns zero.
         
//
// NOTE:The "HeapAlloc" loop here ensures that we
// actually allocate a buffer large enough for all the
// PIDs in the system.
         
//
dwSize2 = 256 * sizeof(DWORD);
do {

if (lpdwPIDs) {
HeapFree(GetProcessHeap(), 0, lpdwPIDs);
dwSize2 *= 2;
            }


lpdwPIDs = (LPDWORD) HeapAlloc(GetProcessHeap(), 0,
dwSize2);
if (lpdwPIDs == NULL)
__leave;

if (!lpfEnumProcesses(lpdwPIDs, dwSize2, &dwSize))
__leave;

}
 while (dwSize == dwSize2);

// How many ProcID's did we get?
dwSize /= sizeof(DWORD);

// Loop through each ProcID.
for (dwIndex = 0; dwIndex < dwSize; dwIndex++) {

szFileName[0] = 0;

// Open the process (if we can security does not
// permit every process in the system to be opened).
hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, lpdwPIDs[dwIndex]);
if (hProcess != NULL) {

// Here we call EnumProcessModules to get only the
// first module in the process.This will be the
// EXE module for which we will retrieve the name.
if (lpfEnumProcessModules(hProcess, &hMod,
sizeof(hMod), &dwSize2)) {

// Get the module name
if (!lpfGetModuleBaseName(hProcess, hMod,
szFileName, sizeof(szFileName)))
szFileName[0] = 0;
               }

CloseHandle(hProcess);
            }

// Regardless of OpenProcess success or failure, we
// still call the enum func with the ProcID.
if (!lpProc(lpdwPIDs[dwIndex], 0, szFileName, lParam))
break;

// Did we just bump into an NTVDM?
if (_stricmp(szFileName, "NTVDM.EXE") == 0) {

// Fill in some info for the 16-bit enum proc.
sInfo.dwPID = lpdwPIDs[dwIndex];
sInfo.lpProc = lpProc;
sInfo.lParam = (DWORD) lParam;
sInfo.bEnd = FALSE;

// Enum the 16-bit stuff.
lpfVDMEnumTaskWOWEx(lpdwPIDs[dwIndex],
(TASKENUMPROCEX) Enum16, (LPARAM) &sInfo);

// Did our main enum func say quit?
if (sInfo.bEnd)
break;
            }

         }


}
 __finally {

if (hInstLib)
FreeLibrary(hInstLib);

if (hInstLib2)
FreeLibrary(hInstLib2);

if (lpdwPIDs)
HeapFree(GetProcessHeap(), 0, lpdwPIDs);
      }


// If any OS other than Windows NT 4.0.
}
 else if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS
|| (osver.dwPlatformId == VER_PLATFORM_WIN32_NT
&& osver.dwMajorVersion > 4)) {

__try {

hInstLib = LoadLibraryA("Kernel32.DLL");
if (hInstLib == NULL)
__leave;

// If NT-based OS, load VDMDBG.DLL.
if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
hInstLib2 = LoadLibraryA("VDMDBG.DLL");
if (hInstLib2 == NULL)
__leave;
         }


// Get procedure addresses.We are linking to
// these functions explicitly, because a module using
// this code would fail to load under Windows NT,
// which does not have the Toolhelp32
// functions in KERNEL32.DLL.
lpfCreateToolhelp32Snapshot =
(HANDLE (WINAPI *)(DWORD,DWORD))
GetProcAddress(hInstLib, "CreateToolhelp32Snapshot");

lpfProcess32First =
(BOOL (WINAPI *)(HANDLE,LPPROCESSENTRY32))
GetProcAddress(hInstLib, "Process32First");

lpfProcess32Next =
(BOOL (WINAPI *)(HANDLE,LPPROCESSENTRY32))
GetProcAddress(hInstLib, "Process32Next");

if (lpfProcess32Next == NULL
|| lpfProcess32First == NULL
|| lpfCreateToolhelp32Snapshot == NULL)
__leave;

if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
lpfVDMEnumTaskWOWEx = (INT (WINAPI *)(DWORD, TASKENUMPROCEX,
LPARAM)) GetProcAddress(hInstLib2, "VDMEnumTaskWOWEx");
if (lpfVDMEnumTaskWOWEx == NULL)
__leave;
         }


// Get a handle to a Toolhelp snapshot of all processes.
hSnapShot = lpfCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapShot == INVALID_HANDLE_VALUE) {
FreeLibrary(hInstLib);
return FALSE;
         }


// Get the first process' information.
procentry.dwSize = sizeof(PROCESSENTRY32);
bFlag = lpfProcess32First(hSnapShot, &procentry);

// While there are processes, keep looping.
while (bFlag) {

// Call the enum func with the filename and ProcID.
if (lpProc(procentry.th32ProcessID, 0,
procentry.szExeFile, lParam)) {

// Did we just bump into an NTVDM?
if (_stricmp(procentry.szExeFile, "NTVDM.EXE") == 0) {

// Fill in some info for the 16-bit enum proc.
sInfo.dwPID = procentry.th32ProcessID;
sInfo.lpProc = lpProc;
sInfo.lParam = (DWORD) lParam;
sInfo.bEnd = FALSE;

// Enum the 16-bit stuff.
lpfVDMEnumTaskWOWEx(procentry.th32ProcessID,
(TASKENUMPROCEX) Enum16, (LPARAM) &sInfo);

// Did our main enum func say quit?
if (sInfo.bEnd)
break;
               }


procentry.dwSize = sizeof(PROCESSENTRY32);
bFlag = lpfProcess32Next(hSnapShot, &procentry);

}
 else
bFlag = FALSE;
         }


}
 __finally {

if (hInstLib)
FreeLibrary(hInstLib);

if (hInstLib2)
FreeLibrary(hInstLib2);
      }


}
 else
return FALSE;

// Free the library.
FreeLibrary(hInstLib);

return TRUE;
}



BOOL WINAPI Enum16(DWORD dwThreadId, WORD hMod16, WORD hTask16,
PSZ pszModName, PSZ pszFileName, LPARAM lpUserDefined)  {

BOOL bRet;

EnumInfoStruct *psInfo = (EnumInfoStruct *)lpUserDefined;

bRet = psInfo->lpProc(psInfo->dwPID, hTask16, pszFileName,
psInfo->lParam);

if (!bRet)
psInfo->bEnd = TRUE;

return !bRet;
}



BOOL CALLBACK MyProcessEnumerator(DWORD dwPID, WORD wTask,
LPCSTR szProcess, LPARAM lParam)  {

if (wTask == 0)
printf("%5u   %s\n", dwPID, szProcess);
else
printf("  %5u %s\n", wTask, szProcess);

return TRUE;
}



void main()  {
EnumProcs((PROCENUMPROC) MyProcessEnumerator, 0);

参考

Pietrek, Matt, "Under the Hood,"  Microsoft Systems Journal , no. 8 (August 1996).

Pietrek, Matt, "Under the Hood,"  Microsoft Systems Journal , no. 11 (November 1996).


这篇文章中的信息适用于:
Microsoft Win32 应用程序编程接口 (API)当用于
    Microsoft Windows 95 Service Pack 1
    Microsoft Windows 98 Standard Edition
    Microsoft Windows Millennium Edition
    Microsoft Windows NT 4.0 Service Pack 7
    Microsoft Windows 2000 Standard Edition
    Microsoft Windows XP Standard Edition
关键字: 
kbhowto kbthread kbkernbase kbgrpdskernbase KB175030
Microsoft和/或其各供应商对于为任何目的而在本服务器上发布的文件及有关图形所含信息的适用性,不作任何声明。 所有该等文件及有关图形均"依样"提供,而不带任何性质的保证。Microsoft和/或其各供应商特此声明,对所有与该等信息有关的保证和条件不负任何责任,该等保证和条件包括关于适销性、符合特定用途、所有权和非侵权的所有默示保证和条件。在任何情况下,在由于使用或运行本服务器上的信息所引起的或与该等使用或运行有关的诉讼中,Microsoft和/或其各供应商就因丧失使用、数据或利润所导致的任何特别的
目录
相关文章
|
2月前
|
供应链 搜索推荐 数据挖掘
探秘京东 API 接口的神奇应用场景
京东API如同数字钥匙,助力商家实现商品、库存、订单等多平台高效同步,提升效率超80%。支持物流实时追踪,增强用户满意度;赋能精准营销与数据分析,决策准确率提升20%以上,全面优化电商运营。
138 1
|
3月前
|
人工智能 自然语言处理 机器人
使用 API 编程开发扣子应用
扣子(Coze)应用支持通过 API 编程,将 AI 聊天、内容生成、工作流自动化等功能集成至自有系统。主要 API 包括 Bot API(用于消息交互与会话管理)及插件与知识库 API(扩展功能与数据管理)。开发流程包括创建应用、获取密钥、调用 API 并处理响应,支持 Python 等语言。建议加强错误处理、密钥安全与会话管理,提升集成灵活性与应用扩展性。
1244 0
|
4月前
|
监控 供应链 搜索推荐
电商数据开发实践:深度剖析1688商品详情 API 的技术与应用
在电商数字化转型中,数据获取效率与准确性至关重要。本文介绍了一款高效商品详情API,具备全维度数据采集、价格库存管理、多媒体资源获取等功能,结合实际案例探讨其在电商开发中的应用价值与优势。
|
4月前
|
API 定位技术 调度
实现精准定位的—坐标系经纬度转换API技术说明和行业应用
在地图服务、物流调度等应用中,多源地理位置数据因采用不同坐标系(如WGS84、GCJ02、BD09)需统一转换,以避免位置偏移影响路径规划与分析精度。本文介绍坐标转换背景、技术方案及Python调用示例,强调其在智慧交通与物流系统中的重要性。
535 0
|
6月前
|
人工智能 供应链 安全
未来电商趋势:API技术在智能供应链中的应用
随着电商蓬勃发展,供应链管理正借助API技术实现智能化升级。本文解析API作为电商生态“粘合剂”的作用,探讨其在库存管理、物流协同和风险预测中的关键应用,以及对AI融合、区块链安全和实时生态的推动。API不仅提升效率与用户体验,更重塑电商未来格局,成为企业竞争的核心优势。拥抱API集成,将是应对市场复杂性的关键策略。
192 4
|
6月前
|
存储 供应链 API
区块链技术在电商API中的应用:保障数据安全与交易透明
区块链技术在电商API中的应用,为数据安全与交易透明提供了新方案。通过数据加密、分布式存储、智能合约管理、商品溯源及实时结算等功能,有效提升电商数据安全性与交易可信度。然而,技术成熟度、隐私保护和监管合规等挑战仍需克服。未来,随着物联网、大数据等技术融合及政策支持,区块链将在电商领域发挥更大潜力,推动行业智能化发展。
|
2月前
|
Ubuntu API C++
C++标准库、Windows API及Ubuntu API的综合应用
总之,C++标准库、Windows API和Ubuntu API的综合应用是一项挑战性较大的任务,需要开发者具备跨平台编程的深入知识和丰富经验。通过合理的架构设计和有效的工具选择,可以在不同的操作系统平台上高效地开发和部署应用程序。
157 11
|
3月前
|
人工智能 数据可视化 测试技术
AI 时代 API 自动化测试实战:Postman 断言的核心技巧与实战应用
AI 时代 API 自动化测试实战:Postman 断言的核心技巧与实战应用
536 11
|
5月前
|
存储 机器学习/深度学习 API
Android API Level 到底是什么?和安卓什么关系?应用发布如何知道自己的版本?优雅草卓伊凡
Android API Level 到底是什么?和安卓什么关系?应用发布如何知道自己的版本?优雅草卓伊凡
903 31
Android API Level 到底是什么?和安卓什么关系?应用发布如何知道自己的版本?优雅草卓伊凡
|
3月前
|
安全 API 数据安全/隐私保护
【Azure 环境】Microsoft Graph API实现对Entra ID中应用生成密码的时间天数
本文介绍如何通过 Azure 的 App Management Policy 限制用户在创建 AAD 应用程序的 Client Secret 时设置最长 90 天的有效期。通过 Microsoft Graph API 配置 defaultAppManagementPolicy,可有效控制密码凭据的生命周期,增强安全管理。
143 4