Win32 获取EXE/DLL文件版本信息

CFileVersion.h

#pragma once

#include <windows.h>
#include <string>
#include <tchar.h>

#ifdef _UNICODE
using _tstring = std::wstring;
#else
using _tstring = std::string;
#endif

// 版本号辅助类
class CVersionNumber
{
public:

    // 无参构造
    CVersionNumber();

    // 从版本字符串构造
    CVersionNumber(const _tstring& strVer);

    // 从指定版本号构造
    CVersionNumber(WORD v1, WORD v2, WORD v3, WORD v4);

    // 从版本字符串构造
    CVersionNumber& operator = (const _tstring& strVer);

    //获取版本号字符串
    _tstring GetString() const;

    // 是否为空
    bool IsEmpty() const;

    // 清空
    void Clear();

    // 比较运算重载
    bool operator == (const CVersionNumber& ref);
    bool operator != (const CVersionNumber& ref);
    bool operator < (const CVersionNumber& ref);
    bool operator <= (const CVersionNumber& ref);
    bool operator > (const CVersionNumber& ref);
    bool operator >= (const CVersionNumber& ref);

private:

    // 比较版本号大小
    int _Compare(const CVersionNumber& ref) const;

private:

    WORD m_nVer[4];         //版本号
};

typedef struct _FILE_VERSION_INFO
{
    _tstring strComments;                       //文件注释
    _tstring strInternalName;                   //内部名称
    _tstring strProductName;                    //产品名称
    _tstring strCompanyName;                    //公司名称
    _tstring strLegalCopyright;                 //法律版权
    _tstring strProductVersion;                 //产品版本
    _tstring strFileDescription;                //文件描述
    _tstring strLegalTrademarks;                //合法商标
    _tstring strPrivateBuild;                   //私有构建
    _tstring strFileVersion;                    //文件版本
    _tstring strOriginalFilename;               //原始文件名
    _tstring strSpecialBuild;                   //特殊构建
    _tstring strFileVersionEx;                  //文件版本(从 VS_FIXEDFILEINFO中 获取)
    _tstring strProductVersionEx;               //产品版本(从 VS_FIXEDFILEINFO中 获取)

    CVersionNumber FileVerNumber;               //文件版本号
    CVersionNumber ProductVerNumber;            //产品版本号
}FILE_VERSION_INFO;

class CFileVersion
{
    struct LANGANDCODEPAGE {
        WORD wLanguage;
        WORD wCodePage;

        LANGANDCODEPAGE()
            :
            wLanguage(0),
            wCodePage(0)
        {

        }
    };

public:
    CFileVersion();
    ~CFileVersion();

    CFileVersion operator = (const CFileVersion& r) = delete;
    static FILE_VERSION_INFO GetVersionInfo(const _tstring& strFile);
    static FILE_VERSION_INFO GetCurrentModuleVersionInfo();

public:
    bool LoadFile(const _tstring& strFile);             //加载文件信息
    void Close();

    FILE_VERSION_INFO GetVersionInfo() const;           //整个版本信息

    _tstring GetComments() const;                       //文件注释
    _tstring GetInternalName() const;                   //内部名称
    _tstring GetProductName() const;                    //产品名称
    _tstring GetCompanyName() const;                    //公司名称
    _tstring GetLegalCopyright() const;                 //法律版权
    _tstring GetProductVersion() const;                 //产品版本
    _tstring GetFileDescription() const;                //文件描述
    _tstring GetLegalTrademarks() const;                //合法商标
    _tstring GetPrivateBuild() const;                   //私有版本
    _tstring GetFileVersion() const;                    //文件版本
    _tstring GetOriginalFilename() const;               //原始文件名
    _tstring GetSpecialBuild() const;                   //特别版本
    _tstring GetFileVersionEx() const;                  //文件版本(从 VS_FIXEDFILEINFO中 获取)
    _tstring GetProductVersionEx() const;               //产品版本(从 VS_FIXEDFILEINFO中 获取)
    VS_FIXEDFILEINFO GetFixedFileInfo() const;          //文件的版本信息

private:
    _tstring _QueryInfo(const _tstring& strName) const;
    void _LoadAllInfo();

