多年前写过一篇文章《C# 实现IM聊天信息输入显示控件(1)-显示GIF动画图片》,主要是使用ActiveX控件实现RichTextBox插入gif动画图片,包括使用QQ的ImageOle和飞信使用的DynamicGifCtl,这2种方式都需要先注册ActiveX。后续发现QQ新版本没有再使用ImageOle,最近刚好有这方面的需求,于是通过万能的谷歌,找到了相关的资料,不敢独享,于是就有了这篇文章。

一、致谢

  感谢大神万大侠,没有他的系列文章和介绍,我也不可能写下这篇文章。我只是在他提供的控件基础上进行简单的封装,以便用于.NET。万大侠的系列文章地址:致力于richedit应用于IM解决方案

二、im_richedit简介

  万大侠的im_richedit提供了2个抽象类和一个函数供实现一个IMRichTextBox,它们分别是:

  1、IMRichEditDelegate类

class IMRichEditDelegate {
public:
virtual void EraseBackground(HDC dc, const RECT& rect) = 0;
virtual void PostRenderRichObject(ULONG richobject_id,
HDC dc, const RECT& rect) = 0;
};

  2、IMRichEdit类

class IMRichEdit {
public:
virtual void DeleteThis() = 0;
virtual int GetCharSize() const = 0;
virtual void SetCharSize(int size) = 0;
virtual BSTR GetCharFace() const = 0; // 注意, 返回的BSTR需要释放!!!
virtual void SetCharFace(const wchar_t* face_name) = 0;
virtual bool GetCharBold() const = 0;
virtual void SetCharBold(bool bold) = 0;
virtual bool GetCharItalic() const = 0;
virtual void SetCharItalic(bool italic) = 0;
virtual COLORREF GetCharColor() const = 0;
virtual void SetCharColor(COLORREF color) = 0;
virtual int GetSelectionCharSize() const = 0;
virtual void SetSelectionCharSize(int size) = 0;
virtual BSTR GetSelectionCharFace() const = 0;
virtual void SetSelectionCharFace(const wchar_t* face_name) = 0;
virtual bool GetSelectionCharBold() const = 0;
virtual void SetSelectionCharBold(bool bold) = 0;
virtual bool GetSelectionCharItalic() const = 0;
virtual void SetSelectionCharItalic(bool italic) = 0;
virtual COLORREF GetSelectionCharColor() const = 0;
virtual void SetSelectionCharColor(COLORREF color) = 0;
virtual int SaveSelectionCharFormat() = 0;
virtual bool RestoreSelectionCharFormat(int save_state) = 0;
virtual void SelectAll() = 0;
virtual void Cut() = 0;
virtual void Copy() = 0;
virtual void Paste() = 0;
virtual void ResetContent() = 0;
virtual void SetCaretToEnd() = 0;
virtual void ScrollToCaret() = 0;
virtual void InsertText(const wchar_t* text) = 0;
virtual bool InsertLink(const wchar_t* text) = 0;
virtual void InsertBreak() = 0;
virtual ULONG InsertRichObject(IMRichObjectType type) = 0;
virtual ULONG GetRichObjectId(IOleObject* ole_object) const = 0;
virtual bool GetRichObjectType(ULONG richobject_id,
IMRichObjectType* type) const = 0;
// picture_filepath缓冲区大小为MAX_PATH.
virtual bool GetRichObjectPicture(ULONG richobject_id,
wchar_t* picture_filepath) const = 0;
virtual bool SetRichObjectPicture(ULONG richobject_id,
const wchar_t* picture_filepath) = 0;
// Tag含义:
// IMRichObjectCustomPicture: 自定义
// IMRichObjectSystemPicture: 系统编号
// IMRichObjectFancyCharacter: 字符值
virtual bool GetRichObjectTag(ULONG richobject_id, int* tag) const = 0;
virtual bool SetRichObjectTag(ULONG richobject_id, int tag) = 0;
virtual bool GetRichObjectFrameCount(ULONG richobject_id,
UINT* frame_count) const = 0;
virtual bool GetRichObjectCurremtFrame(ULONG richobject_id,
UINT* current_frame) const = 0;
};

  3、CreateIMRichEdit函数

