int CPollTask::Run() { if (NULL == m_lpQQUser || NULL == m_lpQQProtocol || NULL == m_lpRecvMsgTask) { m_bStop = FALSE; return 0; } while (1) { if (m_bStop) break; CBuffer * lpMsgData = new CBuffer; if (NULL == lpMsgData) continue; BOOL bRet = m_lpQQProtocol->Poll(m_HttpClient, WEBQQ_CLIENT_ID, m_lpQQUser->m_LoginResult2.m_strPSessionId.c_str(), lpMsgData); if (!bRet || lpMsgData->GetData() == NULL || lpMsgData->GetSize() <= 0) { delete lpMsgData; ::OutputDebugStringA("poll message error!\r\n"); continue; } m_lpRecvMsgTask->AddMsgData(lpMsgData); } m_bStop = FALSE; return 0; }
BOOL CHostBrowser::LoadDC(LPCTSTR pszFile, CQueryHit*& pHits) { CFile pFile; if ( ! pFile.Open( pszFile, CFile::modeRead | CFile::shareDenyWrite ) ) return FALSE; // File open error UINT nInSize = (UINT)pFile.GetLength(); if ( ! nInSize ) return FALSE; // Empty file CBuffer pBuffer; if ( ! pBuffer.EnsureBuffer( nInSize ) ) return FALSE; // Out of memory if ( pFile.Read( pBuffer.GetData(), nInSize ) != nInSize ) return FALSE; // File read error pBuffer.m_nLength = nInSize; if ( ! pBuffer.UnBZip() ) return FALSE; // Decompression error augment::auto_ptr< CXMLElement > pXML ( CXMLElement::FromString( pBuffer.ReadString( pBuffer.m_nLength, CP_UTF8 ), TRUE ) ); if ( ! pXML.get() ) return FALSE; // XML decoding error // <FileListing Version="1" CID="SKCB4ZF4PZUDF7RKQ5LX6SVAARQER7QEVELZ2TY" Base="/" Generator="DC++ 0.762"> if ( ! pXML->IsNamed( L"FileListing" ) ) return FALSE; // Invalid XML file format // CString strTitle = pXML->GetAttributeValue( L"CID" ); return LoadDCDirectory( pXML.get(), pHits ); }
// If file was downloaded with a resource, validate checksum void CScriptFile::DoResourceFileCheck ( void ) { if ( !m_pFile || m_bDoneResourceFileCheck ) return; m_bDoneResourceFileCheck = true; if ( g_pClientGame->GetResourceManager()->IsResourceFile( m_strFilename ) ) { // Remember current position and seek to the end long lCurrentPos = m_pFile->FTell (); m_pFile->FSeek ( 0, SEEK_END ); // Retrieve size of file long lSize = m_pFile->FTell (); // Read data CBuffer buffer; buffer.SetSize( lSize ); m_pFile->FSeek ( 0, SEEK_SET ); m_pFile->FRead ( buffer.GetData(), buffer.GetSize() ); // Seek back to where the pointer was m_pFile->FSeek ( lCurrentPos, SEEK_SET ); // Check file content g_pClientGame->GetResourceManager()->ValidateResourceFile( m_strFilename, buffer ); } }
/////////////////////////////////////////////////////////////// // // JpegEncode // // XRGB to jpeg // /////////////////////////////////////////////////////////////// bool JpegEncode ( uint uiWidth, uint uiHeight, uint uiQuality, const void* pData, uint uiDataSize, CBuffer& outBuffer ) { // Validate if ( uiDataSize == 0 || uiDataSize != uiWidth * uiHeight * 4 ) return false; struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); unsigned long memlen = 0; unsigned char *membuffer = NULL; jpeg_mem_dest (&cinfo,&membuffer,&memlen ); cinfo.image_width = uiWidth; /* image width and height, in pixels */ cinfo.image_height = uiHeight; cinfo.input_components = 3; /* # of color components per pixel */ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ jpeg_set_defaults(&cinfo); jpeg_set_quality (&cinfo, uiQuality, true); cinfo.dct_method = JDCT_IFAST; /* Start compressor */ jpeg_start_compress(&cinfo, TRUE); /* Process data */ CBuffer rowBuffer; rowBuffer.SetSize ( uiWidth * 3 ); char* pRowTemp = rowBuffer.GetData (); JSAMPROW row_pointer[1]; while (cinfo.next_scanline < cinfo.image_height) { BYTE* pRowSrc = (BYTE*)pData + cinfo.next_scanline * uiWidth * 4; for ( uint i = 0 ; i < uiWidth ; i++ ) { pRowTemp[i*3+0] = pRowSrc[i*4+2]; pRowTemp[i*3+1] = pRowSrc[i*4+1]; pRowTemp[i*3+2] = pRowSrc[i*4+0]; } row_pointer[0] = (JSAMPROW)pRowTemp; (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); } /* Finish compression and release memory */ jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); // Copy out data and free memory outBuffer = CBuffer ( membuffer, memlen ); free ( membuffer ); return true; }
// // Add extra data to the dump file and hope visual studio doesn't mind // void CCrashDumpWriter::AppendToDumpFile ( const SString& strPathFilename, const CBuffer& dataBuffer, DWORD dwMagicStart, DWORD dwMagicEnd ) { CBuffer output; CBufferWriteStream stream ( output ); // 4 bytes zero stream.Write ( (DWORD)0 ); // 4 bytes magic stream.Write ( dwMagicStart ); // 4 bytes size of data stream.Write ( dataBuffer.GetSize () ); // n bytes data stream.WriteBytes ( dataBuffer.GetData (), dataBuffer.GetSize () ); // 4 bytes size of data stream.Write ( dataBuffer.GetSize () ); // 4 bytes magic stream.Write ( dwMagicEnd ); // 4 bytes zero stream.Write ( (DWORD)0 ); FileAppend ( strPathFilename, output.GetData (), output.GetSize () ); }
void CMainDlg::UpdateLog(PatchedProcess &proc) { if (proc.hLogPipe != INVALID_HANDLE_VALUE) { DWORD bytesAvailable = 0; PeekNamedPipe(proc.hLogPipe, NULL, 0, NULL, &bytesAvailable, NULL); if (bytesAvailable) { CBuffer buf; buf.EnsureSize(bytesAvailable); DWORD dwOk = 0; ReadFile(proc.hLogPipe, buf.GetData(), bytesAvailable, &dwOk, NULL); if (dwOk == bytesAvailable) { proc.Log.append((TCHAR *)buf.GetData(), bytesAvailable / sizeof(TCHAR)); proc.LogChanged = true; } } } }
static bool QueryAndReadProcessMemory(HANDLE hProcess, PVOID pAddr, CBuffer &buf) { MEMORY_BASIC_INFORMATION info = {0,}; if (!VirtualQueryEx(hProcess, pAddr, &info, sizeof(info))) return false; size_t todo = ((INT_PTR)info.BaseAddress + info.RegionSize - (INT_PTR)pAddr); if (todo > buf.GetAllocated()) todo = buf.GetAllocated(); SIZE_T dwDone = 0; ReadProcessMemory(hProcess, pAddr, buf.GetData(), todo, &dwDone); buf.SetSize(dwDone); return true; }
///////////////////////////////////////////////////////////// // // CDirect3DEvents9::CheckForScreenShot // // Take a screenshot if required and able // ///////////////////////////////////////////////////////////// void CDirect3DEvents9::CheckForScreenShot ( void ) { // Make a screenshot if needed if ( CCore::GetSingleton().bScreenShot && !CScreenShot::IsSaving () ) { // Max one screenshot per second if ( GetTickCount64_ () - ms_LastSaveTime < 1000 ) return; ms_LastSaveTime = GetTickCount64_ (); uint uiWidth = CDirect3DData::GetSingleton ().GetViewportWidth (); uint uiHeight = CDirect3DData::GetSingleton ().GetViewportHeight (); // Call the pre-screenshot function SString strFileName = CScreenShot::PreScreenShot (); // Try to get the screen data SString strError; if ( CGraphics::GetSingleton ().GetScreenGrabber ()->GetBackBufferPixels ( uiWidth, uiHeight, ms_ScreenShotBuffer, strError ) ) { // Validate data size uint uiDataSize = ms_ScreenShotBuffer.GetSize (); uint uiReqDataSize = uiWidth * uiHeight * 4; if ( uiDataSize == uiReqDataSize ) { // Start the save thread CScreenShot::BeginSave ( strFileName, ms_ScreenShotBuffer.GetData (), uiDataSize, uiWidth, uiHeight ); } else { g_pCore->GetConsole()->Printf ( _("Screenshot got %d bytes, but expected %d"), uiDataSize, uiReqDataSize ); strFileName = ""; } } else { g_pCore->GetConsole()->Print ( _("Screenshot failed") + SString( " (%s)", *strError ) ); strFileName = ""; } // Call the post-screenshot function CScreenShot::PostScreenShot ( strFileName ); CCore::GetSingleton().bScreenShot = false; } }
int CLuaFileDefs::fileRead ( lua_State* luaVM ) { // string fileRead ( file, count ) CScriptFile* pFile; unsigned long ulCount = 0; CScriptArgReader argStream ( luaVM ); argStream.ReadUserData ( pFile ); argStream.ReadNumber ( ulCount ); if ( !argStream.HasErrors ( ) ) { if ( ulCount > 0 ) { // Allocate a buffer to read the stuff into and read some shit into it CBuffer buffer; long lBytesRead = pFile->Read ( ulCount, buffer ); if ( lBytesRead != -1 ) { // Push the string onto the lua stack. Use pushlstring so we are binary // compatible. Normal push string takes zero terminated strings. lua_pushlstring ( luaVM, buffer.GetData(), lBytesRead ); } else { m_pScriptDebugging->LogBadPointer ( luaVM, "file", 1 ); lua_pushnil ( luaVM ); } // We're returning the result string return 1; } else { // Reading zero bytes from a file results in an empty string lua_pushstring ( luaVM, "" ); return 1; } } else m_pScriptDebugging->LogCustom ( luaVM, argStream.GetFullErrorMessage() ); lua_pushnil ( luaVM ); return 1; }
// Check resource file data matches server checksum void CResourceManager::ValidateResourceFile( const SString& strInFilename, const CBuffer& fileData ) { SString strFilename = PathConform( strInFilename ).ToLower(); CDownloadableResource* pResourceFile = MapFindRef( m_ResourceFileMap, strFilename ); if ( pResourceFile ) { if ( pResourceFile->IsAutoDownload() && !pResourceFile->IsDownloaded() ) { // Scripting error g_pClientGame->GetScriptDebugging()->LogError( NULL, "Attempt to load '%s' before onClientFileDownloadComplete event", *ConformResourcePath( strInFilename ) ); } else { CChecksum checksum; if ( !fileData.IsEmpty() ) checksum = CChecksum::GenerateChecksumFromBuffer( fileData.GetData(), fileData.GetSize() ); else checksum = CChecksum::GenerateChecksumFromFile( strInFilename ); if ( checksum != pResourceFile->GetServerChecksum() ) { if ( pResourceFile->IsDownloaded() ) { char szMd5[33]; CMD5Hasher::ConvertToHex( checksum.md5, szMd5 ); char szMd5Wanted[33]; CMD5Hasher::ConvertToHex( pResourceFile->GetServerChecksum().md5, szMd5Wanted ); SString strMessage( "Resource file checksum failed: %s [Size:%d MD5:%s][Wanted:%s][datasize:%d] ", *ConformResourcePath( strInFilename ), (int)FileSize( strInFilename ), szMd5, szMd5Wanted, fileData.GetSize() ); g_pClientGame->TellServerSomethingImportant( 1007, strMessage, false ); g_pCore->GetConsole ()->Print( strMessage ); AddReportLog( 7057, strMessage + g_pNet->GetConnectedServer( true ), 10 ); } else if ( !pResourceFile->IsAutoDownload() ) { char szMd5[33]; CMD5Hasher::ConvertToHex( checksum.md5, szMd5 ); SString strMessage( "Attempt to load resource file before it is ready: %s [Size:%d MD5:%s] ", *ConformResourcePath( strInFilename ), (int)FileSize( strInFilename ), szMd5 ); g_pClientGame->TellServerSomethingImportant( 1008, strMessage, false ); g_pCore->GetConsole ()->Print( strMessage ); AddReportLog( 7058, strMessage + g_pNet->GetConnectedServer( true ), 10 ); } } } } }
BOOL CCollectionFile::LoadDC(LPCTSTR pszFile) { m_nType = SimpleCollection; // ToDo: Add schema detection m_sThisURI = CSchema::uriFolder; m_sParentURI = CSchema::uriCollectionsFolder; CFile pFile; if ( ! pFile.Open( pszFile, CFile::modeRead | CFile::shareDenyWrite ) ) return FALSE; // File open error UINT nInSize = (UINT)pFile.GetLength(); if ( ! nInSize ) return FALSE; // Empty file CBuffer pBuffer; if ( ! pBuffer.EnsureBuffer( nInSize ) ) return FALSE; // Out of memory if ( pFile.Read( pBuffer.GetData(), nInSize ) != nInSize ) return FALSE; // File read error pBuffer.m_nLength = nInSize; if ( ! pBuffer.UnBZip() ) return FALSE; // Decompression error augment::auto_ptr< CXMLElement > pXML ( CXMLElement::FromString( pBuffer.ReadString( pBuffer.m_nLength, CP_UTF8 ), TRUE ) ); if ( ! pXML.get() ) return FALSE; // XML decoding error // <FileListing Version="1" CID="SKCB4ZF4PZUDF7RKQ5LX6SVAARQER7QEVELZ2TY" Base="/" Generator="DC++ 0.762"> if ( ! pXML->IsNamed( L"FileListing" ) ) return FALSE; // Invalid XML file format m_sTitle = pXML->GetAttributeValue( L"CID" ); LoadDC( pXML.get() ); return ( m_pFiles.GetCount() != 0 ); }
long CScriptFile::Read ( unsigned long ulSize, CBuffer& outBuffer ) { if ( !m_pFile ) return -1; DoResourceFileCheck(); // If read size is large, limit it to how many bytes can be read (avoid memory problems with over allocation) if ( ulSize > 10000 ) { long lCurrentPos = m_pFile->FTell (); m_pFile->FSeek ( 0, SEEK_END ); long lFileSize = m_pFile->FTell (); m_pFile->FSeek ( lCurrentPos, SEEK_SET ); ulSize = Min < unsigned long > ( 1 + lFileSize - lCurrentPos, ulSize ); // Note: Read extra byte at end so EOF indicator gets set } outBuffer.SetSize( ulSize ); return m_pFile->FRead ( outBuffer.GetData(), ulSize ); }
// If compiled script, make sure correct chunkname is embedded void CLuaShared::EmbedChunkName(SString strChunkName, const char** pcpOutBuffer, uint* puiOutSize) { const char*& cpBuffer = *pcpOutBuffer; uint& uiSize = *puiOutSize; if (!IsLuaCompiledScript(cpBuffer, uiSize)) return; if (uiSize < 12) return; // Get size of name in original uint uiStringSizeOrig = *(uint*)(cpBuffer + 12); if (uiSize < 12 + 4 + uiStringSizeOrig) return; static CBuffer store; store.Clear(); CBufferWriteStream stream(store); // Ensure name starts with @ and ends with NULL if (!strChunkName.BeginsWith("@")) strChunkName = "@" + strChunkName; if (strChunkName[strChunkName.length() - 1] != '\0') strChunkName.push_back('\0'); // Header stream.WriteBytes(cpBuffer, 12); // New name size stream.Write(strChunkName.length()); // New name bytes incl zero termination stream.WriteBytes(strChunkName.c_str(), strChunkName.length()); // And the rest stream.WriteBytes(cpBuffer + 12 + 4 + uiStringSizeOrig, uiSize - 12 - 4 - uiStringSizeOrig); cpBuffer = store.GetData(); uiSize = store.GetSize(); }
///////////////////////////////////////////////////////////////////////////// // // CRenderWareSA::RightSizeTexture // // Check texture and shrink if required. // Returns new texture if did shrink // ///////////////////////////////////////////////////////////////////////////// RwTexture* CRenderWareSA::RightSizeTexture( RwTexture* pTexture, uint uiSizeLimit ) { // Validate RwRaster* pRaster = pTexture->raster; if ( !pRaster ) return NULL; RwD3D9Raster* pD3DRaster = (RwD3D9Raster*)( &pRaster->renderResource ); if ( !pD3DRaster->texture || !pD3DRaster->lockedSurface || !pD3DRaster->lockedRect.pBits ) return NULL; // Get texture info uint uiWidth = pRaster->width; uint uiHeight = pRaster->height; D3DFORMAT d3dFormat = pD3DRaster->format; bool bHasAlpha = pD3DRaster->alpha != 0; bool bIsCubeTexture = ( pD3DRaster->cubeTextureFlags & 0x01 ) != 0; bool bHasMipMaps = ( pRaster->numLevels > 1 ); bool bIsCompressed = ( pD3DRaster->textureFlags & 0x10 ) != 0; // Check we can do this if ( bIsCubeTexture || !bIsCompressed ) return NULL; // Only process DXT formats if ( d3dFormat != D3DFMT_DXT1 && d3dFormat != D3DFMT_DXT3 && d3dFormat != D3DFMT_DXT5 ) return NULL; // Change size uint uiReqWidth = Min( uiSizeLimit, uiWidth ); uint uiReqHeight = Min( uiSizeLimit, uiHeight ); if ( uiReqWidth == uiWidth && uiReqHeight == uiHeight ) return NULL; // Lock mip level 0 if required D3DLOCKED_RECT lockedRect = pD3DRaster->lockedRect; bool bNeedOwnLock = ( pD3DRaster->lockedLevel != 0 ) || !pD3DRaster->lockedSurface; if ( bNeedOwnLock ) if ( FAILED( pD3DRaster->texture->LockRect( 0, &lockedRect, NULL, D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY ) ) ) return NULL; // Try resize CBuffer newPixelBuffer; bool bDidResize = g_pCore->GetGraphics()->ResizeTextureData( lockedRect.pBits, lockedRect.Pitch, uiWidth, uiHeight, d3dFormat, uiReqWidth, uiReqHeight, newPixelBuffer ); if ( bNeedOwnLock ) pD3DRaster->texture->UnlockRect( 0 ); if ( !bDidResize ) return NULL; // Make new RwTexture from pixels NativeTexturePC_Header header; memset( &header, 0, sizeof( header ) ); header.TextureFormat.platformId = 9; header.TextureFormat.filterMode = pTexture->flags & 0xff; header.TextureFormat.uAddressing = ( pTexture->flags & 0xf00 ) >> 8; header.TextureFormat.vAddressing = ( pTexture->flags & 0xf000 ) >> 12; memcpy( header.TextureFormat.name, pTexture->name, 32 ); memcpy( header.TextureFormat.maskName, pTexture->mask, 32 ); header.RasterFormat.rasterFormat = ( pRaster->format & 0x0f ) << 8; // ( dxt1 = 0x00000100 or 0x00000200 / dxt3 = 0x00000300 ) | 0x00008000 mipmaps? header.RasterFormat.d3dFormat = pD3DRaster->format; header.RasterFormat.width = uiReqWidth; header.RasterFormat.height = uiReqHeight; header.RasterFormat.depth = pRaster->depth; header.RasterFormat.numLevels = 1; header.RasterFormat.rasterType = pRaster->type; // dxt1 = 4 / dxt3 = 4 header.RasterFormat.alpha = bHasAlpha; header.RasterFormat.cubeTexture = bIsCubeTexture; header.RasterFormat.autoMipMaps = false; header.RasterFormat.compressed = bIsCompressed; // Create stream containing new texture data CBuffer nativeData; CBufferWriteStream stream( nativeData ); stream.Write( 1 ); stream.Write( 0 ); // Size ignored stream.Write( 0x1803FFFF ); stream.WriteBytes( &header, sizeof( header ) ); stream.Write( newPixelBuffer.GetSize() ); stream.WriteBytes( newPixelBuffer.GetData(), newPixelBuffer.GetSize() ); RwBuffer buffer; buffer.ptr = (void*)nativeData.GetData(); buffer.size = nativeData.GetSize(); RwStream * rwStream = RwStreamOpen( STREAM_TYPE_BUFFER, STREAM_MODE_READ, &buffer ); if ( !rwStream ) return NULL; // Read new texture RwTexture* pNewRwTexture = NULL; rwD3D9NativeTextureRead( rwStream, &pNewRwTexture ); RwStreamClose( rwStream, NULL ); return pNewRwTexture; }
/////////////////////////////////////////////////////////////// // // JpegDecode // // jpeg to XRGB // /////////////////////////////////////////////////////////////// bool JpegDecode ( const void* pData, uint uiDataSize, CBuffer& outBuffer, uint& uiOutWidth, uint& uiOutHeight ) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; /* Initialize the JPEG decompression object with default error handling. */ cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); /* Specify data source for decompression */ jpeg_mem_src (&cinfo,(uchar*)pData,uiDataSize ); /* Read file header, set default decompression parameters */ (void) jpeg_read_header(&cinfo, TRUE); /* default decompression parameters */ // TODO /* Start decompressor */ (void) jpeg_start_decompress(&cinfo); /* Write output file header */ JDIMENSION uiWidth = cinfo.output_width; /* scaled image width */ JDIMENSION uiHeight = cinfo.output_height; /* scaled image height */ uiOutWidth = uiWidth; uiOutHeight = uiHeight; outBuffer.SetSize ( uiWidth * uiHeight * 4 ); char* pOutData = outBuffer.GetData (); /* Process data */ JSAMPROW row_pointer[1]; CBuffer rowBuffer; rowBuffer.SetSize ( uiWidth * 3 ); char* pRowTemp = rowBuffer.GetData (); while (cinfo.output_scanline < cinfo.output_height) { BYTE* pRowDest = (BYTE*)pOutData + cinfo.output_scanline * uiWidth * 4; row_pointer[0] = (JSAMPROW)pRowTemp; JDIMENSION num_scanlines = jpeg_read_scanlines(&cinfo, row_pointer, 1); for ( uint i = 0 ; i < uiWidth ; i++ ) { pRowDest[i*4+0] = pRowTemp[i*3+2]; pRowDest[i*4+1] = pRowTemp[i*3+1]; pRowDest[i*4+2] = pRowTemp[i*3+0]; pRowDest[i*4+3] = 255; } } // Finish decompression and release memory. (void) jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); if ( jerr.num_warnings ) return false; return true; }
int CGetChatPicTask::Run() { CBuffer bufPic; BOOL bRet; if (NULL == m_lpQQUser || NULL == m_lpQQProtocol || NULL == m_lpMsg) { m_bStop = FALSE; return 0; } if (OP_TYPE_BUDDY_PIC == m_nType) // 好友图片 { CBuddyMessage * lpMsg = (CBuddyMessage *)m_lpMsg; int nCount = (int)lpMsg->m_arrContent.size(); for (int i = 0; i < nCount; i++) { CContent * lpContent = lpMsg->m_arrContent[i]; if (NULL == lpContent) continue; if (CONTENT_TYPE_CUSTOM_FACE == lpContent->m_nType) // 自定义表情 { bRet = m_lpQQProtocol->GetBuddyChatPic(m_HttpClient, lpMsg->m_nMsgId, lpContent->m_CFaceInfo.m_strName.c_str(), lpMsg->m_nFromUin, WEBQQ_CLIENT_ID, m_lpQQUser->m_LoginResult2.m_strPSessionId.c_str(), &bufPic); if (bRet) SavePic(lpContent->m_CFaceInfo.m_strName.c_str(), bufPic.GetData(), bufPic.GetSize()); } else if (CONTENT_TYPE_OFF_PIC == lpContent->m_nType) // 离线图片 { bRet = m_lpQQProtocol->GetBuddyOffChatPic(m_HttpClient, lpContent->m_CFaceInfo.m_strName.c_str(), lpMsg->m_nFromUin, WEBQQ_CLIENT_ID, m_lpQQUser->m_LoginResult2.m_strPSessionId.c_str(), &bufPic); if (bRet) SavePic(lpContent->m_CFaceInfo.m_strName.c_str(), bufPic.GetData(), bufPic.GetSize()); } } ::PostMessage(m_lpQQUser->m_hProxyWnd, QQ_MSG_BUDDY_MSG, NULL, (LPARAM)lpMsg); } else if (OP_TYPE_GROUP_PIC == m_nType) // 群图片 { CGroupMessage * lpMsg = (CGroupMessage *)m_lpMsg; int nCount = (int)lpMsg->m_arrContent.size(); for (int i = 0; i < nCount; i++) { CContent * lpContent = lpMsg->m_arrContent[i]; if (lpContent != NULL && CONTENT_TYPE_CUSTOM_FACE == lpContent->m_nType) { LPCTSTR lpFmt = _T("%[^:]:%d"); TCHAR cServer[1024] = {0}; int nPort = 0; _stscanf(lpContent->m_CFaceInfo.m_strServer.c_str(), lpFmt, cServer, &nPort); bRet = m_lpQQProtocol->GetGroupChatPic(m_HttpClient, lpMsg->m_nGroupCode, lpMsg->m_nSendUin, cServer, nPort, lpContent->m_CFaceInfo.m_nFileId, lpContent->m_CFaceInfo.m_strName.c_str(), m_lpQQUser->m_LoginResult2.m_strVfWebQq.c_str(), &bufPic); if (bRet) SavePic(lpContent->m_CFaceInfo.m_strName.c_str(), bufPic.GetData(), bufPic.GetSize()); } } ::PostMessage(m_lpQQUser->m_hProxyWnd, QQ_MSG_GROUP_MSG, NULL, (LPARAM)lpMsg); } else if (OP_TYPE_SESS_PIC == m_nType) { // WebQQ协议目前不支持临时会话发送/接收自定义表情 } m_bStop = FALSE; return 0; }