团灭Windows进程通信(二)——剪贴板在中间

文章来源:http://blog.csdn.net/huanglong8/article/details/53708337

说起Windows的剪贴板,大家并不陌生,复制粘贴都需要经历它这一层,那么其剪贴板的实质其实就是一块预先分配好的内存地址,这个地址上存放着用户需要复制的内容或地址。所以,剪贴板其实就是提供了在不同进程间相互通信的发送获取数据的一个共享通道。
关于剪贴版其他的一些定义或意义,网上文章诸多,可以参考:

http://www.cnblogs.com/1314NNNKKK/p/3522363.html

————↓来自参考
为使剪贴板的这种IPC机制更加完善和便于使用,需要解决好如下三个问题:提供数据的进程在结束时Windows系统将删除其创建的全 局内存块,而接受数据的进程则希望在其退出后剪贴板中的数据仍然存在,可以继续为其他进程所获取;能方便地管理和传送剪贴板数据句柄;能方便设置和确定剪 贴板数据格式。为完善上述功能,Windows提供了存在于USER32.dll中的一组API函数、消息和预定义数据格式等,并通过对这些函数、消息的 使用来管理在进程间进行的剪贴板数据交换。

  Windows系统为剪贴板提供了一组API函数和多种消息,基本可以满足编程的需要。而且Windows还为剪贴板预定义了多种数据格式。通过这些预定义的格式,可以使接收方正确再现数据提供方放置于剪贴板中的数据内容。
————↑来自参考

具体的API可以查百度嘛,现在我们来实际情况编写小程序。
在接下来的所有进程通信系列介绍中,我们都要尽可能的完成这么一个需求。

需要编写两个独立进程,这个进程以控制台或窗口实现用户控制。分别为模块A,模块B。模块A发送指令到模块B,模块B接收到后显示,模块B也可以发送指令给模块A,模块A接收后也显示。并且整个发送指令又用户设定内容,并且模块间的通信机制以阻塞为主,即有消息过来时进行处理。

好了解了需求后,我们需要思考两个问题,第一个问题就是 用户的读写IO 操作,第二个问题就是 如何阻塞获取。

用户的读写IO操作可以用两个线程来解决,一个用来读并显示在控制台中,一个用来写进行发送指令。
为了让发送指令后,立即被接收到,可以通过windows消息来进行。windows提供的消息机制中,有一个消息为 WM_CLIPBOARDUPDATE 。它的作用在于当剪贴板的内容改变时,则会接收到此消息的过程,这里不光只内容的改变,只要有剪贴板的动作,就会触发。

程序用关键代码段描述:

BOOL OpenClipboard(); [1]
返回值:
如果通过CWnd打开了剪贴板,则返回非零值。
如果其他应用程序或窗口已经打开了剪贴板,则返回零。
说明:
在调用Windows的CloseClipboard函数之前,其他应用程序将不能修改剪贴板的内容。
在调用Windows的EmptyClipboard函数之前,当前的CWnd对象将不会成为剪贴板的拥有者。

我们预先定义一下简单的协议结构

#define MSGHEADA "[CLIPPED_BOARD][FROMA]"
#define MSGHEADB "[CLIPPED_BOARD][FROMB]"

两个线程进行控制

发送线程

DWORD WINAPI Send(LPVOID lpParameter )
{
    char buff[0xFFF];
    DWORD dwd;
    ZeroMemory(buff,sizeof(buff));
    while(true)
    {
        gets_s(buff,sizeof(buff));
        HGLOBAL hClip = 0;
        if (OpenClipboard(0))
        {
            EmptyClipboard();
            hClip=GlobalAlloc(GMEM_MOVEABLE,0xFFF);
            char *pbuff=(char*)GlobalLock(hClip);
            strcpy(pbuff,MSGHEADA);
            strcat(pbuff,buff);
            GlobalUnlock(hClip);
            SetClipboardData(CF_TEXT,hClip);
            CloseClipboard();
            GlobalFree(hClip);
            hClip = 0;
        }
    }
    return 0;
}

接收线程

LRESULT CALLBACK Recv(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    int val = uMsg;
    char tmp[512] = {0};
    if(val ==  WM_CLIPBOARDUPDATE ) 
    {

        HGLOBAL hClip = 0;
        if (OpenClipboard(0))
        {
            char* buff;
            hClip=GetClipboardData(CF_TEXT);
            if(hClip) buff=(char*)GlobalLock(hClip);
            else 
            {
                CloseClipboard();
                return DefWindowProc(hwnd, uMsg, wParam, lParam);
            }
            if(buff!=0 && memcmp(buff,MSGHEADB,sizeof(MSGHEADB)-1) ==0)
            {
                printf("FromB: %s\n",buff+sizeof(MSGHEADB)-1);
            }
            else
            {
                GlobalUnlock(hClip);
                CloseClipboard();
                return DefWindowProc(hwnd, uMsg, wParam, lParam);
            }
            GlobalUnlock(hClip);
            CloseClipboard();
        }
        else 
        {
            printf("open error\n");
            return DefWindowProc(hwnd, uMsg, wParam, lParam);
        }
    }   
    else
    {
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
}

在程序最后要跟上winform的消息循环。

MSG msg;
while( GetMessage( &msg , hwnd , 0 , 0 ) )
{
    TranslateMessage( &msg ) ;
    DispatchMessage( &msg ) ;
}

团灭Windows进程通信(二)——剪贴板在中间_第1张图片

源码示例分享:

Windows进程通信_剪贴板 http://download.csdn.net/detail/huanglong8/9714143

针对这种剪贴板的进程通信有利有弊。毕竟微软提供的这一套措施不光是提供给开发者用的,它最重要的功能还是提供给操作用户使用。针对小而简练,并且具有剪贴板等需求的应用才会被考虑。

优点:

  • 代码简单,使用方便
  • 支持多格式传输,文本,图片, 链接等。

缺点

  • 一片内存,多个使用,容易造成混淆与数据丢失。
  • 仅用于本地进程通信。

那么这种剪贴板是共享内存,那微软也提供了共享内存机制,我们可以靠自己申请一片固有的内存地址来作为独立进程通信的共享区域,下一章则会列举及实践在Windows共享内存上如何实现本系列的需求。

你可能感兴趣的:(Windows开发)