本文讲述了如何用C++Builder实现Messenger的详细方法,其中使用了如下技术:
1. 多线程序技术,防止界面出现死锁。
2. 使用了网络枚举来枚举在线的网络用户。
3. 使用了Unicode的转换函数进从AnsiString到Unicode的转换。
4. 使用了简单的不规则窗口的技术。
5. 自动安装,将自己加入系统起动中。
6. 系统托盘技术。
编程方法:
1. 在窗体上加入的有的控件:TListView,TTreeView,TMemo,菜单、托盘、按钮、状态栏
2. 针对各控件按本文所写加入代码即可。
3. 以下是发送函数
void __fastcall TFormMain::ButtonSendClick(TObject *Sender) { AnsiString Message,UserName,FromName; TListItem *ListItem; if(CheckBoxAnony->Checked)FromName=EditAnony->Text; else FromName=”"; Message=Memo1->Text; if(Message==”"){ShowMessage(“Please Enter words to send”);return;} if(!ListView1->SelCount){ if(TreeView1->Selected==NULL){ShowMessage(“Please select destnation”);return;} UserName=TreeView1->Selected->Text; if(TreeView1->Selected->Level==1)UserName=UserName+”*”; new NetMessageSend(false,UserName,FromName,Message,CheckBoxGetRe t->Checked); return; } ListItem=ListView1->Selected; UserName=ListItem->Caption; if(TreeView1->Selected->Level==0)UserName+=”*”; while(UserName[1]==’\\’) UserName=UserName.SubString(2,UserName.Length()-1); new NetMessageSend(false,UserName,FromName,Message,CheckBoxGetRe t->Checked); for(int i=1;i ListItem=ListView1->GetNextItem(ListItem,sdAll,TItemStates()< if(TreeView1->Selected->Level==0)UserName+=”*”; while(UserName[1]==’\\’)UserName=UserName.SubString(2,UserName.Length()-1); new NetMessageSend(false,UserName,FromName,Message,CheckBoxGetRe t->Checked); } } |
以下是网络结点枚举函数,是个线程
bool __fastcall EnumNetResource::GetNetRes( TTreeNodes *Nodes,TTreeNode * Node,NETRESOURCE *pNetResource,int Depth) { #define ENUMBUFSIZE (16*1024) #define ENUMCOUNT 10 NETRESOURCE buff[1024]; AnsiString UserName; if(Terminated) return false; if(Nodes==NULL) return false; if(Depth==0) return true; HANDLE hEnum; bool reValue=true; NETRESOURCE *pNetRes,NetRes; if(WNetOpenEnum(RESOURCE_GLOBALNET,RESOURCETYPE_ANY,0, pNetResource,&hEnum)!=NO_ERROR)return false; DWORD ECount=ENUMCOUNT; DWORD ESize=ENUMBUFSIZE; DWORD Error_num; do{ Error_num=WNetEnumResource(hEnum,&ECount,buff,&ESize ); if (ESize>ENUMBUFSIZE) return false; if (Error_num==NO_ERROR){ for (DWORD num=0;num pNetRes=&buff[num]; file://if(Node)Node->ImageIndex=1-Depth; UserName=AnsiString(pNetRes->lpRemoteName); while(UserName[1]==’\\’) UserName=UserName.SubString(2,UserName.Length()-1); TTreeNode *tNode=Nodes->AddChild(Node,UserName); if(tNode) switch(pNetRes->dwType){ case RESOURCETYPE_ANY: switch(tNode->Level){ case 0:tNode->ImageIndex=1;break; case 1: case 2:tNode->ImageIndex=2;break; } break; case RESOURCETYPE_DISK:tNode->ImageIndex=3;break; case RESOURCETYPE_PRINT:tNode->ImageIndex=4;break; } if(pNetRes->dwDisplayType!=RESOURCEDISPLAYTYPE_SHARE){ if(!GetNetRes(Nodes,tNode,pNetRes,Depth-1)) reValue=false; } } } }while(ECount==ENUMCOUNT); if (Error_num!=ERROR_NO_MORE_ITEMS && Error_num!=NO_ERROR) reValue=false; WNetCloseEnum(hEnum); return reValue; } |
以下是多线程发送函数,是个线程
void __fastcall NetMessageSend::Execute() { file://—- Place thread code here —- const maxlen=1600; wchar_t *pMsgBuff; AnsiString retstr; long int retvalue,msglen,sendlen; msglen=FMessage.WideCharBufSize(); pMsgBuff=(wchar_t *)malloc(msglen*2+10); FMessage.WideChar(pMsgBuff,msglen); for(long int i=0;i else sendlen=msglen*2-i; retvalue=NetMessageBufferSend(NULL,FUserName,pFromName,(char *)pMsgBuff+i,sendlen); } if(FGetRet){ switch(retvalue){ case NERR_Success: retstr=”@_@ Sent OK!”; break; case ERROR_ACCESS_DENIED: retstr=”:( Has no access”; break; case ERROR_INVALID_PARAMETER: retstr=”:( Parameter error.”; break; case ERROR_NOT_SUPPORTED: retstr=”:( Network not supported.”; break; case NERR_NameNotFound: retstr=”:( Parameter is invalid.”; break; case NERR_NetworkError: retstr=”:( General failure network hardware.”; break; default: retstr=”:( Unknow error”; break; } Application->MessageBox(retstr.c_str(),(“Result for “+AnsiString(FUserName)).c_str(),MB_OK); } free(pMsgBuff); } 本文代码在C++ Builder6.0,Windows2000专业版下实现。 |
>> 本文固定链接: http://www.vcgood.com/archives/788