精华内容
下载资源
问答
  • 2021-07-27 23:09:07

    变量

    设定变量

    set month=7

    使用变量

    %day%

    注释

    ::请以管理员身份运行

    比较大小

    EQU 等于

    NEQ 不等于

    LSS 小于

    LEQ 小于或等于

    GTR 大于

    GEQ 大于或等于

    if语句

    如果日期大于31,日期设定为1,月份加1。

    if %day% GTR 31 (
    set /a day=1 
    set /a month=month+1)

    while循环

    使用goto语句实现

    :while
    //循环内容
    pause
    goto :while

    输出到屏幕

    echo %date%表单数据已复制到剪切板

    输出到文本

    echo %f% >res.txt

    读取文本到剪切板

    clip < res.txt

    删除文件

    del res.txt

    暂停

    pause

    关闭回显

    @echo off

    更多相关内容
  • Android剪切板开发记录

    2021-01-03 15:27:08
    之前我一直以为验证码的来源是图片,通过对比图片的ID和用户的输入判断验证码的对错。学习之后发现其实这个模块用绘制更加简单 Canvas c = new Canvas(bp); //Android通过Canvas类暴露了很多drawXXX方法,我们可以...

    Startpage:主流APP的启动流程里,用户点击APP图标启动服务时,首先会跳出2~5s的欢迎界面,一方面这个界面可以用来缓冲连接网络和服务器获取数据更新服务的时间,避免APP内出现白屏现象,另一方面这个界面的UI设计中插入广告图片可以带来经济效益一举两得,在学生项目的开发中,使用Startpage来提高整个APP的可观赏性和流畅性。实现方法非常简单,在布局中设置一个全屏(无导航栏和状态栏)的页面,载入设计好的欢迎界面,在此界面上做一个定时跳转的Inent组件,时间设置为3s。
    MainActivity:主菜单Button Navigation Activity,基本实现了底部导航栏的功能,我只是使用了底版,其中所有的UI布局以及布局元素都是我自己设计的。底部菜单栏的Button Icon来自阿里巴巴集团的官方矢量图标及插画库AntDesign。
    关于隐藏导航栏栏:在Android Studio的模板开发中,使用的是全局导航栏即继承Manifests里的Style设置,每一个页面都会有蓝紫色的导航栏,当然导航栏的颜色是可以自定义的,但是有些页面不应该出现导航栏目,一方面让功能组件有了更多的显示区域,另一方变整个页面也变得更加好看。为了贴合主流APP的设计理念以及大众审美,在一些不需要导航栏的页面应该删除导航栏,具体参考资料来源于CSDN。但是不能将所有的导航栏都隐藏,因为在其他页面可能还会用到。所以采用的方法是在Activity文件里用代码控制是否显示导航栏,而不是在Manifests里更改APP的页面设置。
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getSupportActionBar().hide();
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

    关于圆角TextView:主流APP的文本框一般是半透明长方形圆角文本框,但是开发环境里默认的文本框都是长方形,为了使实现圆角文本框,采用Sharp设置已经编辑好的圆角文本框的.xml文件,然后在布局中引用这个.xml,实现圆角文本框,其实不管是圆角、圆形文本框、按钮等,都是通过样式设置隐藏方形的四个角来实现圆角效果。

    对于类似于Startpage和Splash这样的启动页面、欢迎页面,可以用.png资源文件(图片)作为页面的背景而不需要布局,只需要通过getwindow方法设定图片来自资源:
    this.getWindow().setBackgroundDrawableResource(R.drawable.a);
    而一般的欢迎界面一般不是固定的,而是几张图片随机出现其中的一张,这种时候我们把所有作为启动页资源的文件建立一个数组,将他们存放进去,先声明这个变量:
    int[] ImageArray = new int[]{R.drawable.b0,R.drawable.b1,R.drawable.b2};
    这样在我们的图片数组中就有了b1和b2两张图片(可以添加更多),假设我们有6张图片,然后利用random方法生成一个0~6的随机数,用来控制随机出现的图片的下标
    Random random = new Random();
    int index = random.nextInt(7);
    注意:random.nextInt(7);生成的是0~6的7个数字,不包含7
    得到了随机下标,就可以利用上面说到的getwindows来设置出现随机图片作为背景:
    this.getWindow().setBackgroundDrawableResource(ImageArray[index]);
    关于评论功能的想法:早上实验课实现了基于SharedPreferences的信息保存与提取,我需要的评论功能是:用户可以在文本框内编辑自己的评论文本,完成之后点击提交按钮调用SharedPreferences将这些文本显示到评论区。
    透明按钮:实现非常简单,只需要在xml设置里设定就可以,配合圆角按钮使用更好
    android:background="@android:color/transparent"
    打包运行后的一些问题:主页不能滑动换页收藏页面,图片蒙版做成亚克力样式,一来可以美化登陆界面,二来背景图片的深色区域不会影响到文本框的提示内容。主页回退会返回到登录界面,而一般是回退到桌面,所以需要结束掉loginactivity

    今天完成了数据库链接登陆及注册页面的功能,顺带加上了验证码验证登录。数据库表名为user,只记录ID和Password两项数据* 下面重点说一下查询表user全部内容的方法。我们查询出来的内容,需要有个容器存放,以供使用,所以定义了一个ArrayList类的list
    ArrayList list = new ArrayList();
    有了容器,接下来就该从表中查询数据了,这里使用游标Cursor,这就是数据库的功底了。
    如果需要用Cursor的话,第一个参数:“表名”,中间5个:null,最后是查询出来内容的排序方式:“name DESC”。
    Cursor cursor = db.query(“user”,null,null,null,null,null,“name DESC”);
    游标定义好了,接下来写一个while循环,让游标从表头游到表尾在游的过程中把游出来的数据存放到list容器中。
    while(cursor.moveToNext()){
    String name = cursor.getString(cursor.getColumnIndex(“name”));
    String password = cursor.getString(cursor.getColumnIndex(“password”));
    list.add(new User(name,password));
    }
    return list;

    关于验证码模块,还需要做一个详细的学习笔记。对关键技术部分进行剖析。之前我一直以为验证码的来源是图片,通过对比图片的ID和用户的输入判断验证码的对错。学习之后发现其实这个模块用绘制更加简单
    Canvas c = new Canvas(bp);
    //Android通过Canvas类暴露了很多drawXXX方法,我们可以通过这些方法绘制各种各样的图形。Canvas绘图有三个基本要素:Canvas、绘图坐标系以及Paint。Canvas是画布,我们通过Canvas的各种drawXXX方法将图形绘制到Canvas上面,在drawXXX方法中我们需要传入要绘制的图形的坐标形状,还要传入一个画笔Paint。drawXXX方法以及传入其中的坐标决定了要绘制的图形的形状,比如drawCircle方法,用来绘制圆形,需要我们传入圆心的x和y坐标,以及圆的半径。drawXXX方法中传入的画笔Paint决定了绘制的图形的一些外观,比如是绘制的图形的颜色,再比如是绘制圆面还是圆的轮廓线等。Android系统的设计吸收了很多已有系统的诸多优秀之处,比如Canvas绘图。Canvas不是Android所特有的,Flex和Silverlight都支持Canvas绘图,Canvas也是HTML5标准中的一部分,主流的现代浏览器都支持用JavaScript在Canvas上绘图,如果你用过HTML5中的Canvas,你会发现Android的Canvas的绘图API与其很相似。
    因为验证码的数据都是随机生成的,将他们转换成文本再进行验证更加简单,而且节省了存储空间。实现的主要思路是通过建立一个验证码内容数组,包括数字和大小写字母
    private String createCode() {
    StringBuilder buffer = new StringBuilder();
    for (int i = 0; i < codeLength; i++) {
    buffer.append(CHARS[random.nextInt(CHARS.length)]);
    }
    return buffer.toString();
    }
    可以根据需要去掉容易相互混淆导致认证失败的情况,例如C和G,9和q等,提高用户验证的通过率。然后每次生成验证码时随即从这个数组里抽取4个元素组合成一个4位的验证码,然后用绘图方法将它画在要显示验证码的控件里。
    Bitmap bp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    ARGB_8888: 每个像素占8位,用来保存颜色和透明度值,一共32位,即4个字节,图片质量最高。所支持的颜色种类为:红色:28,绿色:28,蓝色:2^8,一共大约1600多万种颜色为了防止机器人验证,我们可以对这些字母和数字进行一定程度的倾斜和扭曲,并且画上干扰线和干扰点。
    private void drawLine(Canvas canvas, Paint paint) {
    int color = randomColor();
    int startX = random.nextInt(width);
    int startY = random.nextInt(height);
    int stopX = random.nextInt(width);
    int stopY = random.nextInt(height);
    paint.setStrokeWidth(1);
    paint.setColor(color);
    canvas.drawLine(startX, startY, stopX, stopY, paint);
    }
    随机颜色和倾斜度详见代码。
    分模块工作下的引入须注意的事项:在这个项目的工作中,很多模块我都是单独建项目先实现,然后通过复制粘贴引入他们,其中Viedoplayer在引入之后会出现空指针错误,回看代码才发现setContentView的对象居然是(R.layout.activity_main),因为activity_main是存在于项目结构里的,所以这一句话不会报错,但让我好奇的是:用findById去定位页面里的viedoview居然不会报错,只是在启动之后会出现空指针错误。
    异常记录:1.Fragmen中跳转的相关异常
    Toast.makeText(MyFragment2.this,“正打开读书笔记”,Toast.LENGTH_SHORT).show();
    intent.setClass(MyFragment2.this,Book.class);
    如上的代码会出现MyFragment.this报错如下

    仔细分析之后可知:要在fragment中使用Intent就不能和以前一样使用了,因为没有继承Activity或者AppCompatActivity,在new的时候如果传入this是会报错的。MyFragment是建立在MainActivity里的class,它本身并不是一个Activity,但是XXX.this是Activity的写法,所以在这些应用Activity的跳转、显示方法中需要用到getActivity()方法将当前的Fragment强制转换成MainActivity,实现跳转和显示等功能正常运行。以上两句异常语句修改为:
    Toast.makeText(getActivity(),“正在打开读书笔记”,Toast.LENGTH_SHORT).show();
    intent.setClass(getActivity(),Book.class);

    异常记录:2.关于drawable和mipmap
    Mipmap:MIP map技术帮助避免了不想要的锯齿边缘(称为锯齿状图形)在图像中出现,这种锯齿状图形可能是由于在不同分辨率下使用bitmap图像产生的。为了加快渲染速度和减少图像锯齿,贴图被处理成由一系列被预先计算和优化过的图片组成的文件,这样的贴图被称为 MIP map或者 mipmap。从百度和谷歌的说明来看mipmap确实可以加快渲染速度,而且是为了解决在不同分辨率下使用bitmap产生的问题,这就不难理解Launcher图标为什么在mipmap目录下了。在Launcher界面,图标很可能因为选中效果等动画进行放大缩小,因此可以使用mipmap来让动画更加丝滑流畅。

    之所以探究上面的mipmap,是因为上图所示的报错我已经是第二次遇见了,第一次上Android实验课的时候选用户界面,大部分同学的布局背景的是使用机房电脑上老师发的素材图片,而我的背景使用的是自己电脑上的图片资料,运行时闪退debug之后报错。当时的解决方法是换了一张尺寸和大小都缩减很多的图片。这次出现问题的是在程序首页,即登陆界面完成后,加载主界面的Fragment1时出现报错:java.lang.RuntimeException:
    Canvas: trying to draw too large(154054656bytes) bitmap.这句报错的详情指的是需要绘制的图片过大,在一个OnCreat周期中不能完成这些工作。Fragment1采用的是listview显示视频封面,每一个list元素中含有两张图片,但是首页显示的这些图片加起来也只有10MB不到,为什么debug信息里会有154054656bytes这么大的数据呢。我把这句报错信息在网上检索了一下,简书上的一个个人博客上对这个问题做出了解析,但是只有一句话:当你要加载的资源来自项目文件而不是网络时,它们都应该被存储在mipmap文件夹中而不是drawable文件夹。我按这个说法修改了图片资源的路径,果然成功运行。之后我又尝试用同一张图经过PS处理降低像素之后放在drawable文件夹下,也成功地加载了出来。那为什么会有这种区别呢。Mipmap在官方文档中是用来存储需要缩放的图片素材。这些疑问我打算请教羊海潮老师。
    12.22展示意见:功能过于简单,对比市面上常见的小软件没有竞争能力,除观看视频外应该新增其他组件功能,完善学习记录时间对应日历功能和学习日志。

    展开全文
  • OLE剪贴板学习心得

    2014-02-10 15:47:13
    OLE剪贴板学习心得 MFC对OLE剪贴板的支持主要集中在两个类上,分别是 COleDataSource,COleDataObject。 其中,COleDataSource作为操作者,而COleDataObject作为消费者,换句话说,用户需要使用COleDataSource把...
    OLE剪贴板学习心得
    MFC对OLE剪贴板的支持主要集中在两个类上,分别是
    COleDataSource,COleDataObject。
    其中,COleDataSource作为操作者,而COleDataObject作为消费者,换句话说,用户需要使用COleDataSource把数据放到OLE剪贴板上,而使用COleDataObject把它取回。


    将保存在全局内存中的项目放置在OLE剪贴板上,需要进行如下步骤:
    1.在堆上(而不是在堆栈上)创建COleDataSource对象。
    2.调用COleDataSource::CacheGlobalData将HGLOBAL递交给COleDataSource对象。
    3.调用COleDataSource::SetClipboard将对象放置在
       OLE剪贴板上。
    下列使用COleDataSource在OLE剪贴板上提供了ANSI文本字符串.
    char szText[]="Hello,world";
    HANDLE hData=::GlobalAlloc(CMEM_MOVEABLB,::lstrlen(szText)+1);
    ::lstrcpy(pData,szText);
    ::GlobalUnlock(hData);
    COleDataSource * pods=new COleDataSource;
    pods->CacheGlobalData(CF_TEXT,hData);
    pods->SetClipboard();


    MFC的COleDataObject提供了从OLE剪贴板获取项目的机制。
    1.创建COleDataObject对象。
    2.调用COleDataObject::AttachClipboard将   COleDataObject连接到OLE剪贴板。
    3.使用COleDataObject::GetGlobalData获取项目。
    4.释放由GetGlobalData返回的全局内存块。
    以下为例:
       char szTect[];
       COleDataObject pdo;
       pdo.AttachClipboard();
       HANDLE hData=pdo.GetGlobalData(CF_TEXT);
      
       if(hData!=NULL)
          LPCSTR pData=(LPCSTR)::Globallock(hData);
          if(::lstrlen(pData<BUFLEN))
             ::lstrcpy(szText,pData);
          ::GlobalUnlock(hData);
          ::GlobalFree(hData);
    注意,我们以上讨论的OLE剪贴板储存媒介都是内存,下面我们将要讨论储存媒介为非内存的情况。


    COleDataSource::CacheGlobalData和COleDataObject::GetGlobalData与全局内存密不可分。但是您可以使用更一般的COleDataSource::CacheData和COleDataObject::GetData函数在其他数据类型的媒介中传送数据。
    下面例子说明如何使用文件作为传送媒体,通过前贴板来传送文本字符串。字符串首先复制到临时文件中。然后用描述文件的信息和文件包含的数据初始化FORMATETC和STGMEDIUM结构。最后信息被传送给COleDataSource::CacheData,并用COleDataSource::SetClipboar将数据对象放置在剪贴板上。
    char szText[]="Hello,world"
    TCHAR szPath[Max_path],szFileName[Max_path];
    ::GetTempPath(sizeof(szPath)/sizeof(TCHAR),szPath);
    ::GetTempFileName(szPath,_T("tmp"),0,szFileName);//分配临时文件名称。
    CFile file;
    if(file.Open(szFileName,CFile::modeCreate|CFile::modeWrite))
    {
         file.Write(szText,::lstrlen(szText)+1);
         file.Close();
         LPWSTR pwszFileName=(LPWSTR)::CoTaskMemAlloc(MAX_PATH * sizeof(WCHAR));
         #ifdef UNICODE
               ::lstrcpy(pwszFileName,szFileName);
         #else
               ::MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,szFileName,-1,pwszFileName,MAX_PATE);
         #endif
         FORMATETC fe={CF_TEXT,NULL,DVASPECT_CONTENT,-1,TYMED_FILE};
         STGMEDIUM stgm;
         stgm.tymed=TYMED_FILE;
         stgm.lpszFileName=pwszFileName;
         stgm.pUnkForRelease=NULL;
       
         COleDataSource * pods=new COleDataSource;
         pods->CacheData(CF_TEXT,&stgm,&fe);
         pods->setClipboard();
    }


    在消费者端,您可以使用COleDataObject::GetData从剪贴板获取字符串
    char szText[BUFLEN];
    STGMEDIUM stgm;
    FORMATETC fe={CF_TEXT,NULL,DVASPECT_CONTENT,-1,TYMED_FILE;}
    COleDataObject pdo;
    pdo.AttachClipboard();
    if(pdo.GetData(CF_TEXT,&stgm,&fe)&&stgm.tymed==TYMED_FILE)
    {TCHAR szFileName|Max_Path;}
    #ifdef UNICODE
         ::lstrcpy(szFileName,stgm,lpszFileName);
    #else
         ::WideCharToMultiByte(CP_ACP,0,stgm,lpszf|leName,_T,szFileName,sizeof(szFileName)/sizeof(TCHAR),NULL,NULL);
    #endif
         CFile file;
         if(file.Open(szFileName,CFile::modeRead))|DWORD dwSize=file.GetLength();
         if(dwSize<BUFLEN)
               file.Read(szText,(UNIT)dwSize);
         file.Close();
       }
       ::ReleaseStgMedium(&stgm);
    }
     
    在读取OLE剪贴板内容是,用户可以直接使用COleDataObject::GetFileData取代GetData函数。
    __________________________________________
    一)ChangeClipboardChain
    将剪贴的连接从一个句柄转到下一个句柄。
    BOOL ChangeClipboardChain(
    HWND hWndRemove, // handle to window to remove
    HWND hWndNewNext // handle to next window
    );
    (1)hWndRemove表示第一个窗口的句柄(断开)。
    (2)hWndNewNext表示第二个窗口的句柄(连接)。
    注意,在使用之前应该使用SetClipboardViewer事先进行窗口句柄的连接。
    (二)CloseClipboard
    关闭剪贴板。
    BOOL CloseClipboard(VOID)//VOID意思是空白。
    本函数没有参数,事先应该用OpenClipboard函数打开过剪贴板。
    (三)CountClipboardFormats
    不管剪贴板是什么格式,全部转化为数据格式。
    int CountClipboardFormats(VOID)
    本函数没有参数。
    (四)EmptyClipboard
    清空剪贴板。
    BOOL EmptyClipboard(VOID)
    本函数没有参数。
    (五)EnumClipboardFormats
    使剪贴板内的格式转变成指定格式。
    UINT EnumClipboardFormats(
    UINT format // specifies a known available clipboard format
    );
    其中format表示的是将要转化成的格式。该参数的意义可参照后面。
    (六)GetClipboardData
    获取剪贴板内的数据。
    HANDLE GetClipboardData(
    UINT uFormat // clipboard format
    );
    其中format表示的是剪贴板内数据的格式。该参数的意义可参照后面。
    (七)GetClipboardFormatName
    获取剪贴板内数据格式的名称。
    int GetClipboardFormatName(
    UINT format, // clipboard format to retrieve
    LPTSTR lpszFormatName, // address of buffer for name
    int cchMaxCount // length of name string in characters
    );
    (1)format表示的意义同前,应该是不事先规定格式;
    (2)lpszFormatName表示的是格式名称地址;
    (3)cchMaxCount剪贴板内数据的长度。
    (八)GetClipboardOwner
    获取当前剪贴板是属于哪一个窗口的句柄。
    HWND GetClipboardOwner(VOID)
    返回那个窗口的句柄。
    (九)GetClipboardSequenceNumber
    返回剪贴板序号。
    DWORD GetClipboardSequenceNumber(VOID)
    (十)GetClipboardViewer
    返回剪贴板属于窗口的句柄。
    HWND GetClipboardViewer(VOID)
    (十一)GetOpenClipboardWindow
    返回打开剪贴板的那个窗口句柄。
    HWND GetOpenClipboardWindow(VOID)
    (十二)GetPriorityClipboardFormat
    int GetPriorityClipboardFormat(
    UINT *paFormatPriorityList, // address of priority list
    int cFormats // number of entries in list
    );
    (十三)IsClipboardFormatAvailable
    判断剪贴板的格式。
    BOOL IsClipboardFormatAvailable(
    UINT format // clipboard format
    );
    其中format表示的是剪贴板内数据的格式。该参数的意义可参照后面。
    (十四)OpenClipboard
    打开剪贴板。
    BOOL OpenClipboard(
    HWND hWndNewOwner // handle to window opening clipboard
    );
    返回剪贴板的句柄。
    (十五)RegisterClipboardFormat
    注册新的剪贴板格式。
    UINT RegisterClipboardFormat(
    LPCTSTR lpszFormat // address of name string
    );
    lpszFormat新的剪贴板格式名称。
    (十六)SetClipboardData
    设置剪贴板内的数据。
    HANDLE SetClipboardData(
    UINT uFormat, // clipboard format
    HANDLE hMem // data handle
    );
    uFormat表示的是要放进剪贴板数据的格式;
    hMem表示数据的地址指针。
    (十七)SetClipboardViewer
    将剪贴板内容连接到窗口。
    HWND SetClipboardViewer(
    HWND hWndNewViewer // handle to clipboard viewer window
    );
    hWndNewViewer表示要连接到的那个窗口句柄。
    上文中剪贴板格式Format的可选参数如下:
    CF_BITMAP位图格式;
    CF_DIB
    CF_DIBV5
    CF_DIF
    CF_DSPBITMAP
    CF_DSPENHMETAFILE
    CF_DSPMETAFILEPICT
    CF_DSPTEXT
    CF_ENHMETAFILE
    CF_GDIOBJFIRST
    CF_GDIOBJLAST
    CF_HDROP
    CF_LOCALE
    CF_METAFILEPICT
    CF_OEMTEXT
    CF_OWNERDISPLAY
    CF_PALETTE
    CF_PENDATA
    CF_PRIVATEFIRST
    CF_PRIVATELAST
    CF_RIFF
    CF_SYLK
    CF_TEXT文本格式;
    CF_WAVE音乐格式;
    CF_TIFF
    CF_UNICODETEXT




    Windows剪贴板


       Windows剪贴板是一种比较简单同时也是开销比较小的IPC(InterProcess Communication,进程间通讯)机制。Windows系统支持剪贴板IPC的基本机制是由系统预留的一块全局共享内存,用来暂存在各进程间进行交换的数据:提供数据的进程创建一个全局内存块,并将要传送的数据移到或复制到该内存块;接受数据的进程(也可以是提供数据的进程本身)获取此内存块的句柄,并完成对该内存块数据的读取。


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


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


      文本剪贴板和位图剪贴板的使用


      这两种剪贴板是比较常用的。其中,文本剪贴板是包含具有格式CF_TEXT的字符串的剪贴板,是最经常使用的剪贴板之一。在文本剪贴板中传递的数据是不带任何格式信息的ASCII字符。若要将文本传送到剪贴板,可以先分配一个可移动全局内存块,然后将要复制的文本内容写入到此内存区域。最后调用剪贴板函数将数据放置到剪贴板:


    注意:
        下面代码中:
        1、HANDLE hGlobalMemory = GlobalAlloc(GHND, dwLength + 1);
    分配内存长度必须是dwLength + 1,否则在调用SetClipboardData时会出错;可以通过调用 int i2 = ::GlobalSize(hGlobalMemory );来查看分配的长度。


        2、hGlobalMemory不能释放,即不能调用::GlobalFree(hGlobalMemory),因为如果在一个程序中还要粘贴的话就必须不能释放,否则在同一程序中粘贴时获得的指针为NULL,但如果只在别的程序中粘贴则可以释放。


        以上两条是在编制HsfBrowserCtl(HOOPS三维浏览控件)时总结出来的。可参看原码中的复制、粘贴部分。
      DWORD dwLength = 100; // 要复制的字串长度
    HANDLE hGlobalMemory = GlobalAlloc(GHND, dwLength + 1); // 分配内存
    LPBYTE lpGlobalMemory = (LPBYTE)GlobalLock(hGlobalMemory); // 锁定内存
    for (int i = 0; i 〈 dwLength; i++) // 将"*"复制到全局内存块
     *lpGlobalMemory++ = '*';
     GlobalUnlock(hGlobalMemory); // 锁定内存块解锁
     HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄
     ::OpenClipboard(hWnd); // 打开剪贴板
     ::EmptyClipboard(); // 清空剪贴板
     ::SetClipboardData(CF_TEXT, hGlobalMemory); // 将内存中的数据放置到剪贴板
     ::CloseClipboard(); // 关闭剪贴板






      这里以OpenClipboard()打开剪贴板,并在调用了EmptyClipboard()后使hWnd指向的窗口成为剪贴板的拥有者,一直持续到 CloseClipboard()函数的调用。在此期间,剪贴板为拥有者所独占,其他进程将无法对剪贴板内容进行修改。


      从剪贴板获取文本的过程与之类似,首先打开剪贴板并获取剪贴板的数据句柄,如果数据存在就拷贝其数据到程序变量。由于GetClipboardData()获取的数据句柄是属于剪贴板的,因此用户程序必须在调用CloseClipboard()函数之前使用它:






      HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄
    ::OpenClipboard(hWnd); // 打开剪贴板
    HANDLE hClipMemory = ::GetClipboardData(CF_TEXT);// 获取剪贴板数据句柄
    DWORD dwLength = GlobalSize(hClipMemory); // 返回指定内存区域的当前大小
    LPBYTE lpClipMemory = (LPBYTE)GlobalLock(hClipMemory); // 锁定内存
    m_sMessage = CString(lpClipMemory); // 保存得到的文本数据
    GlobalUnlock(hClipMemory); // 内存解锁
    ::CloseClipboard(); // 关闭剪贴板






      大多数应用程序对图形数据采取的是位图的剪贴板数据格式。位图剪贴板的使用与文本剪贴板的使用是类似的,只是数据格式要指明为CF_BITMAP,而且在使用SetClipboardData()或GetClipboardData()函数时交给剪贴板或从剪贴板返回的是设备相关位图句柄。下面这段示例代码将把存在于剪贴板中的位图数据显示到程序的客户区:






      HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄
    ::OpenClipboard(hWnd); // 打开剪贴板
    HANDLE hBitmap = ::GetClipboardData(CF_BITMAP); // 获取剪贴板数据句柄
    HDC hDC = ::GetDC(hWnd); // 获取设备环境句柄
    HDC hdcMem = CreateCompatibleDC(hDC); // 创建与设备相关的内存环境
    SelectObject(hdcMem, hBitmap); // 选择对象
    SetMapMode(hdcMem, GetMapMode(hDC)); // 设置映射模式
    BITMAP bm; // 得到位图对象
    GetObject(hBitmap, sizeof(BITMAP), &bm);
    BitBlt(hDC, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY); //位图复制
    ::ReleaseDC(hWnd, hDC); // 释放设备环境句柄
    DeleteDC(hdcMem); // 删除内存环境
    ::CloseClipboard(); // 关闭剪贴板










    多数据项和延迟提交技术


      要把数据放入剪贴板,在打开剪贴板后一定要调用EmptyClipboard()函数清除当前剪贴板中的内容,而不可以在原有数据项基础上追加新的数据项。但是,可以在EmptyClipboard()和CloseClipboard()调用之间多次调用SetClipboardData()函数来放置多个不同格式的数据项。例如:






      OpenClipboard(hWnd);
    EmptyClipboardData();
    SetClipboardData(CF_TEXT, hGMemText);
    SetClipboardData(CF_BITMAP, hBitmap);
    CloseClipboard();






      这时如果用CF_TEXT或CF_BITMAP等格式标记去调用IsClipboardFormatAvailable()都将返回TRUE,表明这几种格式的数据同时存在于剪贴板中。以不同的格式标记去调用GetClipboardData()函数可以得到相应的数据句柄。


      对于多数据项的剪贴板数据,还可以用CountClipboardFormats()和EnumClipboardFormats()函数得到当前剪贴板中存在的数据格式数目和具体的数据格式。EnumClipboardFormats()的函数原型为:






      UINT EnumClipboardFormats(UINT format);






      参数format指定了剪贴板的数据格式。如果成功执行将返回format指定的格式的下一个数据格式值,如果format为最后的数据格式值,那么将返回0。由此不难写出处理剪贴板中所有格式数据项的程序段代码:






      UINT format = 0; // 从第一种格式值开始枚举
    OpenClipboard(hWnd);
    while(format = EnumClipboardFormats(format))
    {
    …… // 对相关格式数据的处理
    }
    CloseClipboard();






      在数据提供进程创建了剪贴板数据后,一直到有其他进程获取剪贴板数据前,这些数据都要占据内存空间。如在剪贴板放置的数据量过大,就会浪费内存空间,降低对资源的利用率。为避免这种浪费,可以采取延迟提交(Delayed rendering)技术,即由数据提供进程先创建一个指定数据格式的空(NULL)剪贴板数据块,直到有其他进程需要数据或自身进程要终止运行时才真正提交数据。


      延迟提交的实现并不复杂,只需剪贴板拥有者进程在调用SetClipboardData()将数据句柄参数设置为NULL 即可。延迟提交的拥有者进程需要做的主要工作是对WM_RENDERFORMAT、WM_DESTORYCLIPBOARD和 WM_RENDERALLFORMATS等剪贴板延迟提交消息的处理。


      当另一个进程调用GetClipboardData()函数时,系统将会向延迟提交数据的剪贴板拥有者进程发送WM_RENDERFORMAT消息。剪贴板拥有者进程在此消息的响应函数中应使用相应的格式和实际的数据句柄来调用SetClipboardData()函数,但不必再调用OpenClipboard()和EmptyClipboard()去打开和清空剪贴板了。在设置完数据有也无须调用CloseClipboard()关闭剪贴板。如果其他进程打开了剪贴板并且调用EmptyClipboard()函数去清空剪贴板的内容,接管剪贴板的拥有权时,系统将向延迟提交的剪贴板拥有者进程发送WM_DESTROYCLIPBOARD消息,以通知该进程对剪贴板拥有权的丧失。而失去剪贴板拥有权的进程在收到该消息后则不会再向剪贴板提交数据。另外,在延迟提交进程在提交完所有要提交的数据后也会收到此消息。如果延迟提交剪贴板拥有者进程将要终止,系统将会为其发送一条WM_RENDERALLFORMATS消息,通知其打开并清除剪贴板内容。在调用 SetClipboardData()设置各数据句柄后关闭剪贴板。


      下面这段代码将完成对数据的延迟提交,WM_RENDERFORMAT消息响应函数OnRenderFormat()并不会立即执行,当有进程调用GetClipboardData()函数从剪贴板读取数据时才会发出该消息。在消息处理函数中完成对数据的提交:


      进行延迟提交:






      HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄
    ::OpenClipboard(hWnd); // 打开剪贴板
    ::EmptyClipboard(); // 清空剪贴板
    ::SetClipboardData(CF_TEXT, NULL); // 进行剪贴板数据的延迟提交
    ::CloseClipboard(); // 关闭剪贴板






      在WM_RENDERFORMAT消息的响应函数中:






      DWORD dwLength = 100; // 要复制的字串长度
    HANDLE hGlobalMemory = GlobalAlloc(GHND, dwLength + 1); // 分配内存块
    LPBYTE lpGlobalMemory = (LPBYTE)GlobalLock(hGlobalMemory); // 锁定内存块
    for (int i = 0; i 〈 dwLength; i++) // 将"*"复制到全局内存块
    *lpGlobalMemory++ = '*';
    GlobalUnlock(hGlobalMemory); // 锁定内存块解锁
    ::SetClipboardData(CF_TEXT, hGlobalMemory); // 将内存中的数据放置到剪贴板
        DSP和自定义数据格式的使用


       Windows系统预定义了三个带“DSP”前缀的数据格式:CF_DSPTEXT、CF_DSPBITMAP和 CF_DSPMETAFILEPICT。这是一些伪标准格式,用于表示在程序中定义的私有剪贴板数据格式。对于不同的程序,这些格式的规定是不同的,因此这些格式只针对某一具体程序的不同实例才有意义。


      为使用DSP数据格式,必须确保进程本身与剪贴板拥有者进程同属一个程序。可以调用GetClipboardOwner()函数来获取剪贴板拥有者窗口句柄,并调用GetClassName()来获取窗口类名:


    HWND hClipOwner = GetClipboardOwner();
    GetClassName(hClipOwner, &ClassName, 255);


      如果剪贴板拥有者窗口类名同本进程的窗口类名一致,就可以使用带有DSP前缀的剪贴板数据格式了。
    除了使用Windows预定义的剪贴板数据格式外,也可以在程序中使用自定义的数据格式。对于自定义的数据格式lpszFormat,可以调用RegisterClipboardFormat()函数来登记,并获取其返回的格式标识值:


    UINT format = RegisterClipboardFormat(lpszFormat);


      对此返回的格式标识值的使用与系统预定义的格式标识是一样的。可以通过GetClipboardFormatName()函数来获取自定义格式的ASCII名。


      小结


      本文主要对Windows编程中的剪贴板机制作了较为深入的讨论,对其中常用的文本、位图、DSP和自定义数据格式的使用方法以及多数据项和延迟提交等重要技术一并做了阐述。并给出了具体的程序示例代码,使读者能够更好的掌握剪贴板机制的使用。




    功能实现:复制位图到剪切阪。


    今日看了下COleDataSource的原码和网上的文章。


    COleDataSource用内嵌类实现了IDataObject接口
    //COPY HBITMAP To CilpBoard
    void CMyView::OnEditCopy()
    {


        COLORREF BACKGROUND_COLOR = #ffffff;
        tagSTGMEDIUM * data;
        CBitmap * junk;
        COleDataSource* pData = new COleDataSource;
        data = new tagSTGMEDIUM;
        junk = new CBitmap();
        CClientDC cdc(this);
        CDC dc;
        dc.CreateCompatibleDC(&cdc);
        CRect client;
        //replace this with something that calculates
        //the proper rectangle size
        GetClientRect(client);
        junk->CreateCompatibleBitmap(&cdc,client.Width(),client.Height());
        dc.SelectObject(junk);
        CBrush fill(BACKGROUND_COLOR);
        dc.FillRect(client,&fill);
        //replace this with something that draws to a CDC
        OnDraw(&dc);
        data->tymed = TYMED_GDI;
        data->hBitmap = HBITMAP(*junk);
        pData->CacheData( CF_BITMAP, data );
        pData->SetClipboard();
        delete data;
        delete junk;
        //delete pData;
    }


    另转载一篇文章,讲的不怎样,但可参看一下


    利用MFC实现对象拖放


      对象拖放是指对某一指定的对象,利用鼠标拖动的方法,在不同应用的窗口
    之间、同一应用的不同窗口之间或同一应用的同一窗口内进行移动、复制(粘贴)
    等操作的技术。
      利用对象拖放,可以为用户提供方便、直观的操作界面。
    实现对象拖放技术,需要了解、使用MFC的CView、COleDataSource和COleDropTarget
    等类,并利用这些类协同工作。
    本文讨论了对象拖放技术,并研究了如何利用MFC实现该技术。
    利用MFC实现对象拖放,编程比较容易,代码可读性好。
    修改稿
    利用MFC实现对象拖放
    1.对象拖放概念
      对象拖放是指对某一指定的对象,利用鼠标拖动的方法,在不同应用的窗口
    之间、同一应用的不同窗口之间或同一应用的同一窗口内进行移动、复制(粘贴)
    等操作的技术。
      对象拖放是在操作系统的帮助下完成的。 要开始一次拖动, 首先需要指定
    或生成被拖动的对象,然后指定整个拖放操作过程所使用的数据格式,并按指定
    的数据格式提供数据,最后启动对象拖放操作;当对象在某一窗口内落下时,拖
    放过程结束,接收拖放对象的窗口按指定的数据格式提取有关数据,并根据提取
    的数据生成对象。
    2.MFC中用于对象拖放的类
    MFC(Microsoft Foundation ClassLibrary)为实现对象拖放提供了如下三个类。
    为便于后边的
    讨论我们先来熟悉一下这些类。
    2.1.COleDataSource。用于启动一次拖放操作,并向系统提供拖放对象的数据。
    类中的成员
    函数有如下三种:
    a.设定提供数据的方式和使用的数据格式。提供数据的方式有两种,一种是即时
    方式,另一种是延迟方式;即时方式需要在拖动开始之前提供数据;延迟方式不
    需要立即提供数据,当系统请求有关数据时,由OnRenderData()等虚函数提供所
    需的数据。
    可以用CacheGlobalData()等函数指定使用即时方式提供数据,也可以用
    DelayRenderData()等函数指定使用延时方式提供数据。
    b.响应请求,提供数据。应当重载OnRenderFileData()或其他相应的虚函数,以
    提供有关数据(后边将详细讨论)。
    c.实施拖放操作。调用函数DoDragDrop(),开始实施拖放操作。
    2.2.OleDataTarget。用于准备接收拖放对象的目标窗口;一个窗口要想能够接收
    拖放对象,必须包含一个COleDataTarget对象,并注册该对象。类中主要成员函数:
    a.注册。函数Register()注册该对象,以便使窗口能够接收拖放对象。
    b.响应拖放过程中的动作(虚成员函数) 当鼠标首次进入窗口时系统将调用
    OnDragEnter(),当鼠标移出窗口时系统将调用OnDragLeave(), 当鼠标在窗口内移动,
    系统将重复调用调用OnDragOver(),当对象在窗口内落下调用OnDrop()。
    2.3.OleDataObject.用于接收拖放对象,类中主要成员函数有两种:
    a.确定可以使用的数据格式。IsDataAvailable()等函数确定指定数据格式是否可用;
    b.获取数据。GetData()、GetFileData()等函数用于按指定数据格式获得数据。
    3.利用MFC实现对象拖放
       要实现一次对象拖放,需要做三方面的工作:对象所在的窗口准备拖放对象并启拖动操作,
    接受对象的窗口响应有关拖放消息并接受落下的对象,以及拖放完成时的后期处理。
    以下分别予以介绍。
    3.1. 拖动操作的启动。拖放操作一般是从单击鼠标左键开始。在消息WM_LBUTTONDOWN的响应
    函数OnLButtonDown(...)中,首先要判定是否选定了某一对象,如果未选定或选定多个,则不能进
    行拖放操作;如果选定了一个对象,则可以进行拖放操作。
    要启动一次拖放操作,需要先准备一个COleDataSource对象。注意到类COleClientIten和类
    COleServerItem都是从类COleDataSource上派生的,如果选定的是COleClientItem对象或者是
    COleServerItem对象,则可以直接使用;否则,需要生成一个COleDataSource对象,值得注意的
    是:需要象上文中所说的,应该指定使用的数据格式,并按指定格式提供对象的有关数据。
    下面给出准备数据源的例子:
    class myDataSource: public COleDataSource
    public:
    COLORREF color;
    CString str;
    protected:
    virtual BOOL OnRenderFileData(LPFORMATETC,CFile*);
    //......
    };
    BOOL myDataSource::OnRenderFileData(LPFORMATETC lpFormatEtc,CFile* pFile)
    if(lpFormatEtc->cfFormat==CF_TEXT)
    pFile.Write("Test DragDrop",13); //Magic String
    pFile.Write(&color,sizeof(COLORREF));
    int len= str.GetLength();
    pFile.Write(&len,sizeof(int));
    pFile.Write(str,len);
    return TRUE;
    COleDataSource::OnRenderFileData(lpFormatEtc,pFile);
    return FALSE;
      有了以上数据源之后,就可以在消息WM_LBUTTON的响应函数OnLButtonDown()中,按如下方式,指定使用的数据格式:
    myDataSource* pItemDragDrop=new myDataSource;
    pItemDragDrop->str="This string will dragdrop to another place";
    pItemDragDrop->DelayRenderFileData(CF_TEXT,NULL);
      指定好使用的数据格式之后,调用此对象的成员函数DoDragDrop(...),启动对象拖放操作。
    需要注意的是,函数DoDragDrop(...)并不立即返回,而是要等到鼠标按钮弹起之后。
    3.2. 拖放对象的接收。缺省情况下,一般的窗口是不能接收拖放对象的;要使窗口可以接收拖
    放对象,需要在窗口类定义中加入成员对象COleDropTarget,并在生成窗口时调用函数
    COleDataTarget::Register()。例如:
    Class myView : public CScrollView
    private:
    COleDropTarget oleTarget;
    protected:
    virtual int OnCreate(LPCREATESTRUCT);
    //......
    int myView::OnCreate(LPCREATESTRUCT lpCreateStruct)
      //......
      dropTarget.Register(this);
      return 0;
    为实现拖放对象的接收,还应重载CView或COleDropTarget的虚函数:COnDragMove()、
    OnDragEnter()和OnDrop()等。函数OnDragEnter()、OnDragMove()应根据鼠标在窗口中的位置,
    返回以下数值:
    DROPEFFECT_MOVE---表明可以把对象复制到现在的窗口、现在的位置;
    DROPEFFECT_COPY---表明可以把对象从原来的窗口、原来的位置移到现在的窗口、现在的位置;
    DROPEFFECT_NONE---表明不能在该窗口的该位置放下。
    下例只允许移动对象,而不允许复制对象:
    DROPEFFECT myView::OnDragEnter(......)
      return DROPEFFECT_MOVE;
    DROPEFFECT myView::OnDragOver(......)
    return DROPEFFECT_MOVE;
    函数OnDrop()应处理拖动对象放下后的工作。该函数的参数pDataObjec指向一个
    COleDataObject对象,利用指针,可以获取有关数据。该函数的一般实现是:
    a.检查对象的数据格式: 利用函数COleDataObject::IsDataAvailable();
    b.按指定的格式获取数据:利用COleDataObject::GetFileData()等函数;
    c.建立对象(可能与原对象相同,也可能不建立对象仅使用对象中的数据):利用以上步骤
    得到的数据建立对象。例如:
    char magic_string[13];
    COLORREF color;
    CString str;
    int len;
    myDataSource* pMyData;
    if(IsDataAvailable(CF_TEXT))
    CFile file=GetFileData(CF_TEXT);
    file.Read(magic_string,13);
    if(strncmp(magic_string,"Test DragDrop",13)==0)
    file.Read(&color,sizeof(COLORREF));
    file.Read(&len,sizeof(int));
    file.Read(str,len);
    CClientDC dc(this);
    dc.SetTextColor(color);
    dc.SetBkMode(TRANSPARENT);
    dc.TextOut(100,50,str,len);
    pMyData=new myDataSource;
    pMyData->color=color;
    pMyData->str=str;
    对于COleClientItem或COleServerItem对象,可以按以下方法很容易地重建对象:
    COleClient* pItem=GetDocument()->CreateNewItem();
    pItem->CreateFrom(pDataObject);
    3.3. 拖放操作的结束函数DoDragDrop()返回时,拖放过程结束。函数DoDragDrop()的返回值,
    表明了对象的拖放结果。
    DROPEFFECT_MOVE:对象被放到他处,需删除原对象
    DROPEFFECT_COPY:对象被复制到他处,不删除原对象
    DROPEFFECT_NONE:未能实现拖放,无需删除原对象
    例如:
    int DragEffect=pItemTracking->DoDragDrop(......);
    switch(DragEffect)
    case DROPEFFECT_MOVE:
    delete pItemTracking;
    GetDocument()->UpdateAllItems(NULL);
    GetDocument()->UpdateAllViews(NULL);
    break;
    case DROPEFFECT_COPY:
    case DROPEFFECT_NONE:
    default:
    break;
    *********************
    想构建一个自己的粘贴版
    需要Hook的函数
    写粘贴板
    EmptyClipboardData();//清空自己的粘贴板
    SetClipboardData(CF_TEXT, hGMemText);
    SetClipboardData(CF_BITMAP, hBitmap);


    读粘贴版
    GetClipboardData(CF_TEXT,);
    GetClipboardData(CF_BITMAP)
    展开全文
  • 剪贴的连接从一个句柄转到下一个句柄。 BOOL ChangeClipboardChain( HWND hWndRemove, // handle to window to remove HWND hWndNewNext // handle to next window ); (1)hWndRemove表示第一个窗口的...

    (一)ChangeClipboardChain 

    将剪贴的连接从一个句柄转到下一个句柄。
    BOOL ChangeClipboardChain(
    HWND hWndRemove, // handle to window to remove
    HWND hWndNewNext // handle to next window
    );
    (1)hWndRemove表示第一个窗口的句柄(断开)。
    (2)hWndNewNext表示第二个窗口的句柄(连接)。
    注意,在使用之前应该使用SetClipboardViewer事先进行窗口句柄的连接。
    (二)CloseClipboard
    关闭剪贴板。
    BOOL CloseClipboard(VOID)//VOID意思是空白。
    本函数没有参数,事先应该用OpenClipboard函数打开过剪贴板。
    (三)CountClipboardFormats
    不管剪贴板是什么格式,全部转化为数据格式。
    int CountClipboardFormats(VOID)
    本函数没有参数。
    (四)EmptyClipboard
    清空剪贴板。
    BOOL EmptyClipboard(VOID)
    本函数没有参数。
    (五)EnumClipboardFormats
    使剪贴板内的格式转变成指定格式。
    UINT EnumClipboardFormats(
    UINT format // specifies a known available clipboard format
    );
    其中format表示的是将要转化成的格式。该参数的意义可参照后面。
    (六)GetClipboardData
    获取剪贴板内的数据。
    HANDLE GetClipboardData(
    UINT uFormat // clipboard format
    );
    其中format表示的是剪贴板内数据的格式。该参数的意义可参照后面。
    (七)GetClipboardFormatName
    获取剪贴板内数据格式的名称。
    int GetClipboardFormatName(
    UINT format, // clipboard format to retrieve
    LPTSTR lpszFormatName, // address of buffer for name
    int cchMaxCount // length of name string in characters
    );
    (1)format表示的意义同前,应该是不事先规定格式;
    (2)lpszFormatName表示的是格式名称地址;
    (3)cchMaxCount剪贴板内数据的长度。
    (八)GetClipboardOwner
    获取当前剪贴板是属于哪一个窗口的句柄。
    HWND GetClipboardOwner(VOID)
    返回那个窗口的句柄。
    (九)GetClipboardSequenceNumber
    返回剪贴板序号。
    DWORD GetClipboardSequenceNumber(VOID)
    (十)GetClipboardViewer
    返回剪贴板属于窗口的句柄。
    HWND GetClipboardViewer(VOID)
    (十一)GetOpenClipboardWindow
    返回打开剪贴板的那个窗口句柄。
    HWND GetOpenClipboardWindow(VOID)
    (十二)GetPriorityClipboardFormat
    int GetPriorityClipboardFormat(
    UINT *paFormatPriorityList, // address of priority list
    int cFormats // number of entries in list
    );
    (十三)IsClipboardFormatAvailable
    判断剪贴板的格式。
    BOOL IsClipboardFormatAvailable(
    UINT format // clipboard format
    );
    其中format表示的是剪贴板内数据的格式。该参数的意义可参照后面。
    (十四)OpenClipboard
    打开剪贴板。
    BOOL OpenClipboard(
    HWND hWndNewOwner // handle to window opening clipboard
    );
    返回剪贴板的句柄。
    (十五)RegisterClipboardFormat
    注册新的剪贴板格式。
    UINT RegisterClipboardFormat(
    LPCTSTR lpszFormat // address of name string
    );
    lpszFormat新的剪贴板格式名称。
    (十六)SetClipboardData
    设置剪贴板内的数据。
    HANDLE SetClipboardData(
    UINT uFormat, // clipboard format
    HANDLE hMem // data handle
    );
    uFormat表示的是要放进剪贴板数据的格式;
    hMem表示数据的地址指针。
    (十七)SetClipboardViewer
    将剪贴板内容连接到窗口。
    HWND SetClipboardViewer(
    HWND hWndNewViewer // handle to clipboard viewer window
    );
    hWndNewViewer表示要连接到的那个窗口句柄。
    上文中剪贴板格式Format的可选参数如下:
    CF_BITMAP位图格式;
    CF_DIB
    CF_DIBV5
    CF_DIF
    CF_DSPBITMAP
    CF_DSPENHMETAFILE
    CF_DSPMETAFILEPICT
    CF_DSPTEXT
    CF_ENHMETAFILE
    CF_GDIOBJFIRST
    CF_GDIOBJLAST
    CF_HDROP
    CF_LOCALE
    CF_METAFILEPICT
    CF_OEMTEXT
    CF_OWNERDISPLAY
    CF_PALETTE
    CF_PENDATA
    CF_PRIVATEFIRST
    CF_PRIVATELAST
    CF_RIFF
    CF_SYLK
    CF_TEXT文本格式;
    CF_WAVE音乐格式;
    CF_TIFF
    CF_UNICODETEXT


    Windows剪贴板

       Windows剪贴板是一种比较简单同时也是开销比较小的IPC(InterProcess Communication,进程间通讯)机制。Windows系统支持剪贴板IPC的基本机制是由系统预留的一块全局共享内存,用来暂存在各进程间进行 交换的数据:提供数据的进程创建一个全局内存块,并将要传送的数据移到或复制到该内存块;接受数据的进程(也可以是提供数据的进程本身)获取此内存块的句 柄,并完成对该内存块数据的读取。

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

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

      文本剪贴板和位图剪贴板的使用

       这两种剪贴板是比较常用的。其中,文本剪贴板是包含具有格式CF_TEXT的字符串的剪贴板,是最经常使用的剪贴板之一。在文本剪贴板中传递的数据是不 带任何格式信息的ASCII字符。若要将文本传送到剪贴板,可以先分配一个可移动全局内存块,然后将要复制的文本内容写入到此内存区域。最后调用剪贴板函 数将数据放置到剪贴板:

    注意:
    下面代码中:
    1、HANDLE hGlobalMemory = GlobalAlloc(GHND, dwLength + 1);
    分配内存长度必须是dwLength + 1,否则在调用SetClipboardData时会出错;可以通过调用 int i2 = ::GlobalSize(hGlobalMemory );来查看分配的长度。

    2、hGlobalMemory不能释放,即不能调用::GlobalFree(hGlobalMemory),因为如果在一个程序中还要粘贴的话就必须不能释放,否则在同一程序中粘贴时获得的指针为NULL,但如果只在别的程序中粘贴则可以释放。

    以上两条是在编制HsfBrowserCtl(HOOPS三维浏览控件)时总结出来的。可参看原码中的复制、粘贴部分。
      DWORD dwLength = 100; // 要复制的字串长度
    HANDLE hGlobalMemory = GlobalAlloc(GHND, dwLength + 1); // 分配内存
    LPBYTE lpGlobalMemory = (LPBYTE)GlobalLock(hGlobalMemory); // 锁定内存
    for (int i = 0; i 〈 dwLength; i++) // 将"*"复制到全局内存块
     *lpGlobalMemory++ = '*';
     GlobalUnlock(hGlobalMemory); // 锁定内存块解锁
     HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄
     ::OpenClipboard(hWnd); // 打开剪贴板
     ::EmptyClipboard(); // 清空剪贴板
     ::SetClipboardData(CF_TEXT, hGlobalMemory); // 将内存中的数据放置到剪贴板
     ::CloseClipboard(); // 关闭剪贴板



       这里以OpenClipboard()打开剪贴板,并在调用了EmptyClipboard()后使hWnd指向的窗口成为剪贴板的拥有者,一直持续到 CloseClipboard()函数的调用。在此期间,剪贴板为拥有者所独占,其他进程将无法对剪贴板内容进行修改。

      从剪贴板获取文本的过程与之类似,首先打开剪贴板并获取剪贴板的数据句柄,如果数据存在就拷贝其数据到程序变量。由于GetClipboardData()获取的数据句柄是属于剪贴板的,因此用户程序必须在调用CloseClipboard()函数之前使用它:



      HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄
    ::OpenClipboard(hWnd); // 打开剪贴板
    HANDLE hClipMemory = ::GetClipboardData(CF_TEXT);// 获取剪贴板数据句柄
    DWORD dwLength = GlobalSize(hClipMemory); // 返回指定内存区域的当前大小
    LPBYTE lpClipMemory = (LPBYTE)GlobalLock(hClipMemory); // 锁定内存
    m_sMessage = CString(lpClipMemory); // 保存得到的文本数据
    GlobalUnlock(hClipMemory); // 内存解锁
    ::CloseClipboard(); // 关闭剪贴板



       大多数应用程序对图形数据采取的是位图的剪贴板数据格式。位图剪贴板的使用与文本剪贴板的使用是类似的,只是数据格式要指明为CF_BITMAP,而且 在使用SetClipboardData()或GetClipboardData()函数时交给剪贴板或从剪贴板返回的是设备相关位图句柄。下面这段示例 代码将把存在于剪贴板中的位图数据显示到程序的客户区:



      HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄
    ::OpenClipboard(hWnd); // 打开剪贴板
    HANDLE hBitmap = ::GetClipboardData(CF_BITMAP); // 获取剪贴板数据句柄
    HDC hDC = ::GetDC(hWnd); // 获取设备环境句柄
    HDC hdcMem = CreateCompatibleDC(hDC); // 创建与设备相关的内存环境
    SelectObject(hdcMem, hBitmap); // 选择对象
    SetMapMode(hdcMem, GetMapMode(hDC)); // 设置映射模式
    BITMAP bm; // 得到位图对象
    GetObject(hBitmap, sizeof(BITMAP), &bm);
    BitBlt(hDC, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY); //位图复制
    ::ReleaseDC(hWnd, hDC); // 释放设备环境句柄
    DeleteDC(hdcMem); // 删除内存环境
    ::CloseClipboard(); // 关闭剪贴板





    多数据项和延迟提交技术

       要把数据放入剪贴板,在打开剪贴板后一定要调用EmptyClipboard()函数清除当前剪贴板中的内容,而不可以在原有数据项基础上追加新的数据 项。但是,可以在EmptyClipboard()和CloseClipboard()调用之间多次调用SetClipboardData()函数来放置 多个不同格式的数据项。例如:



      OpenClipboard(hWnd);
    EmptyClipboardData();
    SetClipboardData(CF_TEXT, hGMemText);
    SetClipboardData(CF_BITMAP, hBitmap);
    CloseClipboard();



       这时如果用CF_TEXT或CF_BITMAP等格式标记去调用IsClipboardFormatAvailable()都将返回TRUE,表明这几 种格式的数据同时存在于剪贴板中。以不同的格式标记去调用GetClipboardData()函数可以得到相应的数据句柄。

      对于多数据项的剪贴板数据,还可以用CountClipboardFormats()和EnumClipboardFormats()函数得到当前剪贴板中存在的数据格式数目和具体的数据格式。EnumClipboardFormats()的函数原型为:



      UINT EnumClipboardFormats(UINT format);



      参数format指定了剪贴板的数据格式。如果成功执行将返回format指定的格式的下一个数据格式值,如果format为最后的数据格式值,那么将返回0。由此不难写出处理剪贴板中所有格式数据项的程序段代码:



      UINT format = 0; // 从第一种格式值开始枚举
    OpenClipboard(hWnd);
    while(format = EnumClipboardFormats(format))
    {
    …… // 对相关格式数据的处理
    }
    CloseClipboard();



       在数据提供进程创建了剪贴板数据后,一直到有其他进程获取剪贴板数据前,这些数据都要占据内存空间。如在剪贴板放置的数据量过大,就会浪费内存空间,降 低对资源的利用率。为避免这种浪费,可以采取延迟提交(Delayed rendering)技术,即由数据提供进程先创建一个指定数据格式的空(NULL)剪贴板数据块,直到有其他进程需要数据或自身进程要终止运行时才真正 提交数据。

      延迟提交的实现并不复杂,只需剪贴板拥有者进程在调用SetClipboardData()将数据句柄参数设置为NULL 即可。延迟提交的拥有者进程需要做的主要工作是对WM_RENDERFORMAT、WM_DESTORYCLIPBOARD和 WM_RENDERALLFORMATS等剪贴板延迟提交消息的处理。

      当另一个进程调用GetClipboardData()函数 时,系统将会向延迟提交数据的剪贴板拥有者进程发送WM_RENDERFORMAT消息。剪贴板拥有者进程在此消息的响应函数中应使用相应的格式和实际的 数据句柄来调用SetClipboardData()函数,但不必再调用OpenClipboard()和EmptyClipboard()去打开和清空 剪贴板了。在设置完数据有也无须调用CloseClipboard()关闭剪贴板。如果其他进程打开了剪贴板并且调用EmptyClipboard()函 数去清空剪贴板的内容,接管剪贴板的拥有权时,系统将向延迟提交的剪贴板拥有者进程发送WM_DESTROYCLIPBOARD消息,以通知该进程对剪贴 板拥有权的丧失。而失去剪贴板拥有权的进程在收到该消息后则不会再向剪贴板提交数据。另外,在延迟提交进程在提交完所有要提交的数据后也会收到此消息。如 果延迟提交剪贴板拥有者进程将要终止,系统将会为其发送一条WM_RENDERALLFORMATS消息,通知其打开并清除剪贴板内容。在调用 SetClipboardData()设置各数据句柄后关闭剪贴板。

      下面这段代码将完成对数据的延迟提交,WM_RENDERFORMAT消息响应函数OnRenderFormat()并不会立即执行,当有进程调用GetClipboardData()函数从剪贴板读取数据时才会发出该消息。在消息处理函数中完成对数据的提交:

      进行延迟提交:



      HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄
    ::OpenClipboard(hWnd); // 打开剪贴板
    ::EmptyClipboard(); // 清空剪贴板
    ::SetClipboardData(CF_TEXT, NULL); // 进行剪贴板数据的延迟提交
    ::CloseClipboard(); // 关闭剪贴板



      在WM_RENDERFORMAT消息的响应函数中:



      DWORD dwLength = 100; // 要复制的字串长度
    HANDLE hGlobalMemory = GlobalAlloc(GHND, dwLength + 1); // 分配内存块
    LPBYTE lpGlobalMemory = (LPBYTE)GlobalLock(hGlobalMemory); // 锁定内存块
    for (int i = 0; i 〈 dwLength; i++) // 将"*"复制到全局内存块
    *lpGlobalMemory++ = '*';
    GlobalUnlock(hGlobalMemory); // 锁定内存块解锁
    ::SetClipboardData(CF_TEXT, hGlobalMemory); // 将内存中的数据放置到剪贴板
    DSP和自定义数据格式的使用

       Windows系统预定义了三个带“DSP”前缀的数据格式:CF_DSPTEXT、CF_DSPBITMAP和 CF_DSPMETAFILEPICT。这是一些伪标准格式,用于表示在程序中定义的私有剪贴板数据格式。对于不同的程序,这些格式的规定是不同的,因此 这些格式只针对某一具体程序的不同实例才有意义。

      为使用DSP数据格式,必须确保进程本身与剪贴板拥有者进程同属一个程序。可以调用GetClipboardOwner()函数来获取剪贴板拥有者窗口句柄,并调用GetClassName()来获取窗口类名:

    HWND hClipOwner = GetClipboardOwner();
    GetClassName(hClipOwner, &ClassName, 255);

      如果剪贴板拥有者窗口类名同本进程的窗口类名一致,就可以使用带有DSP前缀的剪贴板数据格式了。
    除了使用Windows预定义的剪贴板数据格式外,也可以在程序中使用自定义的数据格式。对于自定义的数据格式lpszFormat,可以调用RegisterClipboardFormat()函数来登记,并获取其返回的格式标识值:

    UINT format = RegisterClipboardFormat(lpszFormat);

      对此返回的格式标识值的使用与系统预定义的格式标识是一样的。可以通过GetClipboardFormatName()函数来获取自定义格式的ASCII名。

      小结

      本文主要对Windows编程中的剪贴板机制作了较为深入的讨论,对其中常用的文本、位图、DSP和自定义数据格式的使用方法以及多数据项和延迟提交等重要技术一并做了阐述。并给出了具体的程序示例代码,使读者能够更好的掌握剪贴板机制的使用。


    功能实现:复制位图到剪切阪。

    今日看了下COleDataSource的原码和网上的文章。

    COleDataSource用内嵌类实现了IDataObject接口
    //COPY HBITMAP To CilpBoard
    void CMyView::OnEditCopy()
    {

    COLORREF BACKGROUND_COLOR = #ffffff;
    tagSTGMEDIUM * data;
    CBitmap * junk;
    COleDataSource* pData = new COleDataSource;
    data = new tagSTGMEDIUM;
    junk = new CBitmap();
    CClientDC cdc(this);
    CDC dc;
    dc.CreateCompatibleDC(&cdc);
    CRect client;
    //replace this with something that calculates
    //the proper rectangle size
    GetClientRect(client);
    junk->CreateCompatibleBitmap(&cdc,client.Width(),client.Height());
    dc.SelectObject(junk);
    CBrush fill(BACKGROUND_COLOR);
    dc.FillRect(client,&fill);
    //replace this with something that draws to a CDC
    OnDraw(&dc);
    data->tymed = TYMED_GDI;
    data->hBitmap = HBITMAP(*junk);
    pData->CacheData( CF_BITMAP, data );
    pData->SetClipboard();
    delete data;
    delete junk;
    //delete pData;
    }

    另转载一篇文章,讲的不怎样,但可参看一下

    利用MFC实现对象拖放

      对象拖放是指对某一指定的对象,利用鼠标拖动的方法,在不同应用的窗口
    之间、同一应用的不同窗口之间或同一应用的同一窗口内进行移动、复制(粘贴)
    等操作的技术。
      利用对象拖放,可以为用户提供方便、直观的操作界面。
    实现对象拖放技术,需要了解、使用MFC的CView、COleDataSource和COleDropTarget
    等类,并利用这些类协同工作。
    本文讨论了对象拖放技术,并研究了如何利用MFC实现该技术。
    利用MFC实现对象拖放,编程比较容易,代码可读性好。
    修改稿
    利用MFC实现对象拖放
    1.对象拖放概念
      对象拖放是指对某一指定的对象,利用鼠标拖动的方法,在不同应用的窗口
    之间、同一应用的不同窗口之间或同一应用的同一窗口内进行移动、复制(粘贴)
    等操作的技术。
      对象拖放是在操作系统的帮助下完成的。 要开始一次拖动, 首先需要指定
    或生成被拖动的对象,然后指定整个拖放操作过程所使用的数据格式,并按指定
    的数据格式提供数据,最后启动对象拖放操作;当对象在某一窗口内落下时,拖
    放过程结束,接收拖放对象的窗口按指定的数据格式提取有关数据,并根据提取
    的数据生成对象。
    2.MFC中用于对象拖放的类
    MFC(Microsoft Foundation ClassLibrary)为实现对象拖放提供了如下三个类。
    为便于后边的
    讨论我们先来熟悉一下这些类。
    2.1.COleDataSource。用于启动一次拖放操作,并向系统提供拖放对象的数据。
    类中的成员
    函数有如下三种:
    a.设定提供数据的方式和使用的数据格式。提供数据的方式有两种,一种是即时
    方式,另一种是延迟方式;即时方式需要在拖动开始之前提供数据;延迟方式不
    需要立即提供数据,当系统请求有关数据时,由OnRenderData()等虚函数提供所
    需的数据。
    可以用CacheGlobalData()等函数指定使用即时方式提供数据,也可以用
    DelayRenderData()等函数指定使用延时方式提供数据。
    b.响应请求,提供数据。应当重载OnRenderFileData()或其他相应的虚函数,以
    提供有关数据(后边将详细讨论)。
    c.实施拖放操作。调用函数DoDragDrop(),开始实施拖放操作。
    2.2.OleDataTarget。用于准备接收拖放对象的目标窗口;一个窗口要想能够接收
    拖放对象,必须包含一个COleDataTarget对象,并注册该对象。类中主要成员函数:
    a.注册。函数Register()注册该对象,以便使窗口能够接收拖放对象。
    b.响应拖放过程中的动作(虚成员函数) 当鼠标首次进入窗口时系统将调用
    OnDragEnter(),当鼠标移出窗口时系统将调用OnDragLeave(), 当鼠标在窗口内移动,
    系统将重复调用调用OnDragOver(),当对象在窗口内落下调用OnDrop()。
    2.3.OleDataObject.用于接收拖放对象,类中主要成员函数有两种:
    a.确定可以使用的数据格式。IsDataAvailable()等函数确定指定数据格式是否可用;
    b.获取数据。GetData()、GetFileData()等函数用于按指定数据格式获得数据。
    3.利用MFC实现对象拖放
       要实现一次对象拖放,需要做三方面的工作:对象所在的窗口准备拖放对象并启拖动操作,
    接受对象的窗口响应有关拖放消息并接受落下的对象,以及拖放完成时的后期处理。
    以下分别予以介绍。
    3.1. 拖动操作的启动。拖放操作一般是从单击鼠标左键开始。在消息WM_LBUTTONDOWN的响应
    函数OnLButtonDown(...)中,首先要判定是否选定了某一对象,如果未选定或选定多个,则不能进
    行拖放操作;如果选定了一个对象,则可以进行拖放操作。
    要启动一次拖放操作,需要先准备一个COleDataSource对象。注意到类COleClientIten和类
    COleServerItem都是从类COleDataSource上派生的,如果选定的是COleClientItem对象或者是
    COleServerItem对象,则可以直接使用;否则,需要生成一个COleDataSource对象,值得注意的
    是:需要象上文中所说的,应该指定使用的数据格式,并按指定格式提供对象的有关数据。
    下面给出准备数据源的例子:
    class myDataSource: public COleDataSource
    public:
    COLORREF color;
    CString str;
    protected:
    virtual BOOL OnRenderFileData(LPFORMATETC,CFile*);
    //......
    };
    BOOL myDataSource::OnRenderFileData(LPFORMATETC lpFormatEtc,CFile* pFile)
    if(lpFormatEtc->cfFormat==CF_TEXT)
    pFile.Write("Test DragDrop",13); //Magic String
    pFile.Write(&color,sizeof(COLORREF));
    int len= str.GetLength();
    pFile.Write(&len,sizeof(int));
    pFile.Write(str,len);
    return TRUE;
    COleDataSource::OnRenderFileData(lpFormatEtc,pFile);
    return FALSE;
      有了以上数据源之后,就可以在消息WM_LBUTTON的响应函数OnLButtonDown()中,按如下方式,指定使用的数据格式:
    myDataSource* pItemDragDrop=new myDataSource;
    pItemDragDrop->str="This string will dragdrop to another place";
    pItemDragDrop->DelayRenderFileData(CF_TEXT,NULL);
      指定好使用的数据格式之后,调用此对象的成员函数DoDragDrop(...),启动对象拖放操作。
    需要注意的是,函数DoDragDrop(...)并不立即返回,而是要等到鼠标按钮弹起之后。
    3.2. 拖放对象的接收。缺省情况下,一般的窗口是不能接收拖放对象的;要使窗口可以接收拖
    放对象,需要在窗口类定义中加入成员对象COleDropTarget,并在生成窗口时调用函数
    COleDataTarget::Register()。例如:
    Class myView : public CScrollView
    private:
    COleDropTarget oleTarget;
    protected:
    virtual int OnCreate(LPCREATESTRUCT);
    //......
    int myView::OnCreate(LPCREATESTRUCT lpCreateStruct)
      //......
      dropTarget.Register(this);
      return 0;
    为实现拖放对象的接收,还应重载CView或COleDropTarget的虚函数:COnDragMove()、
    OnDragEnter()和OnDrop()等。函数OnDragEnter()、OnDragMove()应根据鼠标在窗口中的位置,
    返回以下数值:
    DROPEFFECT_MOVE---表明可以把对象复制到现在的窗口、现在的位置;
    DROPEFFECT_COPY---表明可以把对象从原来的窗口、原来的位置移到现在的窗口、现在的位置;
    DROPEFFECT_NONE---表明不能在该窗口的该位置放下。
    下例只允许移动对象,而不允许复制对象:
    DROPEFFECT myView::OnDragEnter(......)
      return DROPEFFECT_MOVE;
    DROPEFFECT myView::OnDragOver(......)
    return DROPEFFECT_MOVE;
    函数OnDrop()应处理拖动对象放下后的工作。该函数的参数pDataObjec指向一个
    COleDataObject对象,利用指针,可以获取有关数据。该函数的一般实现是:
    a.检查对象的数据格式: 利用函数COleDataObject::IsDataAvailable();
    b.按指定的格式获取数据:利用COleDataObject::GetFileData()等函数;
    c.建立对象(可能与原对象相同,也可能不建立对象仅使用对象中的数据):利用以上步骤
    得到的数据建立对象。例如:
    char magic_string[13];
    COLORREF color;
    CString str;
    int len;
    myDataSource* pMyData;
    if(IsDataAvailable(CF_TEXT))
    CFile file=GetFileData(CF_TEXT);
    file.Read(magic_string,13);
    if(strncmp(magic_string,"Test DragDrop",13)==0)
    file.Read(&color,sizeof(COLORREF));
    file.Read(&len,sizeof(int));
    file.Read(str,len);
    CClientDC dc(this);
    dc.SetTextColor(color);
    dc.SetBkMode(TRANSPARENT);
    dc.TextOut(100,50,str,len);
    pMyData=new myDataSource;
    pMyData->color=color;
    pMyData->str=str;
    对于COleClientItem或COleServerItem对象,可以按以下方法很容易地重建对象:
    COleClient* pItem=GetDocument()->CreateNewItem();
    pItem->CreateFrom(pDataObject);
    3.3. 拖放操作的结束函数DoDragDrop()返回时,拖放过程结束。函数DoDragDrop()的返回值,
    表明了对象的拖放结果。
    DROPEFFECT_MOVE:对象被放到他处,需删除原对象
    DROPEFFECT_COPY:对象被复制到他处,不删除原对象
    DROPEFFECT_NONE:未能实现拖放,无需删除原对象
    例如:
    int DragEffect=pItemTracking->DoDragDrop(......);
    switch(DragEffect)
    case DROPEFFECT_MOVE:
    delete pItemTracking;
    GetDocument()->UpdateAllItems(NULL);
    GetDocument()->UpdateAllViews(NULL);
    break;
    case DROPEFFECT_COPY:
    case DROPEFFECT_NONE:
    default:
    break;
    *********************
    想构建一个自己的粘贴版
    需要Hook的函数
    写粘贴板
    EmptyClipboardData();//清空自己的粘贴板
    SetClipboardData(CF_TEXT, hGMemText);
    SetClipboardData(CF_BITMAP, hBitmap);

    读粘贴版
    GetClipboardData(CF_TEXT,);
    GetClipboardData(CF_BITMAP); 
    展开全文
  • Windows剪贴板允许把数据从一个程序传送到另一个程序中。它的原理相对而言比较简单,把数据存放到剪贴板上的程序或从剪贴板上取出数据的程序都无须太多的负担。数据格式CF_TEXT以NULL结尾的ANSI字符集字符串。它在每...
  • 12.2 剪贴板的高级用法

    千次阅读 2015-11-19 17:06:50
    摘录于《Windows程序(第5版,... 如前所述,在数据准备好后向剪贴板传输数据需要四个函数调用: OopnClipboard (hwnd); EmptyClipboard(); SetClipboardData(iFormat, hGlobal); CloseClipboard();  而要取得这些
  • 12.1 剪贴板的简单用法

    千次阅读 2015-11-19 13:43:55
     让我们先看看把数据传入剪贴板(剪切和复制)和从剪贴板中取得数据(粘贴)的代码。 12.1.1 剪贴板数据的标准格式  Windows 支持各种预定义的剪贴板格式,这些格式在 WINUSER.H 中定义并有前缀为 CF 的标识符。  ...
  • 代码如下:(谨以参考) Private Sub Command1_... Then Clipboard.SetText Text1.SelText '理解:如果Text1文本框选定的文字不是空则把剪切板的内容设置为Text1选中的文字 End SubPrivate Sub Command2_Cl...
  • 在进行脚本编写的时候,有时候我们需要判断当前的条件是否符合我们要执行的命令,这时候便可以使用if语句if语句格式:单条件判断:if 判断条件;then条件判断为真时执行的代码命令fi双条件判断:if 判断条件;then条件...
  • 激光波前的剪切测试

    2021-02-08 21:28:31
    考虑到染料激光器的出射波前基本质量、功率与光斑大小等特点,系统选择了三平板剪切干涉作为基本干涉光路和一阶微分法被面复原算法;讨论了优化和工程化方法——对单幅干涉图进行自动数字化采集的智能化判断技术,包括...
  • 剪贴板所有api函数

    2009-11-14 16:26:00
    编写剪贴板相关程序是收集的相关API函数。(一)ChangeClipboardChain 将剪贴的连接从一个句柄转到下一个句柄。 BOOL ChangeClipboardChain( HWND hWndRemove, // handle to window to remove HWND hWndNewNext // ...
  • 剪贴板所有api函数

    千次阅读 2009-06-26 16:07:00
    剪贴板所有api函数 [转大富翁笔记]这是我在编写剪贴板相关程序是收集的相关API函数。(一)ChangeClipboardChain 将剪贴的连接从一个句柄转到下一个句柄。 BOOL ChangeClipboardChain( HWND hWndRemove, // handle to ...
  • 作为一种基于Windows的开发工具,Delphi支持如下四种数据交换方式:剪贴板、动态数据交换 ( DDE)、对象联接与嵌入(OLE)以及动态联接库(DLLs)。这中间前三种方式最为常用,OLE功能最为强大,DDE次之。而剪贴板使用...
  • 随着纤维增强树脂基复合材料(Fiber reinforced plastic, FRP)结构设计水平和制造能力的提升,FRP在结构上的应用由少及多、由次要变主要、由...数值仿真尽管不能完全代替试验,但可为FRP结构性能评估和优化设计提供依...
  • vc++中进程通信之剪贴板常用函数本人节选自《21天学通VC++》一书 操作系统中实现同一台机器上的不同进程之间的通信是非常重要的。一般来说,进程间的通信方法有三种:剪贴板、邮槽和管道。由于后两种方式需要一定的...
  • 在使用DOS时划给的临时区域 答案:A 24.word97在某个文档窗口中进行了多次剪切操作,并关闭了该文档窗口后,剪贴板中的内容为 。 A.第一次剪切的内容 B.最后一次剪切的内容 C.所有剪切的内容 D.空白 答案:B 25.word...
  • (填空、判断、选择) 一、填空题 1、为了保证机器或结构物正常地工作,要求每个构件都有足够的抵抗破坏的能力,即要求它们有足够的 强度 ;同时要求他们有足够的抵抗变形的能力,即要求它们有足够的 刚度 ;另外,...
  • 第七章 剪贴板和动态数据交换(一) 应用程序间的数据交换是象Windows 这样的多任务环境的重要特性。作为一种基于Windows的开发工具,Delphi支持如下四种数据交换方式:剪贴板、动态数据交换 ( DDE)、对象联接...
  • 微机题(判断

    2021-07-05 09:22:33
    该楼层疑似违规已被系统折叠隐藏此楼查看此楼342、CD-ROM是只读光盘。()343、灰色命令项表示当前条件下该命令不能被执行。( )344、在Windows的中文输入方式...(X)347、只有对活动窗口才能进性移动、改变大小等操作...
  • input输入框限制只能输入数字

    千次阅读 2019-12-20 10:59:19
    昨天博主接到一个需求说form表单里面的input输入框有些你得给它限制一下,不要比如有些限制一下只能让他输入数字,不能让客户输入文字或者英文 我这边给大家提供两种方法来实现这个功能,当然,我把相关情况也在这给大家...
  • ( √ ) 129、 在剪切、复制时,必须要启动剪贴板查看程序。( × ) 130、 快捷方式就是原对象,删除它,就删除了原文件。( × ) 131、 快捷方式只是指向对象的指针,其图标左下角有一个小箭头。( √ ) 132、 ...
  • 验证码数字与字母识别

    千次阅读 2018-03-26 11:13:36
    *判断剪切后图片的数字或字母数量,判断方法(图片中所有有为1的列,挨着此列的右边那一列如果一个1都没有表示为一个数字的结束。因为没有连续) */ for(int j=0;j;j++){ if(j){ labe:for(int ...
  • windows消息大全,常数值查询用

    千次阅读 2019-04-24 08:22:41
    windows消息大全,常数值查询用 消息,就是指Windows发出的一个通知,告诉应用程序某个事情发生了。例如,单击鼠标、改变窗口尺寸、按下键盘上的一个键都会使Windows 发送一个消息给应用程序。消息本身是作为一个...
  • 1. 数字图像处理与识别 2. MATLAB基础 图像灰度变换和几何变换 3. 图像的点运算 4. 图像的几何运算 图像增强:空域和频域 5. 空域图像增强 6. 频域图像增强 小波变换 7. 小波变换 图像复原 8. 图像复原 彩色图像处理...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 9,642
精华内容 3,856
关键字:

判断剪贴板数字大小