    LPVOID m_lpVerData;                                 //文件信息数据指针
    LANGANDCODEPAGE m_Translate;                        //语言代码页
    VS_FIXEDFILEINFO m_VsFixedFileInfo;                 //文件的版本信息
    FILE_VERSION_INFO m_VersionInfo;                    //版本信息
};

CFileVersion.cpp

#include "CFileVersion.h"
#include <tchar.h>
#include <strsafe.h>

#pragma comment(lib, "Version.lib")

#pragma pack(push)
#pragma pack(1)
// 包含文件的版本信息。 此信息与语言和代码页无关
// https://learn.microsoft.com/zh-cn/windows/win32/menurc/vs-versioninfo
typedef struct {
    WORD             wLength;       // VS_VERSIONINFO 结构的长度(以字节为单位),此长度不包括在 32 位边界上对齐任何后续版本资源数据的填充
    WORD             wValueLength;  // Value 成员的长度(以字节为单位)
    WORD             wType;         // 版本资源中的数据类型, 1: 资源包含文本数据 0: 版本资源包含二进制数据
    WCHAR            szKey[15];     // Unicode 字符串 L“VS_VERSION_INFO”
    WORD             Padding1;      // 在 32 位边界上对齐 Children 成员所需的任意或零个 WORD
    //VS_FIXEDFILEINFO Value
    //WORD             Padding2
    //WORD             Children
} VS_VERSIONINFO, * PVS_VERSIONINFO;

#pragma pack(pop)

CVersionNumber::CVersionNumber()
    :m_nVer{ 0 }
{
};

CVersionNumber::CVersionNumber(const _tstring& strVer)
    :
    m_nVer{ 0 }
{
    _stscanf_s(strVer.c_str(), _T("%hd.%hd.%hd.%hd"), &m_nVer[0], &m_nVer[1], &m_nVer[2], &m_nVer[3]);
}

CVersionNumber::CVersionNumber(WORD v1, WORD v2, WORD v3, WORD v4)
    :m_nVer{ v1, v2, v3, v4 }
{
}

CVersionNumber& CVersionNumber::operator = (const _tstring& strVer)
{
    _stscanf_s(strVer.c_str(), _T("%hd.%hd.%hd.%hd"), &m_nVer[0], &m_nVer[1], &m_nVer[2], &m_nVer[3]);
    return *this;
}

int CVersionNumber::_Compare(const CVersionNumber& ref) const
{
    for (int i = 0; i < _countof(m_nVer); i++)
    {
        if (m_nVer[i] != ref.m_nVer[i])
        {
            return (m_nVer[i] > ref.m_nVer[i] ? 1 : -1);
        }
    }

    return 0;
}

_tstring CVersionNumber::GetString() const
{
    TCHAR szBuf[MAX_PATH] = { 0 };
    (void)::StringCchPrintf(szBuf, _countof(szBuf), _T("%hd.%hd.%hd.%hd"),
        m_nVer[0],
        m_nVer[1],
        m_nVer[2],
        m_nVer[3]
    );

    return szBuf;
}

bool CVersionNumber::IsEmpty() const
{
    for (const auto& item : m_nVer)
    {
        if (0 != item)
        {
            return false;
        }
    }

    return true;
}

void CVersionNumber::Clear()
{
    for (auto& item : m_nVer)
    {
        item = 0;
    }
}

bool CVersionNumber::operator == (const CVersionNumber& ref)
{
    return _Compare(ref) == 0;
}

bool CVersionNumber::operator != (const CVersionNumber& ref)
{
    return _Compare(ref) != 0;
}

bool CVersionNumber::operator < (const CVersionNumber& ref)
{
    return _Compare(ref) < 0;
}

bool CVersionNumber::operator <= (const CVersionNumber& ref)
{
    return _Compare(ref) <= 0;
}

bool CVersionNumber::operator > (const CVersionNumber& ref)
{
    return _Compare(ref) > 0;
}

bool CVersionNumber::operator >= (const CVersionNumber& ref)
{
    return _Compare(ref) >= 0;
}

CFileVersion::CFileVersion()
    :
    m_lpVerData(NULL)
{
    memset(&m_VsFixedFileInfo, 0, sizeof(m_VsFixedFileInfo));
}

CFileVersion::~CFileVersion()
{
    this->Close();
}

