https://github.com/zeromq/libzmq
http://zeromq.org/intro:get-the-software
http://zeromq.org/distro:microsoft-windows
曹景游
首先检查一下电脑里已经安装的ImageMagick版本,输入:
convert -version
除非你想要把对另外的图像格式的支持或升级一个较新的版本,否则你可能不需要ImageMagick的源码安装。 你也可以安装预先编译二进位版本。然而,如果你仍然想要从源码安装,请选择一个平台,Unix 或 Windows。
在源码安装之前,你可能要回顾ImageMagick的最近变化。
ImageMagick 在多种操作系统 Unix 和包括 Linux,Solaris,FreeBSD,Mac 操作系统 X 和其它的类 Unix 一样的操作系统上建立。 它需要一个编译器,几乎所有现代的 Unix 系统都会有一个。 可以从 ftp.imagemagick.org 或它的镜像网站下载 ImageMagick.tar.gz 并用这个指令解压缩:
gunzip -c ImageMagick.tar.gz | tar xvf -
然后配置编译ImageMagick:
cd ImageMagick-6.?.?
./configure
make
如果配置编译的ImageMagick没有出现错误,要把它安装到系统里,你需要使用管理员权限,输入:
make install
最后,可以测试一下ImageMagick的工作效果:
/usr/local/bin/convert logo: logo.gif
恭喜你,你已经有ImageMagick的工作环境了,你可以使用ImageMagick加入新图片,生成缩略图,组合图片……
还可以使用其它程序接口 C, C++, Perl, 和其它程序。
上述的指导将会使很多的 ImageMagick 使用者满意,但是我们怀疑一些将会有另外的问题或问题考虑。
如果 ImageMagick 无法配置或编译,或如果你没有管理员权限或没有将ImageMagick安装到默认目录
请点这里了解更多……
Windows系统下ImageMagick源码安装需要Microsoft Visual Studio IDE。
有的用户也成功的用Borland C++编译。如果你没有编译器,你可以安装二进位发布版本
从ftp.imagemagick.org或它的镜像网站下载 ImageMagick-windows.zip 文件,然后用 WinZip 解压缩。
然后运行你的Visual Studio IDE选择Open->Project从ImageMagick-6.?.?/VisualMagick/configure文件夹里选择configure.dsp文件 Build->Build编译并执行。
可以通过以下方法获取图片信息
CString ExeCmd(CString pszCmd)
{
//创建匿名管道
SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
HANDLE hRead, hWrite;
if (!CreatePipe(&hRead, &hWrite, &sa, 0))
{
return _T("");
}
//设置命令行进程启动信息(以隐藏方式启动命令并定位其输出到hWrite)
STARTUPINFO si = {sizeof(STARTUPINFO)};
GetStartupInfo(&si);
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.wShowWindow = SW_HIDE;
si.hStdError = hWrite;
si.hStdOutput = hWrite;
//启动命令行
PROCESS_INFORMATION pi;
if (!CreateProcess(NULL, (LPWSTR)(LPCWSTR)pszCmd, NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi))
{
return _T("");
}
//立即关闭hWrite
CloseHandle(hWrite);
//读取命令行返回值
char buff[1024] = {0};
DWORD dwRead = 0;
while (ReadFile(hRead, buff, 1024, &dwRead, NULL))
{
}
CString strRet(buff);
CloseHandle(hRead);
return strRet;
}
使用:
ExeCmd(_T("ping baidu.com"));
ExeCmd(_T("identify -format "%[colorspace]" E:\\P70306-163226.jpg"));
C++程序员应该看一下MagickCMD.cpp命令行实用工具的示例调用该对象的C++。对象变量列表的大小需要BSTR的模仿命令行argc,argv风格的COM组件的调用约定,这是更复杂的C++中然后在VB或VBS。
#include <iostream>
#include <atlbase.h>
#include <atlsafe.h>
#import "ImageMagickObject.tlb" no_namespace
using namespace std;
typedef enum
{
cmdUnknown,
cmdCompare,
cmdComposite,
cmdConvert,
cmdIdentify,
cmdMogrify,
cmdMontage,
cmdStream
} CommandType;
static struct
Commands
{
char
*name;
CommandType
code;
} Commands[] =
{
{ "", cmdUnknown },
{ "compare", cmdCompare },
{ "composite", cmdComposite },
{ "convert", cmdConvert },
{ "identify", cmdIdentify },
{ "mogrify", cmdMogrify },
{ "montage", cmdMontage },
{ "stream", cmdStream }
};
int main(int argc, char* argv[])
{
int
index,
status = 0;
char
*name;
CommandType
code = cmdUnknown;
// We must have at least a command, input, and output
if (argc < 4)
return 0;
index = 1;
while ((name = Commands[index].name))
{
if (stricmp(name,argv[1]) == 0)
{
code = Commands[index].code;
break;
}
index++;
}
if (code == cmdUnknown)
return 0;
CoInitialize(NULL);
try
{
CComVariant
result;
SAFEARRAY
**ppsa = (SAFEARRAY**) NULL;
IMagickImagePtr pImageProc(__uuidof(MagickImage));
if (pImageProc == NULL)
status = 1;
else
{
{
// Define the array bound structure
CComSafeArrayBound bound[1];
bound[0].SetCount(argc-2);
bound[0].SetLowerBound(0);
CComSafeArray<VARIANT> args(bound);
if( !args )
status = 2;
else
{
for(index = 2; index < argc; ++index)
{
CComVariant vt(argv[index]);
HRESULT hr = vt.Detach(&args[index-2]);
}
switch(code)
{
case cmdCompare:
result = pImageProc->Compare(args.GetSafeArrayPtr());
break;
case cmdComposite:
result = pImageProc->Composite(args.GetSafeArrayPtr());
break;
case cmdConvert:
result = pImageProc->Convert(args.GetSafeArrayPtr());
break;
case cmdIdentify:
result = pImageProc->Identify(args.GetSafeArrayPtr());
break;
case cmdMogrify:
result = pImageProc->Mogrify(args.GetSafeArrayPtr());
break;
case cmdMontage:
result = pImageProc->Montage(args.GetSafeArrayPtr());
break;
case cmdStream:
result = pImageProc->Stream(args.GetSafeArrayPtr());
break;
}
pImageProc.Release();
}
}
}
}
catch(_com_error ex)
{
HRESULT
res = ex.Error();
_bstr_t
desc = ex.Description();
printf("Error %s (0x%08x)\n",(char *)desc,res);
status = 4;
}
CoUninitialize();
return status;
}
Magick ++为标准模板库(STL)提供集成支持,以便可以使用强大的可用容器(例如deque, vector,list和map)来编写与PERL和PerlMagick类似的程序。提供了与ImageMagick的列表样式操作的STL兼容模板版本,以便可以对存储在STL容器中的多个图像执行操作。
Magick ++作为ImageMagick 源代码的一部分包含在内,可以通过HTTP 或GitHub进行检索。
它读取图像,裁剪图像,并以PNG图像格式将其写入磁盘:
#include <Magick++.h>
#include <iostream>
using namespace std;
using namespace Magick;
int main(int argc,char **argv)
{
InitializeMagick(*argv);
// Construct the image object. Seperating image construction from the
// the read operation ensures that a failure to read the image file
// doesn't render the image object useless.
Image image;
try {
// Read a file into image object
image.read( "logo:" );
// Crop the image to specified size (width, height, xOffset, yOffset)
image.crop( Geometry(100,100, 100, 100) );
// Write the image to a file
image.write( "logo.png" );
}
catch( Exception &error_ )
{
cout << "Caught exception: " << error_.what() << endl;
return 1;
}
return 0;
}
ImageMagick 不仅仅是一个图像查看器,它还提供了大量的图像编辑工具和选项。
如何在 ImageMagick 中使用 display 命令和其他命令行工具。
假设你有一个目录,其中有很多想要查看的图像。使用以下命令开始
cd Pictures
display *.JPG
这将按照字母数字顺序顺序加载你的 JPG 文件,每张放在一个简单的窗口中。左键单击图像可以打开一个简单的独立菜单(ImageMagick 中唯一的 GUI 功能)。
例如,如果我显示的数码相片目录中的图像大于我的屏幕尺寸,我不用在显示后单独调整大小,我可以指定:
display -resize 50% *.JPG
-monochrome,将图像转换为黑白(不是灰度),还有 -colors,你可以指定在图像中使用多少种颜色
display -resize 50% -monochrome *.JPG
display -resize 50% -colors 8 *.JPG
第一个命令将单个文件(DSC_0001)从 JPG 转换为 PNG 格式,而不更改原始文件。第二个将对目录中的所有 BMP 图像执行此操作。
convert DSC_0001.JPG dsc0001.png
convert *.bmp *.png
如果要查看 ImageMagick 可以使用的格式,请输入:
identify -list format
convert 命令来处理图像的有趣方法。以下是此命令的一般格式:
convert inputfilename [options] outputfilename
-monochrome 选项没有关联的设置,但 -charcoal 变量需要一个相关因子。根据我的经验,它需要一个小的数字(甚至小于 1)来实现类似于炭笔绘画的东西,否则你会得到很大的黑色斑点。即使如此,图像中的尖锐边缘也是非常明显的,与炭笔绘画不同。
convert monochrome_source.jpg -monochrome monochrome_example.jpg
convert DSC_0008.jpg -charcoal 1.2 charcoal_example.jpg
convert DSC_0032.JPG -edge 3 edge_demo.jpg
convert DSC_0032.JPG -colors 4 reduced4_demo.jpg
convert DSC_0032.JPG -colors 4 -edge 3 reduced+edge_demo.jpg
-canny 选项提供了另外一个惊喜。这是另一种边缘检测器,称为“多阶算法”。单独使用 -canny 可以产生基本黑色的图像和一些白线。我后面跟着一个 -negate 选项:
convert DSC_0049.jpg -canny 0x1 -negate canny_egret.jpg
convert DSC_0023.jpg -canny 0x1 -negate canny_ship.jpg
蒙太奇
montage -label %f DSC_0008.jpg charcoal_example.jpg -geometry +10+10 -resize 25% -shadow -title 'charcoal demo' charcoal_demo.jpg
-label 选项会在每个图像下方标记它的文件名(%f)。不用 -geometry 选项,所有的图像将是缩略图大小(120 像素宽),+10+10 负责边框大小。接下来,我调整了整个最终组合的大小(-resize 25%),并添加了一个阴影(没有设置,因此是默认值),最后为这次 montage 操作创建了一个标题(-title)。
假如我想查看最近一年的图片,我便可以在命令行中键入下面的 display 命令:
display -resize 35% 2017/*/*/*.JPG
现在假如我想查看某张图片,但我不确定我是在 2016 年的上半年还是在 2017 的上半年拍摄的,那么我便可以使用下面的命令来找到它:
display -resize 35% 201[6-7]/0[1-6]/*/*.JPG
它可以将一系列的图片缩略图放在一张图片中,这样就会非常有用。例如可以使用下面的命令来完成上面的任务:
montage -label %d/%f -title 2017 -tile 5x -resize 10% -geometry +4+4 2017/0[1-4]/*/*.JPG 2017JanApr.jpg
从左到右,这个命令以标签开头,标签的形式是包含文件名(%f)和以 / 分割的目录(%d)结构,接着这个命令以目录的名称(2017)来作为标题,然后将图片排成 5 列,每个图片缩放为 10% (这个参数可以很好地匹配我的屏幕)。geometry 的设定将在每张图片的四周留白,最后指定那些图片要包括到这张合成图片中,以及一个合适的文件名称(2017JanApr.jpg)。现在图片 2017JanApr.jpg 便可以成为一个索引,使得我可以不时地使用它来查看这个时期的所有图片。
给图片加水印
gm composite -gravity southeast -dissolve 50 "x:\waterPage.jpg" "x:\t1.jpg" "x:t2_watermark.jpg"
GraphicsMagick-1.3.5-Q8版本会去掉图片的ICC信息,使用GraphicsMagick-1.3.30-Q16版本即可
输出ICC信息:
gm convert "x:\t1.jpg" "x:\exifdata.app1"
进程间通讯的四种方式:剪贴板、匿名管道、命名管道和邮槽
//设置剪切板内容
CString str;
this->GetDlgItemText(IDC_EDIT1, str);
OpenClipboard();//打开剪贴板查看,并防止其他应用程序修改剪贴板的内容.
EmptyClipboard();//EmptyClipboard Function该函数清空剪切板并释放剪切板内数据的句柄。函数在之后会将剪切板的所有权指派给当前打开剪切板的窗口。
HANDLE hclip = GlobalAlloc(GMEM_MOVEABLE, str.GetLength() + 1);
char *pBuf = (char *)GlobalLock(hclip);
//WideCharToMultiByte()//字形转换
strcpy(pBuf, str.GetBuffer());
//memcpy(pBuf, str.GetBuffer(), GetLength()+2);
GlobalLock(hclip);
SetClipboardData(CF_TEXT, hclip);//SetClipboardData是把指定数据按照指定格式放入剪切板中
CloseClipboard();//关闭剪贴板,这使其他窗口或程序能访问剪贴板。
//获得剪切板内容
OpenClipboard();
if (IsClipboardFormatAvailable(CF_TEXT))//是以NULL结尾的ASCII字符的文本格式,则该函数返回值为true,否则为false。
{
HANDLE hclip;
hclip = GetClipboardData(CF_TEXT);//用来打开剪贴板并获取剪贴板内容。
char *pBuf = (char *)GlobalLock(hclip);
GlobalUnlock(hclip);
CString STR;
SetDlgItemText(IDC_EDIT1, pBuf);
}
CloseClipboard();
//参考:
//http://bbs.kechuang.org/t/72605
//http://www.cnblogs.com/BoyXiao/archive/2010/12/25/1916677.html
//父进程实现
//创建匿名管道
SECURITY_ATTRIBUTES sa;
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
if (!CreatePipe(&m_hRead, &m_hWrite, &sa, 0))
{
AfxMessageBox(_T("create pipe error"));
}
//子进程的创建
STARTUPINFO sui;
PROCESS_INFORMATION pi;
sui.cb = sizeof(STARTUPINFO);
ZeroMemory(&sui, sizeof(STARTUPINFO));
sui.dwFlags = STARTF_USESTDHANDLES;
sui.hStdInput = m_hRead;
sui.hStdOutput = m_hWrite;
sui.hStdError = GetStdHandle(STD_ERROR_HANDLE);
if (!CreateProcess(_T("../debug/child.exe"), NULL , NULL, NULL, TRUE, 0, NULL, NULL, &sui, &pi ))
{
AfxMessageBox(_T("创建子进程错误"));
}
//关闭进程 线程计数器
if (pi.hThread)
{
CloseHandle(pi.hThread);
}
if (pi.hProcess)
{
CloseHandle(pi.hProcess);
}
//发送数据
char buf[] = "this is pipe server";
DWORD dwWrite = 0;
if (!WriteFile(m_hWrite, buf, strlen(buf) + 1, &dwWrite, NULL))
{
AfxMessageBox(_T("write error parent"));
}
//接收数据
char buf[128] = {0};
DWORD dwRead = 0;
ReadFile(m_hRead, buf, sizeof(buf), &dwRead, NULL );
//子进程实现
//获取继承自父进程的匿名管道读写句柄
m_hRead = GetStdHandle(STD_INPUT_HANDLE);
m_hWrite = GetStdHandle(STD_OUTPUT_HANDLE);
//写入数据
char buf[] = "this is pipe child";
DWORD dwWrite = 0;
if (!WriteFile(m_hWrite, buf, strlen(buf) + 1, &dwWrite, NULL))
{
AfxMessageBox(_T("write error child"));
}
//读取数据
char buf[128] = {0};
DWORD dwRead = 0;
ReadFile(m_hRead, buf, sizeof(buf), &dwRead, NULL );
//参考
http://www.cnblogs.com/BoyXiao/archive/2011/01/01/1923828.html
//服务端
//创建命名管
m_hPipe = CreateNamedPipe(_T("\\\\.\\pipe\\mypipe"), PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, /*OVERLAPPED是为了满足异步实现非阻塞的工能,当连接上用事件通知*/
0, 1, 1024, 1024, 0, NULL);
if (m_hPipe == INVALID_HANDLE_VALUE)
{
return;
}
//创建事件
HANDLE hEvent;
hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!hEvent)
{
MessageBox(_T("创建事件对象失败!"));
CloseHandle(m_hPipe);
m_hPipe = NULL;
return;
}
OVERLAPPED ovlap;
ZeroMemory(&ovlap, sizeof(OVERLAPPED));
ovlap.hEvent = hEvent;
if (!ConnectNamedPipe(m_hPipe, &ovlap))
{
if (ERROR_IO_PENDING != GetLastError())
{
MessageBox(_T("等待客户连接失败!"));
CloseHandle(m_hPipe);
CloseHandle(hEvent);
m_hPipe = NULL;
return;
}
}
//重叠操作
if (WAIT_FAILED == WaitForSingleObject(hEvent, INFINITE))
{
MessageBox(_T("等待对象失败!"));
CloseHandle(m_hPipe);
CloseHandle(hEvent);
m_hPipe = NULL;
return;
}
CloseHandle(hEvent);
//写数据
char buf[] = "this is named pipe server";
DWORD dwWrite = 0;
WriteFile(m_hPipe, buf, strlen(buf) + 1, &dwWrite, NULL);
//读数据
char buf[128] = {0};
DWORD dwRead = 0;
ReadFile(m_hPipe, buf, 128, &dwRead, NULL);
//客户端
//连接命名管道
if (!WaitNamedPipe(_T("\\\\.\\pipe\\mypipe"), NMPWAIT_WAIT_FOREVER))
{
return;
}
m_hPipe = CreateFile(_T("\\\\.\\pipe\\mypipe"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
//写入数据
char buf[] = "this is named pipe client";
DWORD dwWrite = 0;
WriteFile(m_hPipe, buf, strlen(buf) + 1, &dwWrite, NULL);
//读取数据
char buf[128] = {0};
DWORD dwRead = 0;
ReadFile(m_hPipe, buf, 128, &dwRead, NULL);
//参考
//http://www.cnblogs.com/BoyXiao/archive/2011/01/02/1924188.html
//服务端
HANDLE hMail = CreateMailslot(_T("\\\\.\\mailslot\\myslot"), 424, MAILSLOT_WAIT_FOREVER, NULL);
if (hMail == INVALID_HANDLE_VALUE)
{
int nRes = GetLastError();
CString str;
str.Format(_T("%s"), nRes);
AfxMessageBox(str);
return;
}
char buf[424] = {0};
DWORD dwSize = 0;
ReadFile(hMail, buf, 424, &dwSize, NULL);
CString str;
str = buf;
MessageBox(str);
//客户端
HANDLE hMailslot;
hMailslot = CreateFile(_T("\\\\.\\mailslot\\myslot"), GENERIC_WRITE,
FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == hMailslot)
{
MessageBox(_T("打开邮槽失败!"));
return;
}
char buf[] = "this is mail slot client";
DWORD dwSize = 0;
if (!WriteFile(hMailslot, buf, strlen(buf) + 1, &dwSize, NULL))
{
MessageBox(_T("写入邮槽失败!"));
}
//http://blog.csdn.net/kylin_p/article/details/5146797
//http://www.cnblogs.com/BoyXiao/archive/2010/12/31/1923462.html
//http://www.cnblogs.com/jzincnblogs/p/5192654.html
#define WM_SHOWTASK (WM_USER + 1)
void CTestDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
//增加关闭时最小化到托盘的函数
if (nID == SC_CLOSE) //SC_MINIMIZE
{
ToTray();
return;
}
CDialog::OnSysCommand(nID, lParam);
}
}
BEGIN_MESSAGE_MAP(CTestDlg, CDialog)
ON_MESSAGE(WM_SHOWTASK, OnShowTask)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//在托盘区添加图标 最小化到托盘函数
void ToTray(void);
void CTestDlg::ToTray(void)
{
NOTIFYICONDATA nid;
nid.cbSize = (DWORD)sizeof(NOTIFYICONDATA);
nid.hWnd = this->m_hWnd;
nid.uID = IDR_MAINFRAME;
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
nid.uCallbackMessage = WM_SHOWTASK;//自定义的消息名称
nid.hIcon = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME));
wcscpy_s(nid.szTip, _T("***程序"));//信息提示条
Shell_NotifyIcon(NIM_ADD, &nid);//在托盘区添加图标
ShowWindow(SW_HIDE);//隐藏主窗口
}
//恢复界面函数
afx_msg LRESULT OnShowTask(WPARAM wParam, LPARAM lParam);
//托盘事件
LRESULT CTestDlg::OnShowTask(WPARAM wParam, LPARAM lParam)
{
if (wParam != IDR_MAINFRAME)
{
return 1;
}
switch(lParam)
{
case WM_RBUTTONUP://右键起来时弹出快捷菜单,这里只有一个关闭
{
LPPOINT lpoint = new tagPOINT;
::GetCursorPos(lpoint);//得到鼠标位置
CMenu menu;
menu.CreatePopupMenu();//声明一个弹出式菜单
//增加菜单项“关闭”,点击则发送消息WM_DESTROY给主窗口(已
//隐藏),将程序结束。
menu.AppendMenu(MF_STRING, WM_DESTROY, _T("退出"));
//确定弹出式菜单的位置
menu.TrackPopupMenu(TPM_LEFTALIGN, lpoint->x, lpoint->y, this);
//资源回收
HMENU hmenu = menu.Detach();
menu.DestroyMenu();
delete lpoint;
}
break;
case WM_LBUTTONDBLCLK://双击左键的处理
{
this->ShowWindow(SW_SHOW);//简单的显示主窗口
this->ShowWindow(SW_RESTORE);
DeleteTray();
}
break;
default:
break;
}
return 0;
}
//删除托盘中图标
void DeleteTray();
void CTestlDlg::DeleteTray()
{
NOTIFYICONDATA nid;
nid.cbSize = (DWORD)sizeof(NOTIFYICONDATA);
nid.hWnd = this->m_hWnd;
nid.uID = IDR_MAINFRAME;
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
nid.uCallbackMessage = WM_SHOWTASK;//自定义的消息名称
nid.hIcon = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME));
wcscpy_s(nid.szTip, _T("***程序"));//信息提示条为“按计划任务提醒”
Shell_NotifyIcon(NIM_DELETE, &nid);//在托盘中删除图标
}
//退出程序需时需要DeleteTray();
void CTestDlg::OnDestroy()
{
CDialog::OnDestroy();
// TODO: 在此处添加消息处理程序代码
DeleteTray();
}
//修改风格使得他不在任务栏显示
int CTestDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialog::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: 在此添加您专用的创建代码
//修改风格使得他不在任务栏显示
ModifyStyleEx(WS_EX_APPWINDOW, WS_EX_TOOLWINDOW);
return 0;
}
DeleteTray改为:
void CTestDlg::DeleteTray()
{
NOTIFYICONDATA nid;
nid.cbSize = (DWORD)sizeof(NOTIFYICONDATA);
nid.hWnd = this->m_hWnd;
nid.uID = IDR_MAINFRAME;
nid.uFlags = NIF_ICON /*| NIF_MESSAGE | NIF_TIP*/;
//nid.uCallbackMessage = WM_SHOWTASK;//自定义的消息名称
//nid.hIcon = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME));
//wcscpy_s(nid.szTip, _T("***程序"));//信息提示条为“按计划任务提醒”
Shell_NotifyIcon(NIM_DELETE, &nid);//在托盘中删除图标
}
否则会出现程序退出后,托盘图标还在的情况,鼠标移动到图标上后,图标一闪然后消失的问题。
在C++中,可以利用ifstream文件输入流,当我们直接使用ifstream来创建文件输入流的时候,如果文件不存在则流创建失败。
ifstream fin("hello.txt");
if (!fin)
{
std::cout << "can not open this file" << endl;
}
fstream _file;
_file.open(FILENAME,ios::in);
if(!_file)
{
cout<<FILENAME<<"没有被创建";
}
else
{
cout<<FILENAME<<"已经存在";
}
Generic-Text Routine Mappings:
| TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _UNICODE Defined | _UNICODE Defined |
| _taccess | _access | _access |_waccess |
返回值
mode Value Checks File For
00 Existence only
02 Write permission
04 Read permission
06 Read and write permission
Example:
#include <io.h>
#include <stdio.h>
#include <stdlib.h>
int main( void )
{
// Check for existence.
if( (_access( "crt_ACCESS.C", 0 )) != -1 )
{
printf_s( "File crt_ACCESS.C exists.\n" );
// Check for write permission.
// Assume file is read-only.
if( (_access( "crt_ACCESS.C", 2 )) == -1 )
printf_s( "File crt_ACCESS.C does not have write permission.\n" );
}
}
https://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=ZH-CN&k=k(%22TCHAR%2f_TACCESS%22);k(_TACCESS);k(DevLang-%22C%2B%2B%22);k(TargetOS-WINDOWS)&rd=true;k(_TACCESS);k(DevLang-%22C%2B%2B%22);k(TargetOS-WINDOWS)&rd=true)
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
printf ("Target file is %s. ", argv[1]);
hFind = FindFirstFile(strPath.c_str(), &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
{
printf ("Invalid File Handle. Get Last Error reports %d ", GetLastError ());
}
else
{
printf ("The first file found is %s ", FindFileData.cFileName);
FindClose(hFind);
}
WIN32_FIND_DATA wfd;
bool rValue = false;
HANDLE hFind = FindFirstFile(strPath.c_str(), &wfd);
if ((hFind != INVALID_HANDLE_VALUE) && (wfd.dwFileAttributes &FILE_ATTRIBUTE_DIRECTORY))
{
std::cout << "this file exists" << endl;
}
FindClose(hFind);
在windows中可以使用_stat() 函数。
声明:int _stat(const char path, struct _stat buffer);
这个函数使用起来非常方便,如下:
struct _stat fileStat;
if ((_stat(dir.c_str(), &fileStat) == 0) && (fileStat.st_mode & _S_IFDIR))
{
isExist = true;
}
_S_IFDIR 是一个标志位,如果是目录的话,该位就会被系统设置。
在linux底下也有相对应的函数stat();
使用方法基本相同:
struct stat fileStat;
if ((stat(dir.c_str(), &fileStat) == 0) && S_ISDIR(fileStat.st_mode))
{
isExist = true;
}
唯一不同的地方我使用了一个macro, S_ISDIR来判断文件是否存在,原理实际都一样的。
https://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=ZH-CN&k=k(%22WCHAR%2f_STAT%22);k(_STAT);k(DevLang-%22C%2B%2B%22);k(TargetOS-WINDOWS)&rd=true;k(_STAT);k(DevLang-%22C%2B%2B%22);k(TargetOS-WINDOWS)&rd=true)
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/convenience.hpp>
int GetFilePath(std::string &strFilePath)
{
string strPath;
int nRes = 0;
//指定路径
strPath = "D:/myTest/Test1/Test2";
namespace fs = boost::filesystem;
//路径的可移植
fs::path full_path( fs::initial_path() );
full_path = fs::system_complete( fs::path(strPath, fs::native ) );
//判断各级子目录是否存在,不存在则需要创建
if ( !fs::exists( full_path ) )
{
// 创建多层子目录
bool bRet = fs::create_directories(full_path);
if (false == bRet)
{
return -1;
}
}
strFilePath = full_path.native_directory_string();
return 0;
}
namespace CshapMessage
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
IntPtr hwnd;
const int WM_COPYDATA = 0x004A;
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
}
[DllImport("User32.dll")]
public static extern int SendMessage(int hwnd, int msg, int wParam, ref COPYDATASTRUCT IParam);
[DllImport("User32.dll")]
public static extern int FindWindow(string lpClassName, string lpWindowName);
public MainWindow()
{
InitializeComponent();
this.Title = "CshapMessage";
this.Loaded += MainWindow_Loaded;
this.Closed += MainWindow_Closed;
}
private void MainWindow_Closed(object sender, EventArgs e)
{
try
{
HwndSource.FromHwnd(hwnd).RemoveHook(WndProc);
}
catch (Exception) { }
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
hwnd = new WindowInteropHelper(this).Handle;
HwndSource.FromHwnd(hwnd).AddHook(new HwndSourceHook(WndProc));
}
/// <summary>
/// 向C++程序 CshapMessage发送消息
/// </summary>
/// <param name="nMessgeId"></param>
/// <param name="strSend"></param>
/// <returns></returns>
private bool CshapSendMessage(int nMessgeId, String strSend)
{
int WINDOW_HANDLE = FindWindow(null, "VcMessage");//VcMessage为向C++程序发送的窗口名称
if (WINDOW_HANDLE != 0)
{
COPYDATASTRUCT cdata;
cdata.dwData = (IntPtr)100;//这里可以传入一些自定义的数据,但只能是4字节整数
cdata.lpData = strSend;//消息字符串
cdata.cData = System.Text.Encoding.Default.GetBytes(strSend).Length+1;//注意,这里的长度是按字节来算的
SendMessage(WINDOW_HANDLE, WM_COPYDATA, 0, ref cdata);
}
else
{
return false;
}
return true;
}
private void button_Click(object sender, RoutedEventArgs e)
{
String strSend = "C#发送的信息";
int nMessageId = 100;
if (CshapSendMessage(nMessageId,strSend))
{
MessageBox.Show("发送消息成功");
}
else
{
MessageBox.Show("消息发送失败,请打开VcMessage程序");
}
}
//接收消息。
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_COPYDATA)
{
COPYDATASTRUCT cdata = new COPYDATASTRUCT();
Type mytype = cdata.GetType();
cdata = (COPYDATASTRUCT)Marshal.PtrToStructure(lParam, mytype);
switch (cdata.dwData.ToInt32())
{
case 1:
{
string strRecv = cdata.lpData;
break;
}
default:
break;
}
}
return IntPtr.Zero;
}
}
}
BOOL CVcMessageDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//接收C#发送来的数据
switch (pCopyDataStruct->dwData)
{
case 100:
{
CStringA strRecv = (char*)pCopyDataStruct->lpData;
break;
}
default:
{
break;
}
}
return CDialogEx::OnCopyData(pWnd, pCopyDataStruct);
}
void CVcMessageDlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
CStringA strSend = "VC发送的数据";
if (VCSendMessage(1,strSend))
{
AfxMessageBox(_T("消息发送成功"));
}
else
{
AfxMessageBox(_T("消息发送失败"));
}
}
//************************************
// Method: VCSendMessage
// FullName: CVcMessageDlg::VCSendMessage
// Access: public
// Returns: BOOL
// Qualifier: 向C#程序 CshapMessage发送消息
// Parameter: int nMessgeId
// Parameter: CStringA strSend
//************************************
BOOL CVcMessageDlg::VCSendMessage(int nMessgeId,CStringA strSend)
{
HWND hSendWindow = this->m_hWnd;
if (hSendWindow == NULL)
{
return FALSE;
}
CWnd *phwnd = FindWindow(NULL, _T("CshapMessage"));
HWND hRecvWindow = NULL;
if (phwnd == NULL)
{
return FALSE;
}
hRecvWindow = phwnd->GetSafeHwnd();
if (hRecvWindow == NULL)
{
return FALSE;
}
COPYDATASTRUCT CopyData;
CopyData.dwData = nMessgeId;
CopyData.cbData = strSend.GetLength()+1;
CopyData.lpData = (PVOID)strSend.GetBuffer(CopyData.cbData);
::SendMessage(hRecvWindow, WM_COPYDATA, (WPARAM)hSendWindow, (LPARAM)&CopyData);
return TRUE;
}
http://www.codeproject.com/Articles/36468/WPF-NotifyIcon
https://bitbucket.org/hardcodet/notifyicon-wpf/src
https://www.nuget.org/packages/Hardcodet.NotifyIcon.Wpf/
Install-Package Hardcodet.NotifyIcon.Wpf
Hardcodet.NotifyIcon.Wpf.1.0.8.rar
在MainWindow.xaml
xmlns:tb="http://www.hardcodet.net/taskbar"
在MainWindow.xaml的
<tb:TaskbarIcon Name="MyNotifyIcon"
IconSource="Founder.ico"<!--托盘显示图标-->
ToolTipText="Founder 启动本地程序"><!--鼠标移动到托盘图标显示的文字-->
<tb:TaskbarIcon.ContextMenu><!--添加菜单-->
<ContextMenu>
<MenuItem Header="显示" ToolTip="显示主界面" Click="MenuItem_Click_Show" />
<MenuItem Header="退出" ToolTip="退出程序" Click="MenuItem_Click_Close" />
</ContextMenu>
</tb:TaskbarIcon.ContextMenu>
</tb:TaskbarIcon>
ico文件为16x16 32位,也可以更大
App.xaml
ShutdownMode="OnExplicitShutdown"
的作用是只有在调用Application对象的Shutdown()方法时,应用程序才会关闭。
<Application x:Class="Windowless_Sample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
ShutdownMode="OnExplicitShutdown">
<Application.Resources>
<!--
Note that this application does not have a StartupUri declared, so no Window is automatically loaded.
Also, the ShutdownMode was set to explicit, so we have to close the application programmatically
-->
<!-- merge NotifyIcon and related stuff into the application -->
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="NotifyIconResources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
添加资源NotifyIconResources.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tb="http://www.hardcodet.net/taskbar"
xmlns:local="clr-namespace:Windowless_Sample">
<!-- The taskbar context menu - the first row is a dummy to show off simple data binding -->
<!--
The "shared" directive is needed if we reopen the sample window a few times - WPF will otherwise
reuse the same context menu (which is a resource) again (which will have its DataContext set to the old TaskbarIcon)
-->
<ContextMenu x:Shared="false" x:Key="SysTrayMenu">
<MenuItem Header="显示" ToolTip="显示主界面" Command="{Binding ShowWindowCommand}" />
<MenuItem Header="隐藏" ToolTip="隐藏主界面" Command="{Binding HideWindowCommand}" />
<Separator />
<MenuItem Header="退出" ToolTip="退出程序" Command="{Binding ExitApplicationCommand}" />
</ContextMenu>
<!-- the application's NotifyIcon - started from App.xaml.cs. Declares its own view model. -->
<tb:TaskbarIcon x:Key="NotifyIcon"
IconSource="/Red.ico"
ToolTipText="Double-click for window, right-click for menu"
DoubleClickCommand="{Binding ShowWindowCommand}"
ContextMenu="{StaticResource SysTrayMenu}">
<!-- self-assign a data context (could also be done programmatically) -->
<tb:TaskbarIcon.DataContext>
<local:NotifyIconViewModel />
</tb:TaskbarIcon.DataContext>
</tb:TaskbarIcon>
</ResourceDictionary>
NotifyIconViewModel.cs
using System;
using System.Windows;
using System.Windows.Input;
namespace Windowless_Sample
{
/// <summary>
/// Provides bindable properties and commands for the NotifyIcon. In this sample, the
/// view model is assigned to the NotifyIcon in XAML. Alternatively, the startup routing
/// in App.xaml.cs could have created this view model, and assigned it to the NotifyIcon.
/// </summary>
public class NotifyIconViewModel
{
/// <summary>
/// Shows a window, if none is already open.
/// </summary>
public ICommand ShowWindowCommand
{
get
{
return new DelegateCommand
{
CanExecuteFunc = () => Application.Current.MainWindow == null,
CommandAction = () =>
{
Application.Current.MainWindow = new MainWindow();
Application.Current.MainWindow.Show();
}
};
}
}
/// <summary>
/// Hides the main window. This command is only enabled if a window is open.
/// </summary>
public ICommand HideWindowCommand
{
get
{
return new DelegateCommand
{
CommandAction = () => Application.Current.MainWindow.Close(),
CanExecuteFunc = () => Application.Current.MainWindow != null
};
}
}
/// <summary>
/// Shuts down the application.
/// </summary>
public ICommand ExitApplicationCommand
{
get
{
return new DelegateCommand {CommandAction = () => Application.Current.Shutdown()};
}
}
}
/// <summary>
/// Simplistic delegate command for the demo.
/// </summary>
public class DelegateCommand : ICommand
{
public Action CommandAction { get; set; }
public Func<bool> CanExecuteFunc { get; set; }
public void Execute(object parameter)
{
CommandAction();
}
public bool CanExecute(object parameter)
{
return CanExecuteFunc == null || CanExecuteFunc();
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
}
App.xaml.cs
using System.Windows;
using Hardcodet.Wpf.TaskbarNotification;
namespace Windowless_Sample
{
/// <summary>
/// Simple application. Check the XAML for comments.
/// </summary>
public partial class App : Application
{
private TaskbarIcon notifyIcon;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
//create the notifyicon (it's a resource declared in NotifyIconResources.xaml
notifyIcon = (TaskbarIcon) FindResource("NotifyIcon");
}
protected override void OnExit(ExitEventArgs e)
{
notifyIcon.Dispose(); //the icon would clean up automatically, but this is cleaner
base.OnExit(e);
}
}
}
//进程内钩子
//鼠标钩子过程函数
HHOOK g_hHookDm = NULL;
HWND g_DestWndH = NULL;
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
//此区间内的消息都是鼠标消息
if (WM_MOUSEMOVE <= wParam && wParam <= WM_MOUSEWHEEL)
{
if (g_DestWndH != NULL)
{
::SendMessage(g_DestWndH, wParam, wParam, lParam);
//鼠标钩子,lParam是MOUSEHOOKSTRUCT结构指针
PMOUSEHOOKSTRUCT lpMsg = (PMOUSEHOOKSTRUCT)lParam;
lpMsg->hwnd = NULL;
lpMsg->dwExtraInfo = 0L;
lpMsg->pt = CPoint(0, 0);
lpMsg->wHitTestCode = 0L;
}
return 1;//如果不想让此消息再往下传,返回非0
}
else
{
return ::CallNextHookEx(g_hHookDm, nCode, wParam, lParam);
}
}
//创建钩子过程
if (g_hHookDm == NULL)
{
//如果dwThreadid指定的线程是由当前进程创建,并且钩子过程在当时进程中,那么hMod必须设置为NULL.
g_hHookDm = ::SetWindowsHookEx(WH_MOUSE, MouseProc, NULL, GetCurrentThreadId());
if (g_hHookDm != NULL)
{
g_DestWndH = m_hWnd;//保存目的窗口句柄
}
}
//消毁进程内钩子
if (g_hHookDm != NULL)
{
UnhookWindowsHookEx(g_hHookDm);
g_DestWndH = NULL;
}
全局钩子-MFC扩展DLL
/新建一个CMouseHook的导出类
#pragma once
// CMouseHook 命令目标
//.h
class AFX_EXT_CLASS CMouseHook : public CObject //AFX_EXT_CLASS宏声明类为导出类
{
public:
CMouseHook();
virtual ~CMouseHook();
public:
BOOL StartHook(HWND hWnd); //安装钩子函数
BOOL StopHook();//卸载钩子函数
};
//.cpp
#include <afxwin.h>
#include <afxdllx.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#define WM_TOTASK (WM_USER + 2)
#pragma data_seg("SharedDataName")
HHOOK g_mouseHook;
HHOOK g_keyboardHook;
HWND g_hwnd = NULL;
HINSTANCE glhInstance = NULL; //DLL实例句柄
#pragma data_seg()
#pragma comment(linker,"/section:.SharedDataName,rws")
static AFX_EXTENSION_MODULE MyMouseHookDLL = { NULL, NULL };
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
// 如果使用 lpReserved,请将此移除
UNREFERENCED_PARAMETER(lpReserved);
if (dwReason == DLL_PROCESS_ATTACH)
{
TRACE0("MyMouseHook.DLL 正在初始化!\n");
// 扩展 DLL 一次性初始化
if (!AfxInitExtensionModule(MyMouseHookDLL, hInstance))
return 0;
// 将此 DLL 插入到资源链中
// 注意: 如果此扩展 DLL 由
// MFC 规则 DLL (如 ActiveX 控件)隐式链接到,
// 而不是由 MFC 应用程序链接到,则需要
// 将此行从 DllMain 中移除并将其放置在一个
// 从此扩展 DLL 导出的单独的函数中。使用此扩展 DLL 的
// 规则 DLL 然后应显式
// 调用该函数以初始化此扩展 DLL。否则,
// CDynLinkLibrary 对象不会附加到
// 规则 DLL 的资源链,并将导致严重的
// 问题。
new CDynLinkLibrary(MyMouseHookDLL);
glhInstance = hInstance; //插入保存DLL
}
else if (dwReason == DLL_PROCESS_DETACH)
{
TRACE0("MyMouseHook.DLL 正在终止!\n");
// 在调用析构函数之前终止该库
AfxTermExtensionModule(MyMouseHookDLL);
}
return 1; // 确定
}
LRESULT CALLBACK MouseProc(
int nCode, // hook code
WPARAM wParam, // message identifier
LPARAM lParam // mouse coordinates
) //鼠标钩子过程
{
LPMOUSEHOOKSTRUCT pMouseHook = (MOUSEHOOKSTRUCT FAR *)lParam;
if (nCode >= 0)
{
if (WM_LBUTTONDOWN == wParam)
{
//鼠标钩子,lParam是MOUSEHOOKSTRUCT结构指针
PMOUSEHOOKSTRUCT lpMsg = (PMOUSEHOOKSTRUCT)lParam;
CPoint point = lpMsg->pt;
RECT rect;
::GetWindowRect(g_hwnd, &rect); //得到整个窗口在屏幕上的矩形框位置
if ((point.x < rect.left || point.x > rect.right) || (point.y < rect.top || point.y > rect.bottom))
{
::SendMessage(g_hwnd, WM_SYSCOMMAND, WM_TOTASK, 0);
}
}
}
return CallNextHookEx(g_mouseHook, nCode, wParam, lParam);
}
LRESULT CALLBACK KeyboardProc(
int code, // hook code
WPARAM wParam, // virtual-key code
LPARAM lParam // keystroke-message information
)//键盘钩子过程
{
if(VK_F2 == wParam)
{
::SendMessage(g_hwnd, WM_CLOSE, 0, 0);
::UnhookWindowsHookEx(g_mouseHook);
::UnhookWindowsHookEx(g_keyboardHook);
}
else
return 1;
}
//安装钩子并设定接收显示窗口句柄
BOOL CMouseHook::StartHook(HWND hWnd)
{
BOOL bResult = FALSE;
g_hwnd = hWnd;
g_mouseHook =::SetWindowsHookEx(WH_MOUSE, MouseProc, glhInstance/*::GetModuleHandle(_T("MyMouseHook.dll"))*/, 0);
g_keyboardHook =::SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, ::GetModuleHandle(_T("MyMouseHook.dll")), 0);
/*=================================================================================
HHOOK SetWindowsHookEx( int idHook,HOOKPROC lpfn, INSTANCE hMod,DWORD dwThreadId )
参数idHook表示钩子类型,它是和钩子函数类型一一对应的。
比如,WH_KEYBOARD表示安装的是键盘钩子,WH_MOUSE表示是鼠标钩子等等。
Lpfn是钩子函数的地址。
HMod是钩子函数所在的实例的句柄。对于线程钩子,该参数为NULL;
对于系统钩子,该参数为钩子函数所在的DLL句柄。
dwThreadId 指定钩子所监视的线程的线程号。对于全局钩子,该参数为NULL。
SetWindowsHookEx返回所安装的钩子句柄。
值得注意的是线程钩子和系统钩子的钩子函数的位置有很大的差别。
线程钩子一般在当前线程或者当前线程派生的线程内,
而系统钩子必须放在独立的动态链接库中,实现起来要麻烦一些。
==================================================================================*/
if(g_mouseHook != NULL)
bResult = TRUE;
if(g_keyboardHook != NULL)
bResult = TRUE;
//设置显示目标窗口标题编辑框的句柄
return bResult;
}
//卸载钩子
BOOL CMouseHook::StopHook()
{
BOOL bResult = FALSE;
if(g_mouseHook)
{
bResult = UnhookWindowsHookEx(g_mouseHook);
if(bResult)
{
g_mouseHook = NULL;
}
}
if(g_keyboardHook)
{
bResult = UnhookWindowsHookEx(g_keyboardHook);
if(bResult)
{
g_keyboardHook = NULL;
}
}
return bResult;
}
#pragma data_seg("MySec")
HHOOK g_mouseHook;
HHOOK g_keyboardHook;
HWND g_hwnd = NULL;
#pragma data_seg()
#pragma comment(linker,"/section:MySec,RWS") //设置链接器,使MySec节拥有属性为 RWS (READ WRITE SHARED )
LRESULT CALLBACK MouseProc(
int nCode, // hook code
WPARAM wParam, // message identifier
LPARAM lParam // mouse coordinates
) //鼠标钩子过程
{
return 1;
}
LRESULT CALLBACK KeyboardProc(
int code, // hook code
WPARAM wParam, // virtual-key code
LPARAM lParam // keystroke-message information
)//键盘钩子过程
{
if(VK_F2 == wParam)
{
::SendMessage(g_hwnd, WM_CLOSE, 0, 0);
::UnhookWindowsHookEx(g_mouseHook);
::UnhookWindowsHookEx(g_keyboardHook);
}
else
return 1;
}
void SetHook(HWND hwnd)
{
g_hwnd = hwnd;
g_mouseHook =::SetWindowsHookEx(WH_MOUSE, MouseProc, ::GetModuleHandle(_T("dll_hook.dll")), 0);
g_keyboardHook =::SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, ::GetModuleHandle(_T("dll_hook.dll")), 0);
}
//之后我们添加def文件
//或者在def(模块定义文件中 )
LIBRARY "Hook"
EXPORTS
SetHook @2
SECTIONS
MySec READ WRITE SHARED
//编译下,编译通过之后可以看到 hook_dll.dll 和 hook_dll.lib文件。
//接着我们写一个测试程序,新建MFC工程 选择对话框程序.拷贝hook_dll.dll 和 hook_dll.lib到工程目录下,在链接器命令行加上 hook_dll.lib.
//在OnInitDialog()函数之前 定义DLL函数:
_declspec(dllimport) void SetHook(HWND hwnd);
//在OnInitDialog()内添加
SetHook(this->m_hWnd);
#include "stdafx.h"
#include <Windows.h>
#include <iostream>
using namespace std;
int _tmain(int argc, _TCHAR *argv[])
{
STARTUPINFOA si;
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(STARTUPINFOA);
TCHAR cmd[256] = _T("D:\\7za.exe a D:\\nv1.zip D:\\test\\*.*");
BOOL working = ::CreateProcess(NULL, cmd, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS , NULL, NULL, &si, &pi);
if (working == 0)
{
DWORD error = GetLastError();
cout << "CreateProcess Error : " << error << endl;
getchar();
return 0;
}
WaitForSingleObject(pi.hProcess, INFINITE);
unsigned long Result;
GetExitCodeProcess(pi.hProcess, &Result);
cout << "Exit Code : " << Result << endl;
getchar();
return 0;
}
CString ExeCmd(CString pszCmd)
{
//创建匿名管道
SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
HANDLE hRead, hWrite;
if (!CreatePipe(&hRead, &hWrite, &sa, 0))
{
return _T("");
}
//设置命令行进程启动信息(以隐藏方式启动命令并定位其输出到hWrite)
STARTUPINFO si = {sizeof(STARTUPINFO)};
GetStartupInfo(&si);
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.wShowWindow = SW_HIDE;
si.hStdError = hWrite;
si.hStdOutput = hWrite;
//启动命令行
PROCESS_INFORMATION pi;
if (!CreateProcess(NULL, (LPWSTR)(LPCWSTR)pszCmd, NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi))
{
return _T("");
}
//立即关闭hWrite
CloseHandle(hWrite);
//读取命令行返回值
char buff[1024] = {0};
DWORD dwRead = 0;
while (ReadFile(hRead, buff, 1024, &dwRead, NULL))
{
}
CString strRet(buff);
CloseHandle(hRead);
return strRet;
}
使用:
ExeCmd(_T("ping baidu.com"));
ExeCmd(_T("identify -format "%[colorspace]" E:\\P70306-163226.jpg"));
BOOL Start(LPCTSTR lpszTaskInfo)
{
if (!lpszTaskInfo)
{
return FALSE;
}
if (m_hRenderProcess)
{
if (Wait(0))
{
m_nProgress = 0;
SAFE_CLOSE_HANDLE(m_hRenderProcess);
m_dwRenderThreadId = 0;
}
else
{
return FALSE;
}
}
BOOL bRet = FALSE;
HANDLE hDebugInfo = NULL;
do
{
TCHAR szDebugLog[MAX_PATH];
_tcscpy(szDebugLog, m_szFastRenderExPath);
_tcscat(szDebugLog, _T(".debug"));
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
hDebugInfo = CreateFile(szDebugLog, FILE_WRITE_DATA, FILE_SHARE_READ, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.hStdInput = NULL;
si.hStdOutput = hDebugInfo;
si.hStdError = hDebugInfo;
si.wShowWindow = SW_HIDE;
TCHAR szCmdline[MAX_PATH * 2];
_sntprintf(szCmdline, ARRAYSIZE(szCmdline), _T(" -i \"%s\""), lpszTaskInfo); // 第一个空格非常重要
// Start the child process.
if( !CreateProcess( m_szFastRenderExPath, // Module name
szCmdline, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
TRUE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
break;
}
// Close process and thread handles.
m_hRenderProcess = pi.hProcess;
CloseHandle( pi.hThread );
m_dwRenderThreadId = pi.dwThreadId;
// Start the message receive thread
if (!m_dwReceiveThreadId)
{
HANDLE hThread = (HANDLE) _beginthreadex(NULL, 0, ThreadFn, this, 0, &m_dwReceiveThreadId);
if (hThread == NULL)
{
break;
}
CloseHandle(hThread);
}
if (!m_hMsgEvent)
{
m_hMsgEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
}
else
{
ResetEvent(m_hMsgEvent);
}
bRet = TRUE;
}
while (FALSE);
SAFE_CLOSE_HANDLE(hDebugInfo);
if (!bRet)
{
if (m_hRenderProcess)
{
TerminateProcess(m_hRenderProcess, -1);
SAFE_CLOSE_HANDLE(m_hRenderProcess);
}
m_dwRenderThreadId = 0;
SAFE_CLOSE_HANDLE(m_hMsgEvent);
}
return bRet;
}
三个SDK函数: WinExec, ShellExecute,CreateProcess
ShellExecute
void mySystem(CString cmd, CString par, int nShow)
{
SHELLEXECUTEINFO ShExecInfo = {0};
ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
ShExecInfo.hwnd = NULL;
ShExecInfo.lpVerb = NULL;
ShExecInfo.lpFile = cmd;//调用的程序名
ShExecInfo.lpParameters = par;//调用程序的命令行参数
ShExecInfo.lpDirectory = NULL;
ShExecInfo.nShow = SW_HIDE;//窗口状态为隐藏
ShExecInfo.hInstApp = NULL;
ShellExecuteEx(&ShExecInfo); //启动新的程序
WaitForSingleObject(ShExecInfo.hProcess,INFINITE);////等到该进程结束
}
CreateProcess
PROCESS_INFORMATION pi;
DWORD dwExitCode;
//Spawn the child process.
BOOL fSuccess = CreateProcess(..., ...);
if(fSuccess)
{
//Close the thread handle as soon as
//it is no longer needed!
CloseHandle(pi.hThread);
//Suspend our execution until
//the child has terminated.
WaitForSingleObject(pi.hProcess, INFINITE);
//The child process terminated;
//get its exit code.
GetExitCodeProcess(pi.hProcess,
&dwExitCode);
//Close the process handle as soon as
//it is no longer needed.
CloseHandle(pi.hProcess);
}
TCHAR szCommandLine[] = TEXT(".\\ffplay.exe -window_title CDFacePlay -exitonkeydown -exitonmousedown -fs -autoexit .\\video.mp4");
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
si.wShowWindow = FALSE;
si.dwFlags = STARTF_USESHOWWINDOW;
BOOL ret = ::CreateProcess(NULL, szCommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
if (ret)
{
WaitForSingleObject(pi.hProcess, INFINITE);//等待进程完成
}
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
using System.Runtime.InteropServices;
public enum ShowWindowCommands : int
{
SW_HIDE = 0,
SW_SHOWNORMAL = 1, //用最近的大小和位置显示,激活
SW_NORMAL = 1,
SW_SHOWMINIMIZED = 2,
SW_SHOWMAXIMIZED = 3,
SW_MAXIMIZE = 3,
SW_SHOWNOACTIVATE = 4,
SW_SHOW = 5,
SW_MINIMIZE = 6,
SW_SHOWMINNOACTIVE = 7,
SW_SHOWNA = 8,
SW_RESTORE = 9,
SW_SHOWDEFAULT = 10,
SW_MAX = 10
}
[DllImport("shell32.dll")]
public static extern IntPtr ShellExecute(
IntPtr hwnd,
string lpszOp,
string lpszFile,
string lpszParams,
string lpszDir,
ShowWindowCommands FsShowCmd
);
ShellExecute(IntPtr.Zero, "open", UrlOrPath, null, null, ShowWindowCommands.SW_SHOWNORMAL);
UrlOrPath可为exe路径或者网页url(使用默认浏览器打开网页url)
使用ie打开网页url
ShellExecute(NULL, "open", "IEXPLORE", "http://www.csdn.net", NULL, SW_SHOWMAXIMIZED);
using System.Diagnostics;
private static string Execute(string exePath, string parameters)
{
string result = String.Empty;
using (Process p = new Process())
{
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = exePath;
p.StartInfo.Arguments = parameters;
p.Start();
p.WaitForExit();
result = p.StandardOutput.ReadToEnd();
}
return result;
}
tag:
缺失模块。
1、请确保node版本大于6.2
2、在博客根目录(注意不是yilia根目录)执行以下命令:
npm i hexo-generator-json-content --save
3、在根目录_config.yml里添加配置:
jsonContent: meta: false pages: false posts: title: true date: true path: true text: false raw: false content: false slug: false updated: false comments: false link: false permalink: false excerpt: false categories: false tags: true