学习心得:控件之Tree Control (仿系统目录树视图)

2023-05-16

 一、几个概念(摘)

1.外壳名字空间:

 在WINDOWS中又叫外壳名字空间(Shell Name Space).外壳名字空间是Windows下的标准文件系统,它大大扩展了Dos文件系统,形成了以“桌面”(Desktop)为根的单一的文件系统树,原有的C盘、D盘等目录树变成“我的电脑”这一外壳名字空间子树的下一级子树,而像“控制面板”、“回收站”、“网上邻居”等应用程序及“打印机”等设备也被虚拟成了外壳名字空间中的节点。另外,与DOS中物理存储只能和文件系统项一一对应这一点不同的是,一个实际目录在外壳名字空间中可以表现为不同的项。例如“我的文档”与“C:/MyDocuments”其实都指向“C:/My Documents”目录,但它们在外壳名字空间中是不同的项。

2. 外壳名字空间下的路径: PIDL

PIDL是一个元素类型为ITEMIDLIST结构的数组,数组中元素的个数是未知的,但紧接着数组末尾的必是一个双字节的零。每个数组元素代表了外壳名字空间树中的一层(即一个文件夹或文件),数组中的前一元素代表的是后一元素的父文件夹。由此可见, PIDL实际上就是指向一块由若干个顺序排列的ITEMIDLIST结构组成、并在最后有一个双字节零的空间的指针。所以PIDL的类型就被Windows定义为ITEMIDLIST结构的指针。

 PIDL亦有“绝对路径”与“相对路径”的概念。表示“相对路径”的PIDL只有一个ITEMIDLIST结构的元素,用于标识相对于父文件夹的“路径”;表示“绝对路径”的PIDL(简称为“绝对PIDL”)有若干个ITEMIDLIST结构的元素,第一个元素表示外壳名字空间根文件夹(“桌面”)下的某一子文件夹A,第二个元素则表示文件夹A下的某一子文件夹B,其余依此类推。这样绝对PIDL就通过保存一条从“桌面”下的直接子文件夹或文件的绝对PIDL与相对PIDL是相同的,而其他的文件夹或文件的相对PIDL就只是其绝对PIDL的最后一部分了。由于所有的PIDL都是从桌面下的某一个子文件夹开始的,所以对于桌面本身来说,它的PIDL数组显然一个元素都没有。这样就只剩下PIDL数组最后的那个双字节的零了。所以,“桌面”的PIDL就是一个16位的零。

二、几个API

1.HRESULT SHGetSpecialFolderLocation(      
    HWND hwndOwner,
    int nFolder,                                 //CSIDL
    LPITEMIDLIST *ppidl               //返回CSIDL所对应的绝对PIDL(输出)
);

2.DWORD_PTR SHGetFileInfo(      
    LPCTSTR pszPath,                      //uFlags含SHGFI_PIDL时为绝对PIDL(输入)
    DWORD dwFileAttributes,          //绝对PIDL所对应文件的 file attribute flags (输出)
    SHFILEINFO *psfi,                       //返回file information
    UINT cbFileInfo,                          //SHFILEINFO结构大                                                                 UINT uFlags                                //指定你所要获取的信息
);       //该函数返回系统HIMAGELIST


说明:

typedef struct _SHFILEINFO {
  HICON hIcon;                                                
  int iIcon;                                                         //图标索引
  DWORD dwAttributes;                                 //文件属性
  TCHAR szDisplayName[MAX_PATH];    // 显示名称 
  TCHAR szTypeName[80];                          //文件类型:一个值对应一个二进制位
} SHFILEINFO;

uFlags  :SHGFI_DISPLAYNAME  | SHGFI_TYPENAME :psfi返回中包含显示名称和文件类型 (其他类推)

3.HRESULT SHGetDesktopFolder(
  IShellFolder** ppshf                          //f返回桌面IShellFolder接口   
);

IShellFolder的几个方法:

(1).BingToObject 获取子文件夹的IShellFolder接口                                                                   

(2).EnumObject获取IEnumIDList ,IEnumIDList ->Next方法获取子文件的相对PIDL(详见MSDN)