FILE_VERSION_INFO CFileVersion::GetVersionInfo(const _tstring& strFile)
{
    CFileVersion verInfo;
    verInfo.LoadFile(strFile);
    return verInfo.GetVersionInfo();
}

FILE_VERSION_INFO CFileVersion::GetCurrentModuleVersionInfo()
{
    TCHAR szBuf[MAX_PATH] = { 0 };
    ::GetModuleFileName(NULL, szBuf, _countof(szBuf));
    return GetVersionInfo(szBuf);
}

bool CFileVersion::LoadFile(const _tstring& strFile)
{
    PVOID pFsRedirectionOldValue = NULL;
    bool isDisableWow64Fs = false;
    bool isSuccess = false;
    UINT cbTranslate = 0;
    DWORD dwVerSize;

    if (strFile.empty())
    {
        return false;
    }

    this->Close();

    m_VersionInfo = FILE_VERSION_INFO();

    // 禁用文件重定向
    isDisableWow64Fs = ::Wow64DisableWow64FsRedirection(&pFsRedirectionOldValue);

    do
    {
        // 获取版本信息数据大小
        dwVerSize = ::GetFileVersionInfoSize(strFile.c_str(), 0);
        if (0 == dwVerSize)
        {
            break;
        }

        // 分配版本信息缓冲
        m_lpVerData = ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, dwVerSize);
        if (!m_lpVerData)
        {
            break;
        }

        // 获取版本信息
        if (!::GetFileVersionInfo(strFile.c_str(), 0, dwVerSize, m_lpVerData))
        {
            break;
        }

        // 获取语言代码
        LANGANDCODEPAGE* lpTranslate = NULL;
        if (!::VerQueryValue(m_lpVerData, _T("\\VarFileInfo\\Translation"), (LPVOID*)&lpTranslate, &cbTranslate))
        {
            break;
        }

        m_Translate = *lpTranslate;

        // 获取 VS_FIXEDFILEINFO 信息
        PVS_VERSIONINFO lpVersion = (PVS_VERSIONINFO)m_lpVerData;
        if (0 != lpVersion->wValueLength)
        {
            VS_FIXEDFILEINFO* pFixedFileInfo = (VS_FIXEDFILEINFO*)((LPBYTE)lpVersion + sizeof(VS_VERSIONINFO));

            DWORD dwAlign = 4;
            DWORD_PTR dwPadding = ((DWORD_PTR)pFixedFileInfo % dwAlign);
            if (0 != dwPadding)
            {
                pFixedFileInfo = (VS_FIXEDFILEINFO*)((LPBYTE)pFixedFileInfo + (dwAlign - dwPadding));
            }

            m_VsFixedFileInfo = *pFixedFileInfo;
        }

        // 加载所有信息
        _LoadAllInfo();

        isSuccess = true;

    } while (false);

    // 不成功则关闭
    if (!isSuccess)
    {
        this->Close();
    }

    // 恢复文件重定向
    if (isDisableWow64Fs)
    {
        ::Wow64RevertWow64FsRedirection(pFsRedirectionOldValue);
    }

    return isSuccess;
}

void CFileVersion::Close()
{
    if (m_lpVerData)
    {
        HeapFree(::GetProcessHeap(), 0, m_lpVerData);
        m_lpVerData = NULL;
    }
}

void CFileVersion::_LoadAllInfo()
{
    m_VersionInfo.strComments = _QueryInfo(_T("Comments"));
    m_VersionInfo.strInternalName = _QueryInfo(_T("InternalName"));
    m_VersionInfo.strProductName = _QueryInfo(_T("ProductName"));
    m_VersionInfo.strCompanyName = _QueryInfo(_T("CompanyName"));
    m_VersionInfo.strLegalCopyright = _QueryInfo(_T("LegalCopyright"));
    m_VersionInfo.strProductVersion = _QueryInfo(_T("ProductVersion"));
    m_VersionInfo.strFileDescription = _QueryInfo(_T("FileDescription"));
    m_VersionInfo.strLegalTrademarks = _QueryInfo(_T("LegalTrademarks"));
    m_VersionInfo.strPrivateBuild = _QueryInfo(_T("PrivateBuild"));
    m_VersionInfo.strFileVersion = _QueryInfo(_T("FileVersion"));
    m_VersionInfo.strOriginalFilename = _QueryInfo(_T("OriginalFilename"));
    m_VersionInfo.strSpecialBuild = _QueryInfo(_T("SpecialBuild"));
    m_VersionInfo.strFileVersionEx = GetFileVersionEx();
    m_VersionInfo.strProductVersionEx = GetProductVersionEx();

    m_VersionInfo.FileVerNumber = m_VersionInfo.strFileVersionEx.c_str();
    m_VersionInfo.ProductVerNumber = m_VersionInfo.strProductVersionEx.c_str();

}

