推荐

定制开发

成功案例

个性化博客互动平台

pic
pic
pic
pic
pic
pic
pic

有好想法, 懒得实现? 请联系 👉

Contact Me

更多

最新

cron, at

  • crontab -e: 无需用户列,普通用户
  • /var/log/cron: 运行日志
  • /etc/crontab: 只有root允许编辑(多了一个用户列);
    编辑后不需要重启!
  • /var/spool/cron/username: 其他用户
# 如分钟填2,表示一小时的第2分钟;
# 单独的'*'表示每一个最小的精度如:每分钟、每周几... 如果是每分钟都填星号

# 分钟  小时 天  月    星期  USER  命令/脚本
#  0    18   *  1-3   2,5  root   NULL :1-3月份,每个星期2,5的下午6点
#  */2  0-2  *  9-12  1-5  root   sh   :9-12月份,周1-周5,0:00到2:00点,每隔两分钟,执行脚本sh
#		2W: 这个月2号的最近工作日,若2号是周六则实际为4号.不能跨月! LW:表示这个月最后一周的工作日!
#		L:  一个月的最后一天
#					6L:  一个月的最后一个星期五;不加表示周六:7!
#					7#3: 本月第3周的周六

at

指定在某个时间点做某事

更多

vs精简安装

目的

  • vs安装冗余度过大,深度占用系统磁盘空间
  • 用最小体积安装vs

步骤

  • 修该 Setup\vs_setup.pdi(locdata.ini为说明文件) 中 [Complete Dependency List]/[Microsoft Visual Studio 2010…] 为:
gencomp15
gencomp784
gencomp16
gencomp387,{12CDA52C-7A8F-4785-8A22-53C87393FEE0}
gencomp384,{12CDA52C-7A8F-4785-8A22-53C87393FEE0}
gencomp43,{5883FD8F-CE63-48BC-8A02-D1633E41F6C3}
gencomp64,{12CDA52C-7A8F-4785-8A22-53C87393FEE0}
gencomp48,{12CDA52C-7A8F-4785-8A22-53C87393FEE0}
vs_setup.dll
gencomp478,{12CDA52C-7A8F-4785-8A22-53C87393FEE0}
gencomp108,{12CDA52C-7A8F-4785-8A22-53C87393FEE0}
gencomp49,{12CDA52C-7A8F-4785-8A22-53C87393FEE0}
  • 修改 Setup\baseline.dat,将 [vs_setup.dll] 中 UseMediaFwlinks=1 后全部删除.(Framwork)
  • 不要删除以下配置项:
  1. Microsoft Visual Studio Macro Tools
  2. Microsoft .NET Framework 4 Extended //NET Framework 4扩展. 不能删除.
  3. Microsoft Visual C++ 开发组件包 Microsoft Visual C++ 2008 Redistributable Microsoft Visual C++ 2008 Redistributable Microsoft Visual C++ 2010 x64 Runtime Microsoft Visual C++ 2010 x86 Runtime Microsoft SQL Server Compact 3.5 SP2 CHS //删除会影响IntelliSence, WCU\SSCE\SSCERuntime_x86-enu.msi Microsoft SQL Server 2008 R2 Data-Tier Application Project //WCU\DAC\DACProjectSystemSetup_enu.msi CrystalReports //WCU\Crystal Reports\CrystalReportsTemplates.msi -->右键-卸载.
  4. Microsoft .NET Framework 4 Client Profile //优化.net客户端的运行. "可以删除,但不建议删除". Microsoft .NET Framework 4 Multi-Targeting Pack //NET跨平台准备的东西. "可以删除,不建议删除".

更多

Registry

Header file
 /**
 * @file      xRegistry.h
 * @date      2012 5.18/周六 14:20:32
 * @author    lei email:[email protected]
 * @copyright GNU Public License.
 * @remark    注册表编辑
 */
#ifndef AFX_XREGISTRY_H__98332335_740E_4E47_8F08_0689B508E55B__INCLUDED_
#define AFX_XREGISTRY_H__98332335_740E_4E47_8F08_0689B508E55B__INCLUDED_

