当前位置: 首页 > 编程日记 > 正文

几种Windows进程通信

32位Windows采用虚拟内存技术使每个进程虚拟4G内存,在逻辑上实现了对进程之间数据代码的分离与保护。那么相应的进程之间的通信也就有必要整理掌握一下。

Windows进程间通讯的方法有很多:管道、邮件槽、剪切板、共享内存、消息、套接字、RPC、DDE等。

但是他们大部分拥有一个共同的本质:利用Windows操作系统高2GB内核共享空间进行数据传递的桥梁,所以他们都是内核对象!

所以他们大部分都要遵循:A创建对象-->A写入数据-->B打开A创建的对象-->B读入数据的规则

下面着重通过一些代码Demo来加深下对进程间通信的理解

0X01

命名管道

进程A代码

#define READ_PIPE   L"\\\\.\\pipe\\ReadPipe"
#define WRITE_PIPE  L"\\\\.\\pipe\\WritePipe"      //   管道命名typedef struct _USER_CONTEXT_ 
{HANDLE hPipe;HANDLE hEvent;
}USER_CONTEXT,*PUSER_CONTEXT;USER_CONTEXT  Context[2] = {0};HANDLE hThread[2] = {0};BOOL  WritePipe();
BOOL  ReadPipe();BOOL  bOk = FALSE;DWORD WINAPI WritePipeThread(LPVOID LPParam);
DWORD WINAPI ReadPipeThread(LPVOID LPParam);
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{int nRetCode = 0;HANDLE hPipe = NULL;if (WritePipe()==FALSE){return -1;}if (ReadPipe()==FALSE){return -1;}int iIndex = 0;while (TRUE){    if (bOk==TRUE){SetEvent(Context[0].hEvent);SetEvent(Context[1].hEvent);Sleep(1);}iIndex = WaitForMultipleObjects(2,hThread,TRUE,5000);if (iIndex==WAIT_TIMEOUT){continue;}else{break;}}int i = 0;for (i=0;i<2;i++){CloseHandle(Context[i].hEvent);CloseHandle(Context[i].hPipe);}CloseHandle(hThread[0]);CloseHandle(hThread[1]);cout<<"Exit"<<endl;return nRetCode;
}BOOL  WritePipe()
{HANDLE hWritePipe = NULL;hWritePipe = CreateNamedPipe( WRITE_PIPE,             PIPE_ACCESS_DUPLEX,       PIPE_TYPE_MESSAGE |    PIPE_READMODE_MESSAGE |  PIPE_WAIT,               PIPE_UNLIMITED_INSTANCES, MAX_PATH,         MAX_PATH,0,                      NULL);            if (hWritePipe==INVALID_HANDLE_VALUE){return FALSE;}HANDLE hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);Context[0].hEvent = hEvent;Context[0].hPipe  = hWritePipe;hThread[0] = CreateThread(NULL,0,WritePipeThread,NULL,0,NULL);return TRUE;
}BOOL  ReadPipe()
{HANDLE hReadPipe = NULL;hReadPipe = CreateNamedPipe( READ_PIPE,             PIPE_ACCESS_DUPLEX,       PIPE_TYPE_MESSAGE |    PIPE_READMODE_MESSAGE |  PIPE_WAIT,               PIPE_UNLIMITED_INSTANCES, MAX_PATH,         MAX_PATH,0,                      NULL);            if (hReadPipe==INVALID_HANDLE_VALUE){return FALSE;}HANDLE hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);Context[1].hEvent = hEvent;Context[1].hPipe  = hReadPipe;hThread[1] = CreateThread(NULL,0,ReadPipeThread,NULL,0,NULL);return TRUE;}DWORD WINAPI ReadPipeThread(LPVOID LPParam)
{HANDLE hEvent     = Context[1].hEvent;HANDLE hReadPipe  = Context[1].hPipe;DWORD  dwReturn   = 0;char szBuffer[MAX_PATH] = {0};int  iIndex = 0;while (TRUE){iIndex = WaitForSingleObject(hEvent,30);iIndex = iIndex-WAIT_OBJECT_0;if (iIndex==WAIT_FAILED||iIndex==0){break;}if (ReadFile(hReadPipe,szBuffer,MAX_PATH,&dwReturn,NULL)){szBuffer[dwReturn] = '\0';cout<<szBuffer<<endl;}else{if (GetLastError()==ERROR_INVALID_HANDLE){break;}               }}return 0;
}DWORD WINAPI WritePipeThread(LPVOID LPParam)
{HANDLE hEvent     = Context[0].hEvent;HANDLE hWritePipe = Context[0].hPipe;DWORD  dwReturn   = 0;char szBuffer[MAX_PATH] = {0};int  iIndex = 0;while (TRUE){iIndex = WaitForSingleObject(hEvent,30);iIndex = iIndex-WAIT_OBJECT_0;if (iIndex==WAIT_FAILED||iIndex==0){break;}cin>>szBuffer;   if (WriteFile(hWritePipe,szBuffer,strlen(szBuffer),&dwReturn,NULL)){}else{if (GetLastError()==ERROR_INVALID_HANDLE){break;}   }}return 0;
}
View Code