IM_RICHEDIT_EXPORT im_richedit::IMRichEdit* CreateIMRichEdit(
IRichEditOle* richedit_ole, im_richedit::IMRichEditDelegate* delegate);

三、.NET IMRichTextBox实现

  主要参考万大侠提供的示例,使用C++/CLI对im_richedit进行封装。

1、IMRichEditDelegate抽象类实现

  IMRichEditDelegateImpl.h

#pragma once
#include "im_richedit/im_richedit_sdk.h" namespace Starts2000
{
namespace Forms
{
namespace Control
{
class IMRichEditDelegateImpl : public im_richedit::IMRichEditDelegate
{
public:
IMRichEditDelegateImpl();
void EraseBackground(HDC dc, const RECT& rect);
void PostRenderRichObject(ULONG richobject_id, HDC dc, const RECT& rect);
};
}
}
}

  IMRichEditDelegateImpl.cpp

#include "IMRichEditDelegateImpl.h"

namespace Starts2000
{
namespace Forms
{
namespace Control
{
using namespace System::Drawing; IMRichEditDelegateImpl::IMRichEditDelegateImpl()
{
} void IMRichEditDelegateImpl::EraseBackground(HDC dc, const RECT& rect)
{
COLORREF old_color = ::SetBkColor(dc, GetSysColor(COLOR_WINDOW));
if (old_color != CLR_INVALID)
{
::ExtTextOut(dc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
::SetBkColor(dc, old_color);
}
} void IMRichEditDelegateImpl::PostRenderRichObject(ULONG richobjectId,
HDC dc, const RECT& rect)
{
}
}
}
}

2、定义IIMRichTextBox接口,并使用万大侠提供的IMRichEdit抽象类进行实现。

  IIMRichTextBox.h

#pragma once

#include "im_richedit/im_richedit_sdk.h"

namespace Starts2000
{
namespace Forms
{
namespace Control
{
using namespace System;
using namespace System::Drawing;
using namespace System::Runtime::InteropServices; public enum struct IMRichObjectType
{
CustomPicture = im_richedit::IMRichObjectCustomPicture,
SystemPicture = im_richedit::IMRichObjectSystemPicture,
FancyCharacter = im_richedit::IMRichObjectFancyCharacter
}; public interface class IIMRichTextBox
{
Int32 GetCharSize() = 0;
void SetCharSize(Int32 size) = 0;
String^ GetCharFace() = 0; // 注意, 返回的BSTR需要释放!!!
void SetCharFace(String^ faceNname) = 0;
Boolean GetCharBold() = 0;
void SetCharBold(Boolean bold) = 0;
Boolean GetCharItalic() = 0;
void SetCharItalic(Boolean italic) = 0;
Color GetCharColor() = 0;
void SetCharColor(Color color) = 0;
Int32 GetSelectionCharSize() = 0;
void SetSelectionCharSize(Int32 size) = 0;
String^ GetSelectionCharFace() = 0;
void SetSelectionCharFace(String^ faceName) = 0;
Boolean GetSelectionCharBold() = 0;
void SetSelectionCharBold(Boolean bold) = 0;
Boolean GetSelectionCharItalic() = 0;
void SetSelectionCharItalic(Boolean italic) = 0;
Color GetSelectionCharColor() = 0;
void SetSelectionCharColor(Color color) = 0;
Int32 SaveSelectionCharFormat() = 0;
Boolean RestoreSelectionCharFormat(int saveState) = 0;
void SelectAll() = 0;
void Cut() = 0;
void Copy() = 0;
void Paste() = 0;
void ResetContent() = 0;
void SetCaretToEnd() = 0;
void ScrollToCaret() = 0;
void InsertText(String^ text) = 0;
Boolean InsertLink(String^ text) = 0;
void InsertBreak() = 0;
UInt32 InsertRichObject(IMRichObjectType type) = 0;
UInt32 GetRichObjectId(IntPtr oleObjectPtr) = 0;
Boolean GetRichObjectType(UInt32 richobjectId, [Out] IMRichObjectType %type) = 0;
// picture_filepath缓冲区大小为MAX_PATH.
Boolean GetRichObjectPicture(UInt32 richobjectId, String^ pictureFilePath) = 0;
Boolean SetRichObjectPicture(UInt32 richobjectId, String^ pictureFilePath) = 0;
// Tag含义:
// IMRichObjectCustomPicture: 自定义
// IMRichObjectSystemPicture: 系统编号
// IMRichObjectFancyCharacter: 字符值
Boolean GetRichObjectTag(UInt32 richobjectId, [Out] IMRichObjectType %tag) = 0;
Boolean SetRichObjectTag(UInt32 richobjectId, IMRichObjectType tag) = 0;
Boolean GetRichObjectFrameCount(UInt32 richobjectId, [Out] Int32 %frameCount) = 0;
Boolean GetRichObjectCurremtFrame(UInt32 richobjectId, [Out] Int32 %currentFrame) = 0; void InsertImage(String^ fileName) = 0;
};
}
}
}