#include <tchar.h>
#include <vector>
#ifdef __AFXWIN_H__
#include <afxtempl.h> //方便使用CStringArray
#endif

class Registry
{
    typedef struct _RegItem {
        TCHAR szItemName[256];
        unsigned char* pValueBuf;
        unsigned long dwValBufLen;
    } RegItem;

public:
    // defroot: HKEY_CURRENT_USER(0x80000001)
    Registry(const TCHAR* lpDefKeyName=_T("Software\\leizi"), void* hDefRootKey=(void*)0x80000001);
    virtual ~Registry();
    bool  SetRootKey(void* hRootKey=(void*)0x80000001);
    bool  OpenKey(const TCHAR* lpRegKey,bool bCreateIfNoExist=false);
    void  GetKey(TCHAR* lpszRegKey/*OUT*/, void* *phRootKey/*OUT*/);
    bool  SetValue(const TCHAR* lpItem,void *pValue,unsigned long dwLen=sizeof(unsigned long),unsigned long dwType=4); //REG_DWORD
    bool  GetValue(const TCHAR* lpItem,void *pValue,unsigned long *pdwLen=NULL,unsigned long *pdwType=NULL) ;
    bool  DelValue(const TCHAR* lpItem) ;
    // exepath为空时表当前程序的全路径
    void  SetAutoRunOnBoot(TCHAR* pStartName,bool bRunFlag,TCHAR* pExeFullPath=NULL);

    // RegItems由使用者释放(free)
    bool  EnumKeyValues(std::vector<RegItem*>& arrValues,const TCHAR* lpRegKey=NULL);
#ifdef UNICODE
    bool  EnumSubkeys(std::vector<std::wstring>& arrSubkeys,const TCHAR* lpRegKey=NULL);
#else
    bool  EnumSubkeys(std::vector<std::string>& arrSubkeys,const TCHAR* lpRegKey=NULL);
#endif
#ifdef __AFXWIN_H__
    bool  EnumKeyValues(CArray<RegItem*,RegItem*> &arrValues,const TCHAR* lpRegKey=NULL);
    bool  EnumSubkeys(CStringArray &arrSubkeys,const TCHAR* lpRegKey=NULL);
#endif
    void  FreeRegItem(void *pItem);
//////////////////////////////////////////////////////////////////////////
private:
    void* m_hKeyOpened ;
    void* m_hRootKey ;
    TCHAR m_szOpenedKey[1024];
};

#endif
source file
#include "stdafx.h"
#include "xRegistry.h"
#include <string>
#include <windows.h>
#include <winreg.h> //using windows.h
#pragma warning (disable: 4996)

Registry::Registry(const TCHAR* lpDefKeyName/*Software/leizi*/, void* hDefRootKey/*HKEY_CURRENT_USER*/)
{
    m_hKeyOpened = NULL;
    SetRootKey(hDefRootKey);
    OpenKey(lpDefKeyName,true);
}

Registry::~Registry()
{
    if (m_hKeyOpened != NULL) {
        RegCloseKey((HKEY)m_hKeyOpened);
        m_hKeyOpened = NULL;
    }
}

bool Registry::SetRootKey(void* hRootKey/*HKEY_CURRENT_USER*/)
{
    if (hRootKey != HKEY_CLASSES_ROOT &&
        hRootKey != HKEY_CURRENT_USER &&
        hRootKey != HKEY_LOCAL_MACHINE &&
        hRootKey != HKEY_USERS)
        return false;
    m_hRootKey = hRootKey;
    return true;
}