(3)GetAttributesOf获取文件属性

注意事项:参数中是绝对PIDL还是相对PIDL。SHGet绝对,IShellFolder相对。PIDL用IMalloc接口开辟空间

三、仿系统目录树

注:本程序在VS2005编译通过(存在小Bug:树节点的加号要展开后才显示,待修改)。

下面是原码

//  BrowseSysTreeDlg.h : 头文件
//

#pragma  once
#include 
" afxcmn.h "


//  CBrowseSysTreeDlg 对话框
class  CBrowseSysTreeDlg :  public  CDialog
... {
// 构造
public:
    CBrowseSysTreeDlg(CWnd
* pParent = NULL);    // 标准构造函数


// 对话框数据
    enum ...{ IDD = IDD_BROWSESYSTREE_DIALOG };

    
protected:
    
virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

//添加
protected:
    HTREEITEM CreateFolderNode(LPITEMIDLIST lpPidl,HTREEITEM hParent);
    BOOL AttachFolders(HTREEITEM hNode);
    
void FreeNode(HTREEITEM hNode);


// 实现
protected:
    HICON                               m_hIcon;
    CTreeCtrl        m_ctrlTree;
    CImageList        m_imageList;
    IMalloc
*        m_pMalloc;

    
// 生成的消息映射函数
    virtual BOOL OnInitDialog();
    afx_msg 
void OnSysCommand(UINT nID, LPARAM lParam);
    afx_msg 
void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    DECLARE_MESSAGE_MAP()

public:
    afx_msg 
void OnNMDblclkSysTree(NMHDR *pNMHDR, LRESULT *pResult);
public:
    afx_msg 
void OnTvnItemexpandingSysTree(NMHDR *pNMHDR, LRESULT *pResult);
public:
    afx_msg 
void OnDestroy();
}
;

 

//  BrowseSysTreeDlg.cpp : 实现文件
//

#include 
" stdafx.h "
#include 
" BrowseSysTree.h "
#include 
" BrowseSysTreeDlg.h "
#include 
" shlobj.h "

#ifdef _DEBUG
#define  new DEBUG_NEW
#endif


//  用于应用程序“关于”菜单项的 CAboutDlg 对话框

class  CAboutDlg :  public  CDialog
... {
public:
    CAboutDlg();

// 对话框数据
    enum ...{ IDD = IDD_ABOUTBOX };

    
protected:
    
virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
    DECLARE_MESSAGE_MAP()
}
;

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
... {
}


void  CAboutDlg::DoDataExchange(CDataExchange *  pDX)
... {
    CDialog::DoDataExchange(pDX);
}


BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()


//  CBrowseSysTreeDlg 对话框

typedef 
struct  _NodeInfo                                      // 节点信息
... {    
    TCHAR            szName[MAX_PATH];    
//显示的名称
    UINT            uIcon;        //图标
    ULONG            dwAttributes;        //属性
    TCHAR            szPath[MAX_PATH];    //路径
    LPITEMIDLIST                        lpPidl;        //PIDL
    WORD            wPidlLen;        //PLID的长度
    IShellFolder*                                             pShellFolder;        //指向该节点的IShellFolder接口
    BOOL            bHasParent;        //是否有父节点    
}
NODEINFO, * LPNODEINFO;