  IMRichTextBoxWrapper.h

#pragma once

#include <msclr\marshal.h>
# include <vcclr.h>
#include "IIMRichTextBox.h" namespace Starts2000
{
namespace Forms
{
namespace Control
{
using msclr::interop::marshal_as; ref class IMRichTextBoxWrapper : public IIMRichTextBox
{
private:
im_richedit::IMRichEdit* _imRichEdit;
public:
IMRichTextBoxWrapper(im_richedit::IMRichEdit* imRichEdit)
{
_imRichEdit = imRichEdit;
} virtual Int32 GetCharSize() sealed
{
return _imRichEdit->GetCharSize();
}; virtual void SetCharSize(Int32 size) sealed
{
return _imRichEdit->SetCharSize(size);
}; virtual String^ GetCharFace() sealed
{
BSTR bstr = _imRichEdit->GetCharFace();
String^ str = marshal_as<String^>(bstr);
delete bstr;
return str;
};// 注意, 返回的BSTR需要释放!!! virtual void SetCharFace(String^ faceName) sealed
{
pin_ptr<const WCHAR> pFaceName = PtrToStringChars(faceName);
_imRichEdit->SetCharFace(pFaceName);
}; virtual Boolean GetCharBold() sealed
{
return _imRichEdit->GetCharBold();
}; virtual void SetCharBold(Boolean bold) sealed
{
_imRichEdit->SetCharBold(bold);
}; virtual Boolean GetCharItalic() sealed
{
return _imRichEdit->GetCharItalic();
}; virtual void SetCharItalic(Boolean italic) sealed
{
_imRichEdit->SetCharItalic(italic);
}; virtual Color GetCharColor() sealed
{
COLORREF colorRef = _imRichEdit->GetCharColor();
return ColorTranslator::FromWin32(colorRef);
}; virtual void SetCharColor(Color color) sealed
{
_imRichEdit->SetCharColor(ColorTranslator::ToWin32(color));
}; virtual Int32 GetSelectionCharSize() sealed
{
return _imRichEdit->GetSelectionCharSize();
}; virtual void SetSelectionCharSize(Int32 size) sealed
{
_imRichEdit->SetSelectionCharSize(size);
}; virtual String^ GetSelectionCharFace() sealed
{
BSTR bstr = _imRichEdit->GetSelectionCharFace();
String^ str = marshal_as<String^>(bstr);
delete bstr;
return str;
}; virtual void SetSelectionCharFace(String^ faceName) sealed
{
pin_ptr<const WCHAR> pFaceName = PtrToStringChars(faceName);
_imRichEdit->SetSelectionCharFace(pFaceName);
}; virtual Boolean GetSelectionCharBold() sealed
{
return _imRichEdit->GetSelectionCharBold();
}; virtual void SetSelectionCharBold(Boolean bold) sealed
{
_imRichEdit->SetSelectionCharBold(bold);
}; virtual Boolean GetSelectionCharItalic() sealed
{
return _imRichEdit->GetSelectionCharItalic();
}; virtual void SetSelectionCharItalic(Boolean italic) sealed
{
_imRichEdit->SetSelectionCharItalic(italic);
}; virtual Color GetSelectionCharColor() sealed
{
COLORREF colorRef = _imRichEdit->GetSelectionCharColor();
return ColorTranslator::FromWin32(colorRef);
}; virtual void SetSelectionCharColor(Color color) sealed
{
_imRichEdit->SetSelectionCharColor(ColorTranslator::ToWin32(color));
}; virtual Int32 SaveSelectionCharFormat() sealed
{
return _imRichEdit->SaveSelectionCharFormat();
}; virtual Boolean RestoreSelectionCharFormat(int saveState) sealed
{
return _imRichEdit->RestoreSelectionCharFormat(saveState);
}; virtual void SelectAll() sealed
{
_imRichEdit->SelectAll();
}; virtual void Cut() sealed
{
_imRichEdit->Cut();
}; virtual void Copy() sealed
{
_imRichEdit->Copy();
}; virtual void Paste() sealed
{
_imRichEdit->Paste();
}; virtual void ResetContent() sealed
{
_imRichEdit->ResetContent();
}; virtual void SetCaretToEnd() sealed
{
_imRichEdit->SetCaretToEnd();
}; virtual void ScrollToCaret() sealed
{
_imRichEdit->ScrollToCaret();
}; virtual void InsertText(String^ text) sealed
{
pin_ptr<const WCHAR> pText = PtrToStringChars(text);
_imRichEdit->InsertText(pText);
}; virtual Boolean InsertLink(String^ text) sealed
{
pin_ptr<const WCHAR> pText = PtrToStringChars(text);
return _imRichEdit->InsertLink(pText);
}; virtual void InsertBreak() sealed
{
_imRichEdit->InsertBreak();
}; virtual UInt32 InsertRichObject(IMRichObjectType type) sealed
{
return _imRichEdit->InsertRichObject(
static_cast<im_richedit::IMRichObjectType>(type));
}; virtual UInt32 GetRichObjectId(IntPtr oleObjectPtr) sealed
{
return _imRichEdit->GetRichObjectId(
reinterpret_cast<IOleObject *>(oleObjectPtr.ToPointer()));
}; virtual Boolean GetRichObjectType(
UInt32 richobjectId, [Out] IMRichObjectType %type) sealed
{
im_richedit::IMRichObjectType objType;
bool rel = _imRichEdit->GetRichObjectType(richobjectId, &objType);
type = static_cast<IMRichObjectType>(objType);
return rel;
}; // picture_filepath缓冲区大小为MAX_PATH.
virtual Boolean GetRichObjectPicture(
UInt32 richobjectId, String^ pictureFilePath) sealed
{
wchar_t *pFilePath = new wchar_t[MAX_PATH];
bool rel = _imRichEdit->GetRichObjectPicture(richobjectId, pFilePath);
pictureFilePath = marshal_as<String^>(pFilePath);
return rel;
}; virtual Boolean SetRichObjectPicture(
UInt32 richobjectId, String^ pictureFilePath) sealed
{
pin_ptr<const WCHAR> pFileName = PtrToStringChars(pictureFilePath);
return _imRichEdit->SetRichObjectPicture(richobjectId, pFileName);
}; // Tag含义:
// IMRichObjectCustomPicture: 自定义
// IMRichObjectSystemPicture: 系统编号
// IMRichObjectFancyCharacter: 字符值
virtual Boolean GetRichObjectTag(
UInt32 richobjectId, [Out] IMRichObjectType %tag) sealed
{
int iTag;
bool rel = _imRichEdit->GetRichObjectTag(richobjectId, &iTag);
tag = static_cast<IMRichObjectType>(iTag);
return rel;
}; virtual Boolean SetRichObjectTag(UInt32 richobjectId, IMRichObjectType tag) sealed
{
return _imRichEdit->SetRichObjectTag(
richobjectId, static_cast<im_richedit::IMRichObjectType>(tag));
}; virtual Boolean GetRichObjectFrameCount(
UInt32 richobjectId, [Out] Int32 %frameCount) sealed
{
UINT uiFrameCount;
bool rel = _imRichEdit->GetRichObjectFrameCount(richobjectId, &uiFrameCount);
frameCount = uiFrameCount;
return rel;
}; virtual Boolean GetRichObjectCurremtFrame(
UInt32 richobjectId, [Out] Int32 %currentFrame) sealed
{
UINT uiCurrentFrame;
bool rel = _imRichEdit->GetRichObjectCurremtFrame(richobjectId, &uiCurrentFrame);
currentFrame = uiCurrentFrame;
return rel;
}; virtual void InsertImage(String^ fileName) sealed
{
ULONG id = _imRichEdit->InsertRichObject(im_richedit::IMRichObjectSystemPicture);
pin_ptr<const WCHAR> pFileName = PtrToStringChars(fileName);
_imRichEdit->SetRichObjectPicture(id, pFileName);
};
};
}
}
}

3、通过继承.NET的RichTextBox,实现IMRichTextBox