int trimleft(TCHAR* s)
{
    if (!s) return -1;
    TCHAR* p = s;
    while (*p && ((_T(' ') == *p) || (_T('\t') == *p) || (_T('\\') == *p))) p++;
    if (*p) _tcscpy(s, p);
    else *s = 0;
    return 0;
}
int trimright(TCHAR* s)
{
    if (!s) return -1;
    TCHAR* p = s + _tcslen(s) - 1;
    while (*p && (p - s) && ((_T(' ') == *p) || (_T('\t') == *p) || (_T('\\') == *p))) p --;
    *(p + 1) = 0;
    if ((_T(' ') == *p) || (_T('\t') == *p) || (_T('\\') == *p)) *p = 0;
    return 0;
}
// if the subkey already exist,this function just like RegOpenKeyEx().
// if the subkey does not exist,we will call RegCreateKey() recursively
bool Registry::OpenKey(const TCHAR* lpRegKey,bool bCreateIfNoExist/*=TRUE*/)
{
    if (!lpRegKey) return false;
    if (m_hKeyOpened != NULL) {
        RegCloseKey((HKEY)m_hKeyOpened);
        m_hKeyOpened = NULL;
    }

    // here,save the opened key handle
    if (ERROR_SUCCESS == RegOpenKeyEx((HKEY)m_hRootKey,lpRegKey,0,KEY_ALL_ACCESS, (HKEY*)&m_hKeyOpened)) {
        _tcscpy(m_szOpenedKey,lpRegKey);
        return true;
    } else { // this subkey does'nt exist in registry
        if (bCreateIfNoExist) {
            TCHAR szPath[MAX_PATH];
            _tcscpy(szPath,lpRegKey);
            trimright(szPath);

#ifdef UNICODE
            std::wstring sReg(szPath);
            sReg.append(_T("\\"));
            std::wstring sTmp;
#else
            std::string sReg(szPath);
            sReg.append(_T("\\"));
            std::string sTmp;
#endif
            int nFind = 0;
            while (1) {
                nFind = sReg.find(_T('\\'),nFind);
                if (nFind < 0) break;
                if (m_hKeyOpened) RegCloseKey((HKEY)m_hKeyOpened);

                sTmp = sReg.substr(0,nFind);
                if (ERROR_SUCCESS == RegOpenKey((HKEY)m_hRootKey,sTmp.c_str(), (HKEY*)&m_hKeyOpened)) {
                    RegCloseKey((HKEY)m_hKeyOpened);
                    m_hKeyOpened = NULL;
                } else {
                    RegCreateKey((HKEY)m_hRootKey,sTmp.c_str(),(HKEY*)&m_hKeyOpened);
                }
                nFind++;
            }
        }

        if (m_hKeyOpened != NULL)
            return true;
    }
    m_hRootKey = HKEY_CURRENT_USER;
    m_hKeyOpened = NULL;
    return false;
}

void Registry::GetKey(TCHAR* lpszRegKey, void**phRootKey)
{
    if (!lpszRegKey || !phRootKey) return;
    *phRootKey = m_hRootKey;
    _tcscpy(lpszRegKey,m_szOpenedKey);
}

// if the value(wait be setted) is a string,the third param is 0 & last param is ignored
bool Registry::SetValue(const TCHAR* lpItem,void* pValue,unsigned long dwLen/*sizeof(DWORD)*/,unsigned long dwType/*=REG_DWORD*/)
{
    unsigned long dwSetType = dwType;
    unsigned long dwSetSize = dwLen;
    if (dwLen == 0) {
        dwSetType = REG_SZ;
        dwSetSize = _tcslen((TCHAR*)pValue);
    }
    if (m_hKeyOpened==NULL || pValue==NULL ||
        ERROR_SUCCESS!=RegSetValueEx((HKEY)m_hKeyOpened,lpItem,0,dwSetType,(CONST BYTE *)pValue,dwSetSize))
        return false;

    return true;
}

bool Registry::GetValue(const TCHAR* lpItem,void *pValue,unsigned long *pdwLen/*=NULL*/,unsigned long *pdwType/*NULL*/)
{
    if (m_hKeyOpened==NULL || pValue==NULL)
        return false;

    unsigned long dwLen=0,dwType=0;
    // first check the item to see if it exist. if it does exist,get the value, type and length
    bool bGetOK = (ERROR_SUCCESS == RegQueryValueEx((HKEY)m_hKeyOpened,lpItem,NULL,&dwType,NULL,&dwLen) &&
                      ERROR_SUCCESS == RegQueryValueEx((HKEY)m_hKeyOpened,lpItem,NULL,&dwType,(BYTE*)pValue,&dwLen));

    if (pdwType != NULL)
        *pdwType = dwType;

    if (pdwLen != NULL)
        *pdwLen = dwLen;

    if (dwType == REG_SZ)
        ((TCHAR *)pValue)[dwLen] = 0;

    return bGetOK;
}