HTREEITEM CBrowseSysTreeDlg::CreateFolderNode(LPITEMIDLIST lpPidl, HTREEITEM hParent)
... {
    LPNODEINFO        lpParentNodeInfo 
= NULL;
    IShellFolder
*    pShellFolder = NULL;
    TCHAR            szName[MAX_PATH];
    BOOL            bRelease 
= FALSE;

    
if (NULL != hParent)        //获取父IShellFolder接口
    ...{
        lpParentNodeInfo 
= (LPNODEINFO) m_ctrlTree.GetItemData(hParent);
        pShellFolder 
= lpParentNodeInfo->pShellFolder;
    }

    
else                    //没有父节点,则取桌面IShellFolder
    ...{
        ::SHGetDesktopFolder(
&pShellFolder);
        bRelease 
= TRUE;
        
if (NULL == pShellFolder)
            
return NULL;
    }

        
    
//获取属性
    ULONG  Attributes = SFGAO_SHARE | SFGAO_FILESYSTEM | 
        SFGAO_LINK 
| SFGAO_HASSUBFOLDER;
    
if(lpParentNodeInfo == NULL || pShellFolder->GetAttributesOf(1,(LPCITEMIDLIST*)&lpPidl, &Attributes) != NOERROR)
    
...{
        Attributes 
= 0;
    }


    
//长度
    WORD        wParentPidlLen = 0;
    LPITEMIDLIST    lpPidlParent;
    
if (NULL != lpParentNodeInfo)
    
...{
        wParentPidlLen 
= lpParentNodeInfo->wPidlLen;
        lpPidlParent  
= lpParentNodeInfo->lpPidl;
    }

    
// 使用IMalloc接口分配新PIDL需要的空间.
    LPITEMIDLIST  lpPidlNew = (LPITEMIDLIST)m_pMalloc->Alloc(lpPidl->mkid.cb + wParentPidlLen + 2);
    
if(wParentPidlLen != 0)
    
...{
        memcpy(lpPidlNew, lpPidlParent, wParentPidlLen);
        memcpy((
char*)lpPidlNew+wParentPidlLen, lpPidl,lpPidl->mkid.cb);
    }

    
else
    
...{
    memcpy(lpPidlNew, lpPidl, lpPidl
->mkid.cb);
    }

    
*(WORD*)((char*)lpPidlNew + wParentPidlLen + lpPidl->mkid.cb) = 0;
    LPITEMIDLIST lpPidlTemp 
= lpPidlNew;

    
//获取显示图标
    SHFILEINFO  shif;
    UINT        uIcon;
    UINT        uSelectedIcon;
    ::SHGetFileInfo((LPCWSTR)lpPidlTemp, 
0&shif, sizeof(shif),
        SHGFI_PIDL 
| SHGFI_SYSICONINDEX);
    uIcon 
= shif.iIcon;
    ::SHGetFileInfo((LPCWSTR)lpPidlTemp, 
0&shif, sizeof(shif),
        SHGFI_PIDL 
| SHGFI_SYSICONINDEX|SHGFI_OPENICON|SHGFI_DISPLAYNAME);
    uSelectedIcon 
= shif.iIcon;

    
//获取路径
    TCHAR        szPath[MAX_PATH];
    ::SHGetPathFromIDList(lpPidlTemp, szPath);
    
    lstrcpy(szName, shif.szDisplayName);              
//取得显示名称

    
//获取节点IShellFolder
    IShellFolder* pShellFolderNew = NULL;
    pShellFolder
->BindToObject(lpPidl, NULL, IID_IShellFolder,(void**&pShellFolderNew);
    
    
//建立新节点
    LPNODEINFO lpNodeInfoNew =    new NODEINFO;
    lpNodeInfoNew
->bHasParent =    (hParent != NULL);
    lpNodeInfoNew
->dwAttributes = Attributes;
    lpNodeInfoNew
->lpPidl = lpPidlNew;
    
if (NULL == hParent)
        lpNodeInfoNew
->pShellFolder = pShellFolder;
    
else
        lpNodeInfoNew
->pShellFolder = pShellFolderNew;
    memcpy(lpNodeInfoNew
->szName, szName, sizeof(szName));
    memcpy(lpNodeInfoNew
->szPath, szPath, sizeof(szPath));
    lpNodeInfoNew
->uIcon = uIcon;
    lpNodeInfoNew
->wPidlLen = wParentPidlLen + lpPidl->mkid.cb;

    
//建立树视图插入结构
    TVINSERTSTRUCT    tvis;
    tvis.item.mask 
= TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE |
        TVIF_STATE 
| TVIF_PARAM;
    
if(Attributes & SFGAO_HASSUBFOLDER) 
    
...{
        tvis.item.mask 
|= TVIF_CHILDREN;
        tvis.item.cChildren 
= I_CHILDRENCALLBACK; 
        
// 使用 I_CHILDRENCALLBACK 值告诉控件,该结点有子结点,但具体的结点还没给出
        
// 当该结点被展开时就会通知父窗口.这时你应该为该结点添加子结点        
    }

    
else
        tvis.item.cChildren 
= 0;
    tvis.item.stateMask 
= TVIS_OVERLAYMASK;  // 指明状态标志包含覆盖图标
    tvis.hInsertAfter = TVI_LAST;
    tvis.hParent 
= hParent;
    tvis.item.iImage 
=uIcon;
    tvis.item.iSelectedImage 
= uSelectedIcon;
    tvis.item.lParam 
= (DWORD)lpNodeInfoNew;
    tvis.item.cchTextMax 
=MAX_PATH;
    tvis.item.pszText 
= szName;
    tvis.item.stateMask 
= TVIS_OVERLAYMASK;
    
// 设置覆盖图标
    if(Attributes & SFGAO_SHARE)      // 共享的
        tvis.item.state = INDEXTOOVERLAYMASK(1);
    
else if(Attributes & SFGAO_LINK)  // 快捷方式
        tvis.item.state = INDEXTOOVERLAYMASK(2);
    
else                              // 其它的
        tvis.item.state = INDEXTOOVERLAYMASK(0);
    HTREEITEM hIns 
= m_ctrlTree.InsertItem(&tvis);  // 插入该结点

    
if(bRelease) //释放桌面IShellFolder
        pShellFolder->Release();

    
return hIns;    
}


BOOL CBrowseSysTreeDlg::AttachFolders(HTREEITEM hNode)
... {
    CWaitCursor   cur; 
// 显示等待光标
    BOOL  bRet = FALSE;
    BOOL bChildren 
= FALSE;
    m_ctrlTree.SetRedraw(FALSE);    
// 禁止控件更新窗口,以免插入时闪烁

    LPNODEINFO  lpfn 
= (LPNODEINFO)m_ctrlTree.GetItemData(hNode);

    IEnumIDList
*    pEnum = NULL;
    
if(lpfn->pShellFolder->EnumObjects(m_hWnd, SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN,
        
&pEnum) == NOERROR)
    
...{
        bChildren 
= FALSE;
        pEnum
->Reset();      
        ULONG   u 
= 1;       
        LPITEMIDLIST   lpidlChild 
= NULL;
        
while(pEnum->Next(1&lpidlChild, &u) == NOERROR)
        
...{
            
// 为每个PIDL创建对应的树结点(包含其中的虚拟文件夹)
            HTREEITEM  hChild = CreateFolderNode(lpidlChild, hNode);
            
if(hChild != NULL)
                bChildren 
= TRUE;
        }

        
// 释放枚举接口
        pEnum->Release();    
        
// 调整父结点的属性
        if (TRUE == bChildren)
        
...{
            TVITEM tvi;
            tvi.mask 
= TVIF_CHILDREN;
            tvi.hItem 
= hNode;
            m_ctrlTree.SetItem(
&tvi); 
        }

    }

    
// 可以更新窗口了
    m_ctrlTree.SetRedraw(TRUE);
    
return TRUE;
}


void  CBrowseSysTreeDlg::FreeNode(HTREEITEM hNode)
... {
    
if (NULL == hNode)
        hNode 
= m_ctrlTree.GetRootItem();
    
else
    
...{
        LPNODEINFO lpNodeInfo 
= (LPNODEINFO)m_ctrlTree.GetItemData(hNode);
        
if (NULL != lpNodeInfo->pShellFolder)
            lpNodeInfo
->pShellFolder->Release();
        m_pMalloc
->Free(lpNodeInfo->lpPidl);
        delete lpNodeInfo;
        hNode 
= m_ctrlTree.GetChildItem(hNode);
    }

    
while (NULL != hNode)
    
...{
        FreeNode(hNode);
        hNode 
= m_ctrlTree.GetNextSiblingItem(hNode);
    }

}


CBrowseSysTreeDlg::CBrowseSysTreeDlg(CWnd
*  pParent  /**/ /*=NULL*/ )
    : CDialog(CBrowseSysTreeDlg::IDD, pParent)
... {
    m_hIcon 
= AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    VERIFY(SHGetMalloc(
&m_pMalloc)==NOERROR);
}


void  CBrowseSysTreeDlg::DoDataExchange(CDataExchange *  pDX)
... {
    CDialog::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_SYS_TREE, m_ctrlTree);
}