  IMRichTextBox主要通过IIMRichTextBox接口定义的IMRichTextBoxWrapper属性来使用万大侠封装的im_richedi的功能。

  IMRichTextBox.h

#pragma once

#include "im_richedit/im_richedit_sdk.h"
#include "AutoNative.h"
#include "IMRichEditDelegateImpl.h"
#include "IMRichTextBoxWrapper.h" #pragma comment(lib, "im_richedit/im_richedit.lib") namespace Starts2000
{
namespace Forms
{
namespace Control
{
using namespace System;
using namespace System::Diagnostics;
using namespace System::Windows::Forms;
using namespace System::Security::Permissions; public ref class IMRichTextBox : public RichTextBox
{
public:
IMRichTextBox();
property IIMRichTextBox^ IMRichTextBoxWrapper
{
IIMRichTextBox^ get()
{
return _imRichTextBoxWrapper;
}
}
protected:
[SecurityPermission(SecurityAction::LinkDemand, Flags = SecurityPermissionFlag::UnmanagedCode)]
void WndProc(System::Windows::Forms::Message %msg) override;
private:
IMRichEditDelegateImpl* _imRichEditDelegate;
im_richedit::IMRichEdit* _imRichEdit;
IIMRichTextBox^ _imRichTextBoxWrapper;
};
}
}
}