_tstring CFileVersion::_QueryInfo(const _tstring& strName) const
{
    _tstring strRes;
    TCHAR strQuery[MAX_PATH] = { 0 };
    LPCTSTR lpQueryRes = NULL;
    UINT uQueryCchSize;

    do
    {
        if (!m_lpVerData)
        {
            break;
        }

        (void)::StringCchPrintf(strQuery, _countof(strQuery),
            _T("\\StringFileInfo\\%04x%04x\\%s"),
            m_Translate.wLanguage,
            m_Translate.wCodePage,
            strName.c_str());

        if (!::VerQueryValue(m_lpVerData, strQuery, (LPVOID*)&lpQueryRes, &uQueryCchSize))
        {
            break;
        }

        strRes = lpQueryRes;

    } while (false);

    return strRes;
}

_tstring CFileVersion::GetComments() const
{
    return m_VersionInfo.strComments;
}

_tstring CFileVersion::GetInternalName() const
{
    return m_VersionInfo.strInternalName;
}

_tstring CFileVersion::GetProductName() const
{
    return m_VersionInfo.strProductName;
}

_tstring CFileVersion::GetCompanyName() const
{
    return m_VersionInfo.strCompanyName;
}

_tstring CFileVersion::GetLegalCopyright() const
{
    return m_VersionInfo.strLegalCopyright;
}

_tstring CFileVersion::GetProductVersion() const
{
    return m_VersionInfo.strProductVersion;
}

_tstring CFileVersion::GetFileDescription() const
{
    return m_VersionInfo.strFileDescription;
}

_tstring CFileVersion::GetLegalTrademarks() const
{
    return m_VersionInfo.strLegalTrademarks;
}

_tstring CFileVersion::GetPrivateBuild() const
{
    return m_VersionInfo.strPrivateBuild;
}

_tstring CFileVersion::GetFileVersion() const
{
    return m_VersionInfo.strFileVersion;
}

_tstring CFileVersion::GetOriginalFilename() const
{
    return m_VersionInfo.strOriginalFilename;
}

_tstring CFileVersion::GetSpecialBuild() const
{
    return m_VersionInfo.strSpecialBuild;
}

_tstring CFileVersion::GetFileVersionEx() const
{
    TCHAR szBuf[MAX_PATH] = { 0 };
    (void)::StringCchPrintf(szBuf, _countof(szBuf), _T("%hd.%hd.%hd.%hd"),
        HIWORD(m_VsFixedFileInfo.dwFileVersionMS),
        LOWORD(m_VsFixedFileInfo.dwFileVersionMS),
        HIWORD(m_VsFixedFileInfo.dwFileVersionLS),
        LOWORD(m_VsFixedFileInfo.dwFileVersionLS)
    );

    return szBuf;
}

_tstring CFileVersion::GetProductVersionEx() const
{
    TCHAR szBuf[MAX_PATH] = { 0 };
    (void)::StringCchPrintf(szBuf, _countof(szBuf), _T("%hd.%hd.%hd.%hd"),
        HIWORD(m_VsFixedFileInfo.dwProductVersionMS),
        LOWORD(m_VsFixedFileInfo.dwProductVersionMS),
        HIWORD(m_VsFixedFileInfo.dwProductVersionLS),
        LOWORD(m_VsFixedFileInfo.dwProductVersionLS)
    );

    return szBuf;
}

VS_FIXEDFILEINFO CFileVersion::GetFixedFileInfo() const
{
    return m_VsFixedFileInfo;
}

FILE_VERSION_INFO CFileVersion::GetVersionInfo() const
{
    return m_VersionInfo;
}

main.cpp

#include <locale.h>
#include "Win32Utils/CFileVersion.h"