void Registry::FreeRegItem(void *pItem)
{
    if (pItem != NULL) {
        if (((RegItem*)pItem)->pValueBuf != NULL)
            free(((RegItem*)pItem)->pValueBuf);
        free(pItem);
        pItem = NULL;
    }
}

bool Registry::DelValue(const TCHAR* lpItem)
{
    if (m_hKeyOpened==NULL || ERROR_SUCCESS!=RegDeleteValue((HKEY)m_hKeyOpened,lpItem))
        return false;
    return true;
}

#ifdef __AFXWIN_H__
// you are be responsable for freeing the mem which is associate with the first arg
bool Registry::EnumKeyValues(CArray<RegItem*,RegItem*> &arrValues,const TCHAR* lpRegKey/*NULL*/)
{
    if (!lpRegKey)
        return false;

    // 先保存之前打开的键
    TCHAR szOldKeyName[1024] = {0};
    _tcscpy(szOldKeyName,m_szOpenedKey);
    arrValues.RemoveAll();

    // 会改变 m_sOpenedKey
    if (!OpenKey(lpRegKey,false))
        return false;

    TCHAR szItemName[256]  ={0};
    BYTE szItemValue[4096] ={0};
    for (unsigned long i=0; ; i++)
    {
        unsigned long dwType = 0;
        unsigned long dwNameLen   = sizeof(szItemName);
        unsigned long dwValueLen  = sizeof(szItemValue);
        memset(szItemName ,0,sizeof(szItemName));
        memset(szItemValue,0,sizeof(szItemValue));

        if (ERROR_NO_MORE_ITEMS == RegEnumValue((HKEY)m_hKeyOpened,i,szItemName,&dwNameLen,0,&dwType,szItemValue,&dwValueLen))
            break;

        RegItem* lpItem = (RegItem*)calloc(1,sizeof(RegItem));
        _tcscpy(lpItem->szItemName,szItemName);
        lpItem->pValueBuf = (BYTE *)calloc(dwValueLen+1,sizeof(BYTE));
        memcpy(lpItem->pValueBuf,szItemValue,dwValueLen);

        arrValues.Add(lpItem);
    }

    OpenKey(szOldKeyName,false); // 恢复之间打开的key
    return true;
}
#endif

bool Registry::EnumKeyValues( std::vector<RegItem*>& arrValues,const TCHAR* lpRegKey/*=NULL*/)
{
    if (!lpRegKey) return false;

    TCHAR szOldKeyName[1024] = {0};
    _tcscpy(szOldKeyName,m_szOpenedKey);
    arrValues.clear();

    if (!OpenKey(lpRegKey,false))
        return false;

    TCHAR szItemName[256]  ={0};
    BYTE szItemValue[4096] ={0};
    for (unsigned long i=0; ; i++)
    {
        unsigned long dwType = 0;
        unsigned long dwNameLen   = sizeof(szItemName);
        unsigned long dwValueLen  = sizeof(szItemValue);
        memset(szItemName ,0,sizeof(szItemName));
        memset(szItemValue,0,sizeof(szItemValue));

        if (ERROR_NO_MORE_ITEMS == RegEnumValue((HKEY)m_hKeyOpened,i,szItemName,&dwNameLen,0,&dwType,szItemValue,&dwValueLen))
            break;

        RegItem* lpItem = (RegItem*)calloc(1,sizeof(RegItem));
        _tcscpy(lpItem->szItemName,szItemName);
        lpItem->pValueBuf = (BYTE *)calloc(dwValueLen+1,sizeof(BYTE));
        memcpy(lpItem->pValueBuf,szItemValue,dwValueLen);

        arrValues.push_back(lpItem);
    }

    OpenKey(szOldKeyName,false); // rollback
    return true;
}