进程B代码

#define WRITE_PIPE   L"\\\\.\\pipe\\ReadPipe"
#define READ_PIPE  L"\\\\.\\pipe\\WritePipe"HANDLE hThread[2] = {0};DWORD WINAPI  ReadPipeThread(LPARAM LPParam);
DWORD WINAPI  WritePipeThread(LPARAM LPParam);
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{HANDLE hReadPipe  = NULL;HANDLE hWritePipe = NULL;hThread[0] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ReadPipeThread,NULL,0,NULL);hThread[1] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)WritePipeThread,NULL,0,NULL);WaitForMultipleObjects(2,hThread,TRUE,INFINITE);CloseHandle(hReadPipe);CloseHandle(hWritePipe);CloseHandle(hThread[0]);CloseHandle(hThread[1]);cout<<"Exit"<<endl;return -1;
}DWORD WINAPI WritePipeThread(LPARAM LPParam)
{HANDLE hWritePipe = NULL;char  szBuffer[MAX_PATH] = {0};DWORD dwReturn = 0;while(TRUE){hWritePipe = CreateFile(WRITE_PIPE,GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);if (hWritePipe==INVALID_HANDLE_VALUE){continue;}break;}while (TRUE){cin>>szBuffer;if (WriteFile(hWritePipe,szBuffer,MAX_PATH,&dwReturn,NULL)){}else{if (GetLastError()==ERROR_NO_DATA){cout<<"Write Failed"<<endl;break;}}}return 0;
}DWORD WINAPI  ReadPipeThread(LPARAM LPParam)
{HANDLE hReadPipe = NULL;char  szBuffer[MAX_PATH] = {0};DWORD dwReturn = 0;while(TRUE){hReadPipe = CreateFile(READ_PIPE,GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);if (hReadPipe==INVALID_HANDLE_VALUE){continue;}break;}while (TRUE){if (ReadFile(hReadPipe,szBuffer,MAX_PATH,&dwReturn,NULL)){szBuffer[dwReturn] = '\0';cout<<szBuffer;}else{cout<<"Read Failed"<<endl;break;}}return 0;
}
View Code

*其中进程A创建了管道内核对象,以及用于读写管道的双线程。B进程通过对象名打开了A创建的内核对象,同时也创建了双线程进行命名管道的读与写。

对于管道需要多说的是有一种管道是匿名管道,也就是不需要创建对象管道的名字。那么其他进程又是如何知道这个管道对象,从而实现对信息的传递的呢?

原来它是通过内核对象的可继承性进行的,也就是说匿名管道只能作用于父子进程之间,在父进程创建子进程的时候通过对CreateProcess函数中传参,即可让子进程获得父进程的内核对象句柄。

具体实现细节,请参考《Windows核心编程》内核对象一章。

0X02

邮件槽

进程A代码