  IMRichTextBox.cpp

#include "IMRichTextBox.h"

namespace Starts2000
{
namespace Forms
{
namespace Control
{
IMRichTextBox::IMRichTextBox() : RichTextBox()
{
RichTextBox::HideSelection = false;
} void IMRichTextBox::WndProc(Message %msg)
{
if (msg.Msg > 2)
{
__super::WndProc(msg);
return;
} HWND richEditHwnd = NULL;
LPRICHEDITOLE lpRichEditOle = NULL; switch (msg.Msg)
{
case WM_CREATE:
__super::WndProc(msg);
richEditHwnd = reinterpret_cast<HWND>(Handle.ToPointer());
::SendMessage(richEditHwnd, EM_GETOLEINTERFACE, 0, reinterpret_cast<LPARAM>(&lpRichEditOle));
#ifdef _DEBUG
Debug::Assert(lpRichEditOle != NULL);
#endif _imRichEditDelegate = new IMRichEditDelegateImpl();
_imRichEdit = ::CreateIMRichEdit(lpRichEditOle, _imRichEditDelegate);
_imRichTextBoxWrapper = gcnew Starts2000::Forms::Control::IMRichTextBoxWrapper(_imRichEdit);
break;
case WM_DESTROY:
if (_imRichEdit)
{
_imRichEdit->DeleteThis();
_imRichEdit = NULL;
} if (_imRichEditDelegate != NULL)
{
delete _imRichEditDelegate;
_imRichEditDelegate = NULL;
}
__super::WndProc(msg);
break;
default:
__super::WndProc(msg);
break;
}
}
}
}
}

四、示例及效果

