启动一个进程的简单写法:
PROCESS_INFORMATION pi;
STARTUPINFO siStartInfo = {0}; //STARTUPINFO主要用于设置程序主窗口属性;置各项为0(默认值)
siStartInfo.cb = sizeof(siStartInfo);
BOOL isOK;
isOK = CreateProcess(NULL, _T("cmd.exe shutdown.exe"), NULL, NULL, FALSE,
0, NULL, NULL, &siStartInfo, &pi);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
LineDDA使用的简单例子: //每一象素点调用一次回调函数myDDA
void CFgfgDlg::OnPaint() //用在OnPaint或OnDraw内
{
.....
else
{
CPaintDC dc(this);
CRect rt;
GetClientRect(&rt);
dc.SetTextAlign(TA_CENTER|TA_BOTTOM);
::LineDDA(rt.right, 0, rt.right/2, rt.bottom/2,
(LINEDDAPROC)myDDA, (LPARAM)(LPVOID)&dc);
::LineDDA(rt.right/2, rt.bottom/2, rt.right-60, rt.bottom-10,
(LINEDDAPROC)myDDA, (LPARAM)(LPVOID)&dc);
CDialog::OnPaint();
}
}
//static CALLBACK myDDA(int x, int y, LPARAM dc); 声明为静态成员函数
void CALLBACK CFgfgDlg::myDDA(int x, int y, LPARAM dc)
//x,y为象素点坐标,dc为LineDDA最后一参数
{
//static char str[] = "hi, clx";
//((CDC*)dc)->TextOut(x, y, str, sizeof(str)-1);
((CDC*)dc)->Ellipse(x-10, y-10, x+10, y+10);
for (long i=0; i<950000; i++); //延迟一下
}
CTime使用一例:
CTime tOld = CTime::GetCurrentTime();
Sleep(10000);
CTime tCur = CTime::GetCurrentTime();
CTimeSpan t = tCur - tOld; //时间间隔
long s = t.GetTotalSeconds(); //转为秒
CString str;
str.Format("%ld", s);
MessageBox(str);
CreatePipe创建一个管道,这个管道有输入端和输出端,同时也创建了管道使用的缓冲区
一个例子:
void CTestPipeDlg::OnButton1()
{
/*
BOOL CreatePipe(
PHANDLE hReadPipe, // read handle
PHANDLE hWritePipe, // write handle
LPSECURITY_ATTRIBUTES lpPipeAttributes, // security attributes
DWORD nSize // pipe size
CreateProcess(
LPCWSTR lpszImageName,
LPCWSTR lpszCmdLine,
LPSECURITY_ATTRIBUTES lpsaProcess,
LPSECURITY_ATTRIBUTES lpsaThread,
BOOL fInheritHandles,
DWORD fdwCreate,
LPVOID lpvEnvironment,
LPWSTR lpszCurDir,
LPSTARTUPINFOW lpsiStartInfo,
LPPROCESS_INFORMATION lppiProcInfo);
); */
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
HANDLE hRead, hWrite;
if (!CreatePipe(&hRead, &hWrite, &sa, 0))
{
MessageBox(_T("创建管道失败"));
return;
}
//这时当前进程拥有管道的输入和输出端
//再建一个进程,让它的输出连到这个管道,这样的话这个管道就有两个输入一个输出了,不合理,
//因此还要关闭当前进程所拥有的输入端
PROCESS_INFORMATION pi;
STARTUPINFO si = {0};
si.cb = sizeof(STARTUPINFOW);
si.hStdError = hWrite; //这个进程的所有输出信息将自动写到管道缓冲区中
si.hStdOutput = hWrite;
si.wShowWindow = SW_HIDE; //隐藏
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
if (!CreateProcess(NULL, _T("cmd.exe help/?"), NULL, NULL, TRUE,
0, NULL, NULL, &si, &pi))
{
MessageBox(_T("创建进程失败"));
return;
}
CloseHandle(hWrite);
/*BOOL ReadFile(
HANDLE hFile, // handle to file
LPVOID lpBuffer, // data buffer
DWORD nNumberOfBytesToRead, // number of bytes to read
LPDWORD lpNumberOfBytesRead, // number of bytes read
LPOVERLAPPED lpOverlapped // overlapped buffer
);
*/
//读取管道缓冲区里面的内容(cmd dir/?)
char readBuf[4096] = {0};
DWORD dwCount;
while (TRUE)
{
if (!ReadFile(hRead, readBuf, 4095, &dwCount, NULL))
{
break;
}
m_strEdit += readBuf; //m_strEdit为成员变量(CString)
m_strEdit += "/r/n";
UpdateData(FALSE);
Sleep(200);
}
}
关于__stdcall和__cdecl调用方式
以下是别人写的一段话:
_stdcall是Pascal程序的缺省调用方式,通常用于Win32 Api中,函数采用从右到左的压栈方式,自己在
退出时清空堆栈。VC将函数编译后会在函数名前面加上下划线前缀,在函数名后加上"@"和参数的字节数
。
C调用约定(即用__cdecl关键字说明)按从右至左的顺序压参数入栈,由调用者把参数弹出栈。对于传送
参数的内存栈是由调用者来维护的(正因为如此,实现可变参数的函数只能使用该调用约定)。另外,在
函数名修饰约定方面也有所不同。
_cdecl是C和C++程序的缺省调用方式。每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行
文件大小会比调用_stdcall函数的大。函数采用从右到左的压栈方式。VC将函数编译后会在函数名前面加
上下划线前缀。是MFC缺省调用约定。
宏APIENTRY,WINAPI和CALLBACK指的是同一东西:__stdcall(回调函数或api都是用这种调用方式)
kbhit用来检测键盘是否有按键,有则返回-1,没有则返回0. 如果想知道按下了什么键,应该用getch()来获
取(键值已经输入缓冲区,getch从缓冲区中取得而非再从键盘输入). 你给出的程序应该是一个不会正常退
出的死循环吧(不管按什么键),因为, while (!kbhit()) m = getch(); getch()会中断等待你从键盘输入
,这个输入不会被kbhit检测到(此时中断处理中),而待中断处理完后(输入一个字符后)再转到kbhit,而此
时又没有输入马上再次转到getch(). 我给一个我见过的用法:
#include <stdio.h>
void main()
{
char m;
int i = 0;
while (1)
{
while (!kbhit())
{
i++;
if (i == 8)
i = 0;
sound(i);
}
m = getch();
printf("m == %c/n", m);
if (m == 's')
{
nosound();
break;
}
}
getch();
}
两个进程间用发送消息的方式通信,而且希望带上个字符串发送过去,应该考虑发送WM_COPYDATA消息.下面
是一个例子:
//发送端
char fileName[100];
memset(fileName, 0, 100);
GetModuleFileName(NULL, fileName, 100);
COPYDATASTRUCT cpd;
cpd.dwData = 0;
cpd.cbData = strlen(fileName);
cpd.lpData = (void*)fileName;
CString strTitle = "";
strTitle = ReadIniFile("ServerTitle"); //自定义,取窗口标题
HWND hServer = FindWindow(NULL, strTitle);
if (hServer)
{ //发送(不用PostMessage)
::SendMessage(hServer, WM_COPYDATA, 0, (LPARAM)&cpd);
}
//接收端,给出WM_COPYDATA映射宏 ON_WM_COPYDATA()
//处理函数声明 afx_msg BOOL OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct);
//在处理函数里面写:
CString strName("");
strName = (LPCSTR)(pCopyDataStruct->lpData);
strName = strName.Left(strName.Find(".exe", 0));
strName += ".exe";
MessageBox(strName);
return CWnd::OnCopyData(pWnd, pCopyDataStruct);
//例子结束
如果是同一个进程内发(send or post)消息来带去一个字符串,可以发送一个自定义的消息,用wParam或
lParam来保存字符串的地址(32位,强制转为wParam或lParam),在处理这个消息时只需把wParam或lParam转
为char*就可以了. 操作系统(可能是User32.dll)应该在发送消息时为这个字符串再分配了一个空间来存
放,并记录下这个空间的地址,在调用消息处理函数时把这个地址传给了相应的wParam或lParam.
但对于两个进程间以发送自定义消息的方式来通信的情况,带字符串的目的没有达到,我的接收端得到的是
空值.我估计这种方法不行.