#define  MAIL_SLOT_NAME  L"\\\\.\\mailslot\\Name" HANDLE  hReadMailSlot = INVALID_HANDLE_VALUE;
DWORD WINAPI ReadMail();
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{int nRetCode = 0;HANDLE hReadThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ReadMail,NULL,0,NULL);Sleep(INFINITE);if (hReadMailSlot!=INVALID_HANDLE_VALUE){CloseHandle(hReadMailSlot);}Sleep(10);return nRetCode;
}DWORD WINAPI ReadMail()
{hReadMailSlot = CreateMailslot(MAIL_SLOT_NAME,0,0,NULL);if (hReadMailSlot==INVALID_HANDLE_VALUE){return -1;}//查看油槽的信息
DWORD cbMessage = 0;DWORD cMessage  = 0;BOOL bOk  = FALSE;char*  szBuffer = NULL;DWORD  dwReturn = 0;while (TRUE){bOk =  GetMailslotInfo(hReadMailSlot,NULL,&cbMessage,&cMessage,NULL);if (bOk==FALSE){break;}if (cMessage==0){continue;}else{if (szBuffer!=NULL){free(szBuffer);szBuffer = NULL;}szBuffer = (char*)malloc(sizeof(char)*cbMessage+1);if (ReadFile(hReadMailSlot, szBuffer, cbMessage, &dwReturn, NULL)==TRUE){szBuffer[dwReturn] = '\0';if (strcmp(szBuffer,"Exit")==0){break;}cout<<szBuffer<<endl;}        }}cout<<"ReadThread Exit"<<endl;
}
View Code

进程B代码

#define  MAIL_SLOT_NAME  L"\\\\.\\mailslot\\Name" 
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{int nRetCode = 0;HANDLE hWriteMailSlot = NULL;while(TRUE){hWriteMailSlot = CreateFile(MAIL_SLOT_NAME,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);if (hWriteMailSlot==INVALID_HANDLE_VALUE){continue;}else{break;}}DWORD dwReturn = 0;char szBuffer[1024] = {0};while (TRUE){cin>>szBuffer;if (strcmp(szBuffer,"Exit")==0){break;}WriteFile(hWriteMailSlot,szBuffer,strlen(szBuffer),&dwReturn,NULL);}WriteFile(hWriteMailSlot,szBuffer,strlen(szBuffer),&dwReturn,NULL);CloseHandle(hWriteMailSlot);return nRetCode;
}
View Code

*邮件槽的实现和命名管道大同小异,都是A创建对象-->A写入数据-->B打开A创建的对象-->B读入数据。以前一直认为邮件槽是Windows与Linux共有的机制,自从某次上Liunx课和老师讨论了一会进程间通信的问题,

才愚蠢的知道Linux并没有邮件槽这个机制。

0X03

共享内存

进程A代码

using namespace std;int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{int nRetCode = 0;char szBuffer[] = "Shine";HANDLE hMapping = CreateFileMapping(NULL,NULL,PAGE_READWRITE,0,4096,L"ShareMemory");LPVOID lpBase = MapViewOfFile(hMapping,FILE_MAP_WRITE|FILE_MAP_READ,0,0,0);strcpy((char*)lpBase,szBuffer);Sleep(20000);UnmapViewOfFile(lpBase);CloseHandle(hMapping);return nRetCode;
}
View Code

进程B代码

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{int nRetCode = 0;HANDLE hMapping = OpenFileMapping(FILE_MAP_ALL_ACCESS,NULL,L"ShareMemory");if (hMapping){wprintf(L"%s\r\n",L"Success");LPVOID lpBase = MapViewOfFile(hMapping,FILE_MAP_READ|FILE_MAP_WRITE,0,0,0);char szBuffer[20] = {0};strcpy(szBuffer,(char*)lpBase);printf("%s",szBuffer);UnmapViewOfFile(lpBase);CloseHandle(hMapping);}else{wprintf(L"%s",L"OpenMapping Error");}return nRetCode;
}
View Code

说道共享内存不得不说下内存映射:如何将一个文件映射到自己的缓冲区中。

打开文件-->计算文件大小-->创建内存映射对象Mapping-->mapofviewfile映射到自己的缓冲区中

通过文件映射来进行读写文件操作较为方便。

文件映射代码

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{int nRetCode = 0;HANDLE hFile = CreateFile(L"D:\\Demo.txt",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_WRITE|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);DWORD dwHigh = 0;DWORD dwLow = 0;dwLow = GetFileSize(hFile,&dwHigh);   dwLow = ((dwLow + 4095)/4096)*4096;if (hFile==INVALID_HANDLE_VALUE){return -1;}HANDLE hMapping = CreateFileMapping(hFile,NULL,PAGE_READWRITE,dwHigh,dwLow,NULL);if (hMapping==NULL){CloseHandle(hFile);}char* szBuffer = NULL;szBuffer = (char*)MapViewOfFile(hMapping,FILE_MAP_ALL_ACCESS,0,0,0);if (szBuffer!=NULL){cout<<szBuffer<<endl;}*(szBuffer+1) = 'w';UnmapViewOfFile(szBuffer);CloseHandle(hMapping);CloseHandle(hFile);return nRetCode;
}
View Code