  IMRichTextBox不能通过工具箱直接拖到窗体设计器上,只能手动添加代码。

using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using Starts2000.Forms.Control; namespace Starts2000.RichEditDemo
{
public partial class FormMain : Form
{
IMRichTextBox _imRichTextBox; public FormMain()
{
InitializeComponent();
_imRichTextBox = new IMRichTextBox();
_imRichTextBox.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom;
_imRichTextBox.Location = new Point(3, 3);
_imRichTextBox.Width = ClientSize.Width - 6;
_imRichTextBox.Height = ClientSize.Height - 40;
Controls.Add(_imRichTextBox);
} private void btnInsertImage_Click(object sender, EventArgs e)
{
OpenFileDialog dialog = new OpenFileDialog();
dialog.DefaultExt = "gif";
dialog.Filter = "图片文件|*.jpg;*.gif;*.bmp";
dialog.Multiselect = true;
if (dialog.ShowDialog() == DialogResult.OK)
{
foreach (var imgFile in dialog.FileNames)
{
_imRichTextBox.IMRichTextBoxWrapper.InsertImage(imgFile);
}
}
_imRichTextBox.IMRichTextBoxWrapper.ScrollToCaret();
} private void btnInserText_Click(object sender, EventArgs e)
{
var wrapper = _imRichTextBox.IMRichTextBoxWrapper;
var path = Application.StartupPath; wrapper.SaveSelectionCharFormat();
wrapper.SetSelectionCharColor(Color.FromArgb(0, 102, 0));
wrapper.InsertText("Starts2000 " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
wrapper.RestoreSelectionCharFormat(-1);
wrapper.InsertBreak();
wrapper.InsertImage(Path.Combine(path, @"Emotion\2.gif"));
wrapper.SaveSelectionCharFormat();
wrapper.SetSelectionCharColor(Color.Red);
wrapper.InsertText("Hello, IMRichTextBox!");
wrapper.RestoreSelectionCharFormat(-1);
wrapper.InsertImage(Path.Combine(path, @"Emotion\18.gif"));
wrapper.InsertLink("博客园");
wrapper.InsertBreak();
wrapper.ScrollToCaret();
}
}
}

  效果:

五、总结

  1、C++/CLI在封装现有C++项目供.NET使用还是非常给力的。

  2、万大侠的im_richedit还提供了WindowLess的richedit的封装,由于我没有使用,所以没有进行封装,如果有需要,大家可自行封装。

  3、项目使用VS2013进行开发、编译和调试,不保证其他版本VS下能正常编译,项目源码下载:IMRichTextBox

不再需要ImageOle或DynamicGifCtl,.NET实现IM编辑控件的更多相关文章

  1. InvokeHelper,让跨线程访问/修改主界面控件不再麻烦(转)

    http://bbs.csdn.net/topics/390162519 事实上,本文内容很简单且浅显,所以取消前戏,直接开始.. 源代码:在本文最后 这里是一张动画,演示在多线程(无限循环+Thre ...

  2. 从零开始编写自己的C#框架(22)——添加普通列表页面

    普通列表页面指的是上一章那种有层次感列表以外的正常列表页面,由于上一章已讲解了正常添加页面的相关操作了,所以部分相关的操作本章节就不再罗嗦重复一次了.大家可以试试先用本章内容中的一些简单介绍,自己使用 ...

  3. ASP.NET MVC 5 02 - ASP.NET MVC 1-5 各版本特点

    参考书籍:<ASP.NET MVC 4 高级编程>.<ASP.NET MVC 5 高级编程>.<C#高级编程(第8版)>.<使用ASP.NET MVC开发企业 ...

  4. [No000098]SVN学习笔记5-分支,合并,属性,补丁,锁,分支图

    行结束符和空白选项 在项目的生命周期中,有时可能会将行结束符由 CRLF 改为 LF,或者修改一段代码的缩进.不幸的是这样将会使大量的代码行被标记为已修改,尽管代码本身并没有被修改.这里列出的选项将会 ...

  5. 值得推荐的C/C++框架和库

    值得推荐的C/C++框架和库 [本文系外部转贴,原文地址:http://coolshell.info/c/c++/2014/12/13/c-open-project.htm]留作存档 下次造轮子前先看 ...

  6. [转]C/C++ 程序员必须收藏的资源大全

    from: https://github.com/jobbole/awesome-cpp-cn C++ 资源大全中文版 我想很多程序员应该记得 GitHub 上有一个 Awesome – XXX 系列 ...

  7. 2013 duilib入门简明教程 -- 结合win32和MFC (16)

        虽然duilib自带在MFC中使用duilib的Demo,但只是MFC窗口和duilib窗口不重叠的情况.如果要在MFC窗口中嵌入duilib控件,或者在duilib控件中嵌入MFC的控件的话 ...

  8. [转载]C/C++框架和库

    C/C++框架和库 装载自:http://blog.csdn.net/xiaoxiaoyeyaya/article/details/42541419 值得学习的C语言开源项目 Webbench Web ...

  9. PB函数大全

    PB函数大全 Abs()功能计算绝对值.语法Abs ( n )参数n:要得到绝对值的数值型变量或表达式返回值返回值的数据类型与n的数据类型相同,函数执行成功时返回n的绝对值.如果参数n的值为NULL, ...

随机推荐

  1. win10如何安装和创建 证书

    .下载winsdksetup.exe .在 MMC 管理单元中查看证书 打开一个命令提示符窗口. 类型mmc然后按 ENTER 键. 请注意,若要查看本地计算机存储中的证书,您必须具有管理员角色. 上 ...

  2. 学习GIT 版本控制的好去处 另GDB资料

    廖雪峰的官方网站 http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000 作者不仅仅是做技 ...

  3. HDU 3247 Resource Archiver (AC自动机+BFS+状压DP)

    题意:给定 n 个文本串,m个病毒串,文本串重叠部分可以合并,但合并后不能含有病毒串,问所有文本串合并后最短多长. 析:先把所有的文本串和病毒都插入到AC自动机上,不过标记不一样,可以给病毒标记-1, ...

  4. python编码(七)

    本文中,以'哈'来解释作示例解释所有的问题,“哈”的各种编码如下: 1. UNICODE (UTF8-16),C854:2. UTF-8,E59388:3. GBK,B9FE. 一.python中的s ...

  5. Redis java client ==> Jedis

    https://github.com/xetorthio/jedis Jedis is a blazingly small and sane Redis java client. Jedis was ...

  6. Shiro 登录页面的几个固定字段

    http://shiro.apache.org/webapp-tutorial.html Step 3b: Add a login page Since Step 3a enabled login a ...

  7. Win7_Ultimate + VS2010 + openGL 配置

    Win7_Ultimate + VS2010 + openGL 配置 0. 前言 OpenGL作为当前主流的图形API之一,它在一些场合具有比DirectX更优越的特性. (1)与C语言紧密结合. O ...

  8. 软件工程作业 - 实现WC功能(java)

    项目地址:https://github.com/yogurt1998/WordCount 要求 基本要求 -c 统计文件字符数(实现) -w 统计文件单词数(实现) -l 统计文件行数(实现) 扩展功 ...

  9. EBS查找当前Form文件

    http://www.cnblogs.com/benio/archive/2011/06/10/2077289.html 我们经常会要在ORACLE EBS中寻找我们正在浏览的form页面的执行文件, ...

  10. Delphi Language Overview

    Delphi is a high-level, compiled, strongly typed language that supports structured and object-orient ...