#ifdef __AFXWIN_H__
bool Registry::EnumSubkeys(CStringArray &arrSubkeys,const TCHAR* lpRegKey/*NULL*/)
{
    if (!lpRegKey) return false;
    if (!OpenKey(lpRegKey,false)) return false;

    TCHAR szKeyName[1024] = {0};
    arrSubkeys.RemoveAll();
    for (unsigned long i=0; ; i++) {
        if (ERROR_NO_MORE_ITEMS == RegEnumKey((HKEY)m_hKeyOpened,i,szKeyName,1024))
            break;
        arrSubkeys.Add(szKeyName);
    }

    OpenKey(m_szOpenedKey,false);
    return true;
}
#endif

#ifdef UNICODE
bool  Registry::EnumSubkeys(std::vector<std::wstring>& arrSubkeys,const TCHAR* lpRegKey/*=NULL*/)
#else
bool  Registry::EnumSubkeys(std::vector<std::string>& arrSubkeys,const TCHAR* lpRegKey/*=NULL*/)
#endif
{
    if (!lpRegKey) return false;

    // 打开注册表
    if (!OpenKey(lpRegKey,false)) return false;

    TCHAR szKeyName[1024] = {0};
    arrSubkeys.clear();
    for (unsigned long i=0; ; i++) {
        if (ERROR_NO_MORE_ITEMS == RegEnumKey((HKEY)m_hKeyOpened,i,szKeyName,1024))
            break;
        arrSubkeys.push_back(szKeyName);
    }

    OpenKey(m_szOpenedKey,false);
    return true;
}