int _tmain(int argc, LPCTSTR argv[])
{
    setlocale(LC_ALL, "");
    FILE_VERSION_INFO info = CFileVersion::GetCurrentModuleVersionInfo();
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/404918.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Pytorch深度学习开发实践学习】B站刘二大人课程笔记整理lecture06 Logistic回归

【Pytorch深度学习开发实践学习】B站刘二大人课程笔记整理lecture06 Logistic回归 课程网址 Pytorch深度学习实践 部分课件内容&#xff1a; import torchx_data torch.tensor([[1.0],[2.0],[3.0]]) y_data torch.tensor([[0.0],[0.0],[1.0]])class LogisticRegressionModel(…

PYTHON-使用正则表达式进行模式匹配

目录 Python 正则表达式Finding Patterns of Text Without Regular ExpressionsFinding Patterns of Text with Regular ExpressionsCreating Regex ObjectsMatching Regex ObjectsReview of Regular Expression MatchingMore Pattern Matching with Regular ExpressionsGroupi…

【数据结构】排序(2)

目录 一、快速排序&#xff1a; 1、hoare(霍尔)版本&#xff1a; 2、挖坑法&#xff1a; 3、前后指针法&#xff1a; 4、非递归实现快速排序&#xff1a; 二、归并排序&#xff1a; 1、递归实现归并排序&#xff1a; 2、非递归实现归并排序&#xff1a; 三、排序算法…

白酒:陈酿过程中的氧化还原反应与酒体老化

在云仓酒庄豪迈白酒的陈酿过程中&#xff0c;氧化还原反应与酒体老化是影响酒品质的重要因素。陈酿是白酒生产中不可或缺的一环&#xff0c;通过陈酿可以使酒体更加协调、口感更加醇厚。而氧化还原反应作为陈酿过程中的重要化学反应&#xff0c;对酒体的老化起着关键作用。 首先…

Python列表:灵活多变的数据结构

文章目录 一、列表1.创建列表2.访问列表元素3.修改列表元素4.添加元素5.删除元素 二、列表脚本操作符1.连接运算符 2.重复运算符 * 三、列表函数&方法1.函数1.1 len() 函数1.2 max() 函数1.3 min() 函数1.4 sum() 函数1.5 list() 函数 2.方法2.1 append() 方法2.2 extend()…

nginx 具体介绍

一&#xff0c;nginx 介绍 &#xff08;一&#xff09;nginx 与apache 1&#xff0c; Apache event 模型 相对于 prefork 模式 可以同时处理更多的请求 相对于 worker 模式 解决了keepalive场景下&#xff0c;长期被占用的线程的资源浪费问题 因为有监听线程&#…

江科大STM32学习笔记(上)

STM32F103xx 前言外设篇GPIO输出GPIO位结构GPIO模式外设的GPIO配置查看实战1&#xff1a; 如何进行基本的GPIO输入输出 OLED显示屏及调试Keil的调试模式演示 EXTI外部中断NVIC基本结构EXTI结构代码实战2&#xff1a;如何使用中断和对射式红外传感器&#xff06;旋转编码器 TIM&…

嵌入式基础准备 | 初识嵌入式AI

1、嵌入式设备发展 1、第一代&#xff1a;2000年开始 单片机 最简单的电子产品 遥控器&#xff0c;烟雾报警器 裸机编程 RTOS 智能音箱&#xff0c;路由器&#xff0c;摄像头 实时性要求高的操作系统&#xff08;马上请求&#xff0c;马上响应&#xff09; 2、第二代&#xf…

程序媛的mac修炼手册-- 小白入门Java篇

最近因为要用CiteSpace做文献综述&#xff0c;间接接触Java了。所以&#xff0c;继Python、C之后&#xff0c;又要涉猎Java了。刺激&#xff01;&#xff01; 由于CiteSpace与Java要求版本高度匹配&#xff0c;有个匹配详情明天为大家讲解。总之&#xff0c;我的Java之旅开始于…

华清远见作业第四十一天——Qt(第三天)

思维导图&#xff1a; 编程 完善对话框&#xff0c;点击登录对话框&#xff0c;如果账号和密码匹配&#xff0c;则弹出信息对话框&#xff0c;给出提示”登录成功“&#xff0c;提供一个Ok按钮&#xff0c;用户点击Ok后&#xff0c;关闭登录界面&#xff0c;跳转到其他界面 如…

喜报 | 通付盾再次入选“苏州市网络和数据安全技术支撑单位”

近日&#xff0c;为加强苏州市网络和数据安全技术服务体系建设&#xff0c;提升网络和数据安全保障水平&#xff0c;苏州市互联网信息办公室、苏州市互联网协会发布了2024-2025年度苏州市网络和数据安全技术支撑单位名单。经过自主申报、资料审核、专家评审等环节&#xff0c;江…

「C语言进阶1」动态内存分配

目录 一、动态内存分配是什么&#xff1f; 二、为什么需要动态内存分配&#xff1f; 三、怎么进行动态内存分配&#xff1f; 1. malloc 2. calloc 3. realloc a. realloc功能解析 b. 内存泄漏和内存块被截断问题 c. 总结 4. free 四、使用动态内存分配常见的问题 【面试题】 一…

线代:认识行列式、矩阵和向量

本文主要参考的视频教程如下&#xff1a; 8小时学完线代【中国大学MOOC*小元老师】线性代数速学_哔哩哔哩_bilibili 另外这个视频可以作为补充&#xff1a; 【考研数学 线性代数 基础课】—全集_哔哩哔哩_bilibili 行列式的概念和定义 一般会由方程组来引出行列式 比如一个二阶…

IO进程线程的通信操作

1.编程实现互斥机制 程序代码&#xff1a; 1 #include<myhead.h>2 int num520;//临界资源3 //1.创建一个互斥锁变量4 pthread_mutex_t mutex;//定义一个pthread_mutex_t类型的变量5 //定义任务1函数6 void *task1(void *arg)7 {8 printf("不畏过去\n");9 …

java面试题之mybatis篇

什么是ORM&#xff1f; ORM&#xff08;Object/Relational Mapping&#xff09;即对象关系映射&#xff0c;是一种数据持久化技术。它在对象模型和关系型数据库直接建立起对应关系&#xff0c;并且提供一种机制&#xff0c;通过JavaBean对象去操作数据库表的数据。 MyBatis通过…

驾校预约|驾校预约小程序|基于微信小程序的驾校预约平台设计与实现(源码+数据库+文档)

驾校预约小程序目录 目录 基于微信小程序的驾校预约平台设计与实现 一、前言 二、系统功能设计 三、系统实现 1、用户​微信端功能模块​ 2、管理员服务端功能模块 &#xff08;1&#xff09;学员信息管理 &#xff08;2&#xff09; 教练信息管理 &#xff08;3&…

Django学习笔记-HTML实现服务器图片的下载

1.index编写代码,跳转下载页面 2.创建download界面 3.编写download路由 4.创建download函数 1).如果请求的方法是GET&#xff0c;imglist变量存储从models.imgModel模型中获取的所有对象,创建字典ctx,使用render函数来渲染download.htm 2).如果请求的方法是POST,获取要下载的文…

Spring学习上下文【ConfigurableApplicationContext】

话不多说&#xff0c;先上图&#xff1a; ConfigurableApplicationContext是Spring框架中的一个接口&#xff0c;它继承了ApplicationContext接口&#xff0c;并扩展了一些额外的方法&#xff0c;用于允许应用程序在运行时动态地修改和管理应用上下文。ConfigurableApplicati…

【js】无限虚拟列表的原理及实现

什么是虚拟列表 虚拟列表是长列表按需显示思路的一种实现&#xff0c;即虚拟列表是一种根据滚动容器元素的可视区域来渲染长列表数据中某一个部分数据的技术。 简而言之&#xff0c;虚拟列表指的就是「可视区域渲染」的列表。有三个概念需要了解一下&#xff1a; 视口容器元…

KDD 2023 图神经网络方向论文总结

ACM SIGKDD&#xff08;国际数据挖掘与知识发现大会&#xff0c;KDD&#xff09;是数据挖掘领域历史最悠久、规模最大的国际顶级学术会议&#xff0c;也是首个引入大数据、数据科学、预测分析、众包等概念的会议。今年&#xff0c;第29届 KDD 大会在美国加州长滩举行&#xff0…