0X04

消息

进程A代码

void CServerDlg::OnBnClickedOk()
{CString  strBuffer;m_Edit.GetWindowText(strBuffer);if (strBuffer.GetLength()==0){return;}COPYDATASTRUCT  Temp;Temp.dwData = 0;      Temp.cbData = strBuffer.GetLength()*sizeof(WCHAR);      //  sizeof    没有算  '\0'Temp.lpData = strBuffer.GetBuffer();           HWND hFindWindow = ::FindWindow(NULL,L"Client");if (hFindWindow==NULL){return;}::SendMessage(hFindWindow,WM_COPYDATA,NULL,(LPARAM)&Temp);}
View Code

进程B代码

进程B需要添加WM_COPYDATA消息

BOOL CClientDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{// TODO: 在此添加消息处理程序代码和/或调用默认值if (pCopyDataStruct->lpData==NULL||pCopyDataStruct->cbData==0){return FALSE;}int nSize = 0;                           //字节20int nLen = pCopyDataStruct->cbData+sizeof(WCHAR);    //字符HelloWorld10     加了个'\0'
WCHAR* szBuffer =  new WCHAR[nLen>>1];      //   右移一位   除以二    申请  同样大的内存if (szBuffer==NULL){return FALSE;}memset(szBuffer,0,sizeof(WCHAR)*(nLen>>1));memcpy(szBuffer,pCopyDataStruct->lpData,pCopyDataStruct->cbData);m_Edit.SetWindowText(szBuffer);delete szBuffer;szBuffer = NULL;return CDialogEx::OnCopyData(pWnd, pCopyDataStruct);
}
View Code

这种方式是由操作系统负责给目标窗口传递 ,所以目标进程必须需要窗口,不然A得不到窗口句柄就无法传递。这种方式是通过Windows消息队列传递,看起来与之前的内核对象传递消息有悖,

那是因为操作系统把相关细节都屏蔽掉了,如果深究起来还是通过Ring0的操作系统空间内核对象进行传递。

剩下的套接字,RPC,DDE等也可用来进行进程间通信,但总有种杀鸡用牛刀的感觉。我并没有再进行整理,有兴趣的可以在进行了解了解。

转载于:https://www.cnblogs.com/zibility/p/5657308.html

相关文章:

TestNG学习随笔

转载自&#xff1a;http://blog.sina.com.cn/s/blog_68f262210102vh5c.html 通过本人实践&#xff0c;文中所讲的程序可以正确运行&#xff0c;作用正确&#xff0c;并且浅显易懂。以下就是我从中摘录的重要知识点&#xff0c;就当留作自己记录或者帮助其他想学TestNG的人一点借…

录制短视频的录制按钮边框计时效果

项目增加录制短视频功能, 需一录制功能按钮, 使用贝塞尔曲线结合shapelayer绘制按钮边框的计时功能 代码如下: #import "YGRecordView.h" #define BeforeRecord_LineWidth 2.0#define BeforeRecord_LineColor UIColorFromRGBA(0xffffff, 1)#define Record_LineWidt…

区块链学堂:区块链引子

链客&#xff0c;专为开发者而生&#xff0c;有问必答&#xff01; 此文章来自链客区块链技术问答社区&#xff0c;未经允许拒绝转载。 区块链学堂&#xff08;1&#xff09;&#xff1a;区块链引子 相信正在看这篇文章的读者一定已经听说过区块链了&#xff0c;并且也相信…

Git命令文本手册

git init # 初始化本地git仓库&#xff08;创建新仓库&#xff09; git config --global user.name "xxx" # 配置用户名 git config --global user.email "xxxxxx.com" …

Mininet的介绍安装

Mininet的介绍 Mininet是一个强大的网络仿真平台&#xff0c;通过这个这个平台&#xff0c;我们可以很方便的模拟真实环境中的网络操作与架构。当前SDN/OpenFlow发展的如火如荼&#xff0c;但是在真实网络中又不可以进行相关的网络实验&#xff0c;自然需要一个仿真平台可以对这…

项目的简单总结一 -- 关于对贝塞尔和shapelayer结合使用的动画特效

现项目基本稳定, 要开始新的项目, 总结一二 关于对贝塞尔和shapelayer结合使用的动画特效, 在这次的项目中有几处使用到 故做了个小的demo, 记录下 效果如下: demo地址:https://github.com/wyon0313/BezierAnimation

内部区块链的优缺点

链客&#xff0c;专为开发者而生&#xff0c;有问必答&#xff01; 此文章来自链客区块链技术问答社区&#xff0c;未经允许拒绝转载。 内部区块链的优缺点1 区块链的作用是取代可信赖的第三方&#xff0c;或者是在不完全相互信任的实体之间建立信任关系&#xff0c;如此看来…

Spring框架系列之AOP思想

微信公众号&#xff1a;compassblog 欢迎关注、转发&#xff0c;互相学习&#xff0c;共同进步&#xff01; 有任何问题&#xff0c;请后台留言联系&#xff01; 1、AOP概述 &#xff08;1&#xff09;、什么是 AOP AOP 为 Aspect Oriented Programming 的缩写&#xff0c;意为…

jstack 使用(转)

dump 文件里&#xff0c;值得关注的线程状态有&#xff1a;死锁&#xff0c;Deadlock&#xff08;重点关注&#xff09; 执行中&#xff0c;Runnable 等待资源&#xff0c;Waiting on condition&#xff08;重点关注&#xff09; 等待获取监视器&#xff0c;Waiting on monit…

ios TableView编辑状态多选框的修改

在- (void)layoutSubview 和 - (void)setEditing:(BOOL)editing animated:(BOOL)animated 中添加 UIImage *selectImg [UIImage imageNamed:"im_select_sign"]; UIImage *disSelectImg [UIImage imageNamed:"im_disSelect_sign"]; for (UIC…

区块链有哪些技术特征

链客&#xff0c;专为开发者而生&#xff0c;有问必答&#xff01; 此文章来自链客区块链技术问答社区&#xff0c;未经允许拒绝转载。 区块链有哪些技术特征 在信息网络化的大背景下&#xff0c;当需要与不熟悉的对手方进行价值交换活动时&#xff0c;人们如何做才能防止不会…

《JavaEE开发的颠覆者——Spring Boot实战》是一本好书

这本书的风格非常好、每一节都是先点明这一块知识的要点&#xff0c;随后就手把手的做出一个最简明、但有能体现核心的实例&#xff08;大多只有几个Class&#xff09; 这样的书用来熟悉一门框架&#xff0c;实在是再好不过。转载于:https://www.cnblogs.com/nanlan2017/p/1045…

html css 布局知识概况

1、如果想设置页面居中&#xff0c;当设置margin属性为auto的时候&#xff0c;不能在设置浮动或绝对定位属性。并且一定要设置width为一个定值 2、盒子模型三维立体结构图 3、浮动布局 利用浮动可以实现横向布局&#xff0c;通过float来实现&#xff08;left--左浮动&#xff0…

项目的简单总结二--可拉伸的头视图

项目总结二 tableVIew和collectionview中头视图的可拉伸放大效果 demo中只做了tableview的效果, collectionview做法一样 效果如下图: demo地址: https://github.com/wyon0313/ZoomHeaderView

浅谈区块链技术

链客&#xff0c;专为开发者而生&#xff0c;有问必答&#xff01; 此文章来自链客区块链技术问答社区&#xff0c;未经允许拒绝转载。 浅谈区块链技术 这几天空闲的时候在网上浏览了一些区块链的技术&#xff0c;其实区块链只是一个技术&#xff0c;只不过是比特币很好的实…

IIS 7.5 去掉index.php 西数服务器

//新建web.config 加上下面代码<?xml version"1.0"?> <configuration> <system.webServer><rewrite><rules><rule name"OrgPage" stopProcessing"true"><match url"^(.*)$" /><condit…

bzoj1927: [Sdoi2010]星际竞速

跟上一题几乎一样。。。 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<queue> using namespace std; #define rep(i,n) for(int i1;i<n;i) #define clr(x,c) memset(x,c,sizeof(x)) #define op() cl…

在cell中取得UITableView所在的ViewController对象

原来碰到这个问题一般会将控制器传进cell中, 或者将cell要做的响应事件回调到控制器去处理, 前段时间找到一种方法觉得很不错 - (UIViewController *)getTableViewSuperViewController { for (UIView* next [self superview]; next; next next.superview) { UI…

区块链当前现状

链客&#xff0c;专为开发者而生&#xff0c;有问必答&#xff01; 此文章来自链客区块链技术问答社区&#xff0c;未经允许拒绝转载。 区块链是分布式账本技术&#xff0c;用于记录交易数据&#xff0c;具有不可篡改性、完整分布性、可追溯性等技术优势&#xff0c;应用包括…

MVC 4.0 Razor模板引擎 @Html.RenderPartial 与 @Html.RenderAction 区别

近来在学习MVC 4.0&#xff0c;设置布局全局网页的页脚&#xff0c;使用了Razor语法 {Html.RenderPartial("Footer", Model.FooterData);} 但是并不理解Html帮助器方法Html.RenderPartial。 先来介绍一下Html.RenderPartial用法。 Html.RenderPartial在Asp.net Mvc中…

iOS 图片处理-利用GPUImage 磨皮和美白图片

项目中要求处理图片, 简单记录一下美白和磨皮过程 (其中GPUImage还有美颜滤镜, 使用方式基本一样) //磨皮 - (void)editPhotoByBilateralWithLevel:(CGFloat)level { GPUImagePicture *pic [[GPUImagePicture alloc] initWithImage:image]; // 磨皮滤镜…

linux下编译php扩展

1 在pecl.php.net搜索你需要的php扩展 2 在解压后的扩展目录运行phpize 3 执行编译./configure --with-php-config/usr/local/php/bin/php-config 4 修改php/lib/php.ini文件 加上这句话extention扩展.so的绝对路径转载于:https://www.cnblogs.com/wyqn/p/8493456.html

区块链技术原理

链客&#xff0c;专为开发者而生&#xff0c;有问必答&#xff01; 此文章来自链客区块链技术问答社区&#xff0c;未经允许拒绝转载。 以比特币的区块链为例&#xff0c;你可以把区块链想象成一个比特币的公共账本&#xff0c;这个账本&#xff1a; 1.存放在互联网的各个比…

Spring之事务管理配置

1. 基于注解的事务配置 1. 在需要添加事务的方法上加上Transactional注解2. Spring的配置文件中配置事务管理器1 <!-- 添加事务管理器组件DataSourceTransactionManager -->2 <bean id"transactionManager"3 class"org.springframewor…

iOS 图片处理-图片旋转和裁剪

项目中要求处理图片, 简单记录一下图片旋转和裁剪过程 /** 将图片旋转弧度radians */- (UIImage *)imageRotatedByRadians:(CGFloat)radians{ // calculate the size of the rotated views containing box for our drawing space UIView *rotatedViewBox [[UIView alloc…

ThinkPHP 3.1.2 视图 1

一、模板的使用 &#xff08;重点&#xff09;a、规则模板文件夹下[TPL]/[分组文件夹/][模板主题文件夹/]和模块名同名的文件夹[Index]/和方法名同名的文件[index].html&#xff08;.tpl&#xff09;更换模板文件的后缀名&#xff08;修改配置文件&#xff09;TMPL_TEMP…

mysql事务处理用法与实例详解

MySQL的事务支持不是绑定在MySQL服务器本身&#xff0c;而是与存储引擎相关1.MyISAM&#xff1a;不支持事务&#xff0c;用于只读程序提高性能 2.InnoDB&#xff1a;支持ACID事务、行级锁、并发 3.Berkeley DB&#xff1a;支持事务一个事务是一个连续的一组数据库操作&#xff…

C++ 类的内存分布

C类内存分布 转自&#xff1a;http://www.cnblogs.com/jerry19880126/p/3616999.html先写下总结&#xff0c;通过总结下面的例子&#xff0c;你就会明白总结了。下面总结一下&#xff1a; 1、虚基类指针和虚函数指针是可以继承的 2. 虚函数指针来源于父类或者自己是第一个声明虚…

iOS 关于手机权限的检查与获取

手机通讯录权限: /** * 检测权限并作响应的操作 */ - (void)checkAuthorizationStatus:(UISwitch *)sender { switch (ABAddressBookGetAuthorizationStatus()) { case kABAuthorizationStatusAuthorized: //存在权限 //获取通讯…

也谈谈区块链技术

链客&#xff0c;专为开发者而生&#xff0c;有问必答&#xff01; 此文章来自区块链社区&#xff0c;未经允许拒绝转载。 现在区块链技术很火&#xff0c;而且几乎被上升到了一个“革命性”的高度&#xff0c;很多股票居然都因为沾了点区块链变得炙手可热。其实这玩意没有这么…