void Registry::SetAutoRunOnBoot(TCHAR *pStartName,bool bEnable,TCHAR *pExeFullPath/*=NULL*/)
{
    HKEY hKey;
    RegOpenKey(HKEY_CURRENT_USER, _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"), &hKey);
    if (!bEnable) {
        RegDeleteValue(hKey, pStartName);
        RegCloseKey(hKey);
        return;
    }
#ifdef UNICODE
    std::wstring sRunPath(pExeFullPath);
#else
    std::string sRunPath(pExeFullPath);
#endif
    TCHAR szAppPathName[MAX_PATH];
    GetModuleFileName(NULL,szAppPathName,MAX_PATH);

    if (sRunPath.empty()) sRunPath = szAppPathName;
    sRunPath.append(_T(" /OnSysStart"));
    const BYTE *pData = (BYTE *)sRunPath.c_str();
    RegSetValueEx(hKey, pStartName, 0, REG_SZ, pData, sRunPath.length());
    RegCloseKey(hKey);
}

更多

Batch

http://www.bathome.net/
隐藏CMD运行窗口

特殊符号

symbolfunction
.在一般命令中当作空格, 在echo命令中当作空行
^字符画某个符号,如: echo ^>
&组合命令,前后没有因果关系;只是为了写在一行; 注意:左侧不要有空格(会被左侧理解成1个字符),右侧空格无所谓!
&&短路特性.前一个执行成功,才执行后面
||前一个执行失败,才执行后面的命令; |表管道
1>nul将语句产生的输出信息屏蔽(或>nul);
2>nul将语句产生的错误信息屏蔽

基本变量

cmd自上而下、逐条处理批处理语句,注意:以下算作1条语句: for if else & || && | ()
这很类似于宏展开,需要延后这种行为?: setlocal EnableDelayedExpansion

更多

MFC

程序启动流程

  • 系统shell加载程序的codedatadll并调用CreateProcess()创建了一个代表你程序的进程
  • 启动第一个线程(PCB,TCB等的创建)

MFC程序启动流程

  • _tWinMain –> AfxWinMain (WINMAIN.CPP 21)
  • AfxWinMain()负责调用CWinApp中的InitApplication(),InitInstance(),Run()等几个主要函数.

WinMain

int WINAPI WinMain(HINSTANCE hInstance/*当前进程句柄*/, HINSTANCE hPrevInstance/*win32:NULL*/, LPSTR cmd/*argv*/, int show/*maxmize...*/) {
	WNDCLASS wc = {0};
	wc.lpszClassName = "ZClass";
	wc.lpfnWndProc = (WNDPROC)ZWindowProc;
	wc.hInstance = hInstance;
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	wc.style = CS_VERDRAW | CS_HREDRAW | CS_NOCLOSE/*禁止标题栏关闭*/;
	if (!RegisterClass(&wc)) { return 0; }

	// CreateWindow会产生WM_CREATE消息,这是窗口过程收到的第1个消息.
	HWND hWndMain = CreateWindow("ZClass", "caption", WS_OVERLAPPEDWINDOW, 0,0,8,8, NULL,NULL, hInstance, NULL);
	ShowWindow(hWndMain, SW_SHOW);
	// emit WM_PAINT, 这是窗口过程的第2个消息!
	UpdateWindow(hWndMain);

	/* 消息循环 */
	MSG msg;
	while (GetMessage(&msg, NULL, 0,0)) { // NULL:获取所有窗口消息;2个0:不过滤
		// 将WM_KEYDOWN翻译成WM_CHAR.
		TranslateMessage(&msg);
		// 将消息转发(OS)到窗口过程!
		DispatchMessage(&msg);
	}

	return 0;
}

Message Map

  • CObject实现了运行时类型识别功能: CObject::IsKindOf()
  • CCmdTarget实现了消息映射
  • CWinThread没有保存消息映射表,故不适用其父类:BEGIN_MESSAGE_MAP(CWinApp, CCmdTarget)
  • declare_message_map这些宏主要是为了使当前消息映射节点加入到消息映射的链表中去.
  • AFX_MSGMAP的类都保存了一张表,记录了"消息-处理函数"之间的对应关系

消息的种类

  • 命令消息: WM_COMAMDN,CCmdTarget; UI对象、菜单、工具栏、按钮
  • 控件消息: WM_NOTIFY,也属于命令消息的一种,是控件发送给父窗口的"通知消息";
  • 标准消息: WM_PAINT,WM_CREATE,WM_CHAR,WM_LBUTTONDOWN..除了上面两种之外的消息. CWnd不需要我们指定函数名!

AFX_MSGMAP

enum AfxSig {  // 消息映射响应函数参数及返回值的类型
	AfxSig_end = 0, // [marks end of message map]
	AfxSig_bD,      // BOOL (CDC*)
	AfxSig_bb,      // BOOL (BOOL)...
};
typedef void (CCmdTarget::*AFX_PMSG)(void);  // CCmdTarget类的void-void成员函数指针类型
struct AFX_MSGMAP_ENTRY {  // 记录(控件上的)消息所对应的"消息处理函数"----消息映射的节点
	UINT nMessage;  // WM_CREATE、WM_COMMAND、WM_MOVE、WM_SIZE、WM_PAINT...
	UINT nCode;     // 控件消息的控制码,如: BN_CLICKED、
	UINT nID;       // 控件ID:IDC_BUTTON1.., 0:标准消息
	UINT nLastID;   // 指定一定范围内的消息被映射,或两者一样
	UINT nSig;      // pfn函数类型.见上方AfxSig的定义
	AFX_PMSG pfn;   // 是一个指向CCmdTarget类非静态成员函数指针
};
struct AFX_MSGMAP { // 消息映射链表,便于从年轻的消息映射节点走访到最老的消息映射节点.
	const AFX_MSGMAP* pBaseMap;  // 记录基类的(baseClass)messageMap成员以便向上走访,基类消息映射表使子类可以走访到基类,类似于虚函数
	const AFX_MSGMAP_ENTRY* lpEntries;  // _messageEntries[]成员的地址
};

DECLARE_MESSAGE_MAP

下面都定义了_AFXDLL版本(动态连接到MFC-dll)

更多

TC

Total Commander

F7 新建文件夹(ctrl+J)

A + F5 压缩(Alt+F6 解压, +backspace 解压到当前文件)
A + UP 访问过的文件夹历史
A + G 打开CMD,定位到当前路径
A + R 打开驱动器选择列表
A + E 删除当前文件/目录
A + U 上一层路径
A + N 下一个驱动器, +S:上一个
A + ., 下/上一个tab
A + [] 前进后退

更多

Tmux

terminal multiplexer

theme: https://github.com/caiogondim/maglev

1个窗口占据一个终端,里面被切分成多个pane;类似于多桌面.

更多