BEGIN_MESSAGE_MAP(CBrowseSysTreeDlg, CDialog)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    
// }}AFX_MSG_MAP
    ON_NOTIFY(NM_DBLCLK, IDC_SYS_TREE,  & CBrowseSysTreeDlg::OnNMDblclkSysTree)
    ON_NOTIFY(TVN_ITEMEXPANDING, IDC_SYS_TREE, 
& CBrowseSysTreeDlg::OnTvnItemexpandingSysTree)
    ON_WM_DESTROY()
END_MESSAGE_MAP()


//  CBrowseSysTreeDlg 消息处理程序

BOOL CBrowseSysTreeDlg::OnInitDialog()
... {
    CDialog::OnInitDialog();

    
// 将“关于...”菜单项添加到系统菜单中。

    
// IDM_ABOUTBOX 必须在系统命令范围内。
    ASSERT((IDM_ABOUTBOX & 0xFFF0== IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX 
< 0xF000);

    CMenu
* pSysMenu = GetSystemMenu(NULL);
    
if (pSysMenu != NULL)
    
...{
        CString strAboutMenu;
        strAboutMenu.LoadString(IDS_ABOUTBOX);
        
if (!strAboutMenu.IsEmpty())
        
...{
            pSysMenu
->AppendMenu(MF_SEPARATOR);
            pSysMenu
->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }

    }


    
// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
    
//  执行此操作
    SetIcon(m_hIcon, TRUE);            // 设置大图标
    SetIcon(m_hIcon, NULL);        // 设置小图标

    
// TODO: 在此添加额外的初始化代码
    LPITEMIDLIST    lpPidl;
    HIMAGELIST    hSysImageList 
= NULL;
    SHFILEINFO       shif;
    
    
if (NOERROR != SHGetSpecialFolderLocation(m_hWnd, CSIDL_DESKTOP, &lpPidl))
        
return FALSE;
    hSysImageList 
=(HIMAGELIST) ::SHGetFileInfo((LPCWSTR)lpPidl, 0&shif, sizeof(shif),
            SHGFI_PIDL 
| SHGFI_SMALLICON | SHGFI_SYSICONINDEX);
    
// 设置重叠图标
    
// 设置1号重叠图标对应图标列表中索引为0的图标,这是一个手托,象征被共享的文件夹
    
// 设置2号重叠图标对应图标列表中索引为1的图标,这是一个箭头,象征快捷方式
    
// 设置3号重叠图标对应图标列表中索引为2的图标,这个图标??
    ImageList_SetOverlayImage(hSysImageList, 0,1);
    ImageList_SetOverlayImage(hSysImageList, 
1,2);
    ImageList_SetOverlayImage(hSysImageList, 
2,3);
    m_ctrlTree.SetImageList(CImageList::FromHandle(hSysImageList),TVSIL_NORMAL);

    HTREEITEM hItem 
= CreateFolderNode(lpPidl, NULL);
    AttachFolders(hItem);
    m_ctrlTree.Expand(hItem, TVE_EXPAND);

    
return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}


void  CBrowseSysTreeDlg::OnSysCommand(UINT nID, LPARAM lParam)
... {
    
if ((nID & 0xFFF0== IDM_ABOUTBOX)
    
...{
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }

    
else
    
...{
        CDialog::OnSysCommand(nID, lParam);
    }

}


//  如果向对话框添加最小化按钮,则需要下面的代码
//   来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
//   这将由框架自动完成。

void  CBrowseSysTreeDlg::OnPaint()
... {
    
if (IsIconic())
    
...{
        CPaintDC dc(
this); // 用于绘制的设备上下文

        SendMessage(WM_ICONERASEBKGND, reinterpret_cast
<WPARAM>(dc.GetSafeHdc()), 0);

        
// 使图标在工作矩形中居中
        int cxIcon = GetSystemMetrics(SM_CXICON);
        
int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(
&rect);
        
int x = (rect.Width() - cxIcon + 1/ 2;
        
int y = (rect.Height() - cyIcon + 1/ 2;

        
// 绘制图标
        dc.DrawIcon(x, y, m_hIcon);
    }

    
else
    
...{
        CDialog::OnPaint();
    }

}


// 当用户拖动最小化窗口时系统调用此函数取得光标显示。
//
HCURSOR CBrowseSysTreeDlg::OnQueryDragIcon()
... {
    
return static_cast<HCURSOR>(m_hIcon);
}



void  CBrowseSysTreeDlg::OnNMDblclkSysTree(NMHDR  * pNMHDR, LRESULT  * pResult)
... {
    
// TODO: Add your control notification handler code here
    HTREEITEM hItem = m_ctrlTree.GetSelectedItem();
    
if(m_ctrlTree.GetChildItem(hItem) == NULL)
        AttachFolders(hItem);
    
*pResult = 0;
}


void  CBrowseSysTreeDlg::OnTvnItemexpandingSysTree(NMHDR  * pNMHDR, LRESULT  * pResult)
... {
    LPNMTREEVIEW pNMTreeView 
= reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
    
// TODO: Add your control notification handler code here
    if (pNMTreeView->action == TVE_EXPAND )
        
if(m_ctrlTree.GetChildItem(pNMTreeView->itemNew.hItem) == NULL) 
            AttachFolders(pNMTreeView
->itemNew.hItem);
    
*pResult = 0;
}




void  CBrowseSysTreeDlg::OnDestroy()
... {
    FreeNode(NULL);
    m_pMalloc
->Release();
    delete m_pToolTipCtrl;
    CDialog::OnDestroy();
    
// TODO: 在此处添加消息处理程序代码
}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

学习心得:控件之Tree Control (仿系统目录树视图) 的相关文章

  • UE4开发HTML5遇到的问题

    最近要做一个基于UE4的HTML5仿真项目 xff0c 没真正做过HTML5的小白 xff0c 表示很无所畏惧 首先 xff0c 找一篇UE4下H5的教程 xff0c 简单学习一遍 xff1a 安装 xff0c 环境 xff0c 项目配置
  • redis windows版本编译

    1 redis for windows 下载地址 xff1a https github com tporadowski redis 2 下载后解压 xff0c 用vs2019打开 redis version msvs RedisServer
  • Ubuntu子系统VcXsrv黑屏compiz (core)

    在windows10上安装图形化ubuntu桌面的步骤 xff1a 1 安装 windows 子系统 ubuntu 1 xff09 在启用或关闭Linux 的 Windows子系统 2 xff09 在Microsoft Store中搜索ub
  • 虚幻引擎5.1版本新增功能

    虚幻引擎5 1版本新增功能 虚幻引擎5 1现已发布 xff01 2022年11月15日 其他应用 功能 广播与实况活动 建筑 影视 模拟 汽车与运输 游戏 虚幻引擎5 1 虚拟制片 我们很高兴地宣布 xff0c 虚幻引擎5 1现已推出 在这
  • vc与dev-c++混合编程 动态链接库c函数调用

    上回书说道 xff0c 如何在vc中使用dev c 43 43 中的类 xff0c 这次说一个更简单的问题 xff0c 如何实现vc调用dev c 43 43 的函数 1 打开dev c 43 43 新建工程 xff0c 选择dll xff
  • 【译】你可能不知道的iOS性能优化建议(来自前Apple工程师)

    作者丨凉介 来源丨掘金 链接 xff1a https juejin im post 5e4cfa4f6fb9a07cce74dba7 今天在推特上看到一篇关于性能优化不错的文章 xff0c 是前苹果开发人员写的 xff0c 翻译了一下与大家
  • c++20 concept

    Visual Studio 2019今天发布了16 3版本更新 xff0c 加入了C 43 43 20的concept支持 xff0c 在此记录一下concept的用法 xff1a concept示例 1 限制只能打印int类型 span
  • 解决STM32程序一烧录进去断电或复位即丢失问题

    分享一下个人错误经验 xff0c 之前焊接了一块STM32F103RCT6芯片 xff0c 配了ISP自动下载电路 xff0c 焊接好后上电烧写发现可以烧录进去 xff0c 但是怎么一断电或者一复位怎么程序就没了 xff0c 连一个简单的L
  • 阿里云ECS Windows服务器MySQL无法启动排查的解决方法

    问题现象 Windows主机 xff0c 部署MySQL程序后 xff0c 重启开机无法自动启动 xff0c 同版本在其他服务器运行正常 问题原因 排查Windows系统日志 xff0c 发现有如下报警记录 xff1a Microsoft
  • C规范编辑笔记(三)

    往期文章 xff1a C规范编辑笔记 一 C规范编辑笔记 二 正文 xff1a 继上篇我们的C规范编辑笔记 二 后 xff0c 我们今天开始分享第三篇笔记 xff0c 话不多说 xff0c 我们开始 1 一个 tab 键盘等于四个空格键 我
  • linux免费证书申请教程

    linux免费证书申请教程 直接去阿里云 菜单有个证书服务 进去有个购买证书菜单 选择免费的 然后会提示写个人资料 然后系统生成csr 然后提交审核 查看原文 xff1a http newmiracle cn p 61 963
  • wsl2迁移镜像虚拟磁盘

    wsl2备份 迁移 ubuntu 虚拟磁盘镜像 Author once day Date 2022年11月13日 1 引言 默认的wsl2会把Linux子系统虚拟磁盘文件放在C盘下 xff0c 如果在wsl2里面安装了太多的程序 xff0c
  • Gitlab-标准流程配置[总结多篇文章并实践多次,小白零基础亦可上手]

    谈谈这几天的感受吧 xff1a 公司因为以前的gitlab服务器出了一点问题 xff0c 让半路出家的我来看一下 xff0c 最后说模拟搭建一个gitlab服务器 xff0c 先看一下里面是跑些什么东东 xff0c 需要配置的内容是什么等
  • C语言之数组(数组赋值的三种形式)

    在C语言中 xff0c 对数组进行赋值的三种形式 1 通过循环的形式 即 xff1a 数组名 下标 对数组的元素进行依次赋值 include lt stdio h gt int main int i int a 10 61 0 for i
  • 4招教你创建一个程序代码

    Python 有两种主要的方式来完成你的要求 xff1a 语句和表达式 xff08 函数 算术表达式等 xff09 相信大部分读者已经了解二者的不同 xff0c 但是不管怎样 xff0c 我们还是再来复习一下 语句使用关键字来组成命令 xf
  • 苹果电脑备份和恢复方法。Time Machine

    苹果电脑在Leopard操作系统中自带了一个叫时间机器 Time Machine 的软件 xff0c 用于数据备份和恢复 既然70 80 的用户都不做备份 xff0c 为什么苹果要在Leopard中隆重推出时间机器这个新功能呢 xff1f
  • 进程通讯-Condition

    进程之间通讯 Condition await signal signalAll await 调用await方法的线程释放当前的lock xff0c 当前线程处于等待状态 类似于synchronized的wait 方法 signal 调用si
  • C语言中的位移运算

    位移运算 1 左移 span class hljs comment C左移表达式 span x lt lt k 对于一个n位的操作数x xff0c x lt lt k操作会生成一个值 xff1a x向左移动k位 xff0c 丢弃最高的k位
  • C语言读取文本文件中的矩阵,并将其保存在数组中

    一个简单的C语言读取文本文件操作 xff0c 原数据是3 5的一个矩阵 如下图 xff1a 读取后保存在一个二维数组中 include lt stdio h gt int main int a 3 5 FILE fpread fpread
  • LabVIEW2020 使用“格式化写入字符串”函数将数字转换为字符串

    目录 一 案例 xff1a 二 前面板 三 程序框图 四 验证 一 案例 xff1a 想把数值输入控件中的数字转换成字符串 例如 xff1a 数值输入控件输入30 xff0c 想转换成字符串 34 30 34 二 前面板 1 在前面板窗口上

随机推荐