目前共有28篇帖子。
【原创C++程序】用C++创建显示文章事件指令的剪切板内容(可粘贴到RMXP事件编辑器中)
1樓 巨大八爪鱼 2016-1-26 22:44
【核心代码】
// RXData.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "RubyMarshal.h"

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    ostringstream stream; // 这是一个字符串的缓冲区
    RubyMarshal rms(&stream);
    rms.WriteHeader(); // 写入Marshal的版本号4.8

    rms.BeginArray(1); // 整个剪切板的内容是一个单元素数组
    // ---- 从下面开始都是这个大数组的第一个元素的值 ------
    rms.BeginObject("RPG::EventCommand", 3); // 这个数组的唯一元素是一个RPG::EventCommand对象的实例,该对象有3个成员变量
        rms.BeginMember("code"); // 第一个成员变量code指定了事件指令编号
        rms.WriteFixnum(101); // “显示文章”的编号为101
        rms.BeginMember("indent"); // 第二个成员变量indent指定了事件指令在事件编辑器中的缩进程度
        rms.WriteFixnum(0); // 缩进为0
   
        rms.BeginMember("parameters"); // 第三个成员变量是事件指令的参数
        rms.BeginArray(1); // 该成员变量的值是一个单元素数组
        rms.WriteString("This is a string."); // 数组的唯一元素是一个字符串,指定了显示文章的内容
        // 注意,文章内容的编码必须是UTF8编码格式(准确的说是Unicode编码的UTF8存储方式)
        // 在C++中,char字符数组可以存储任何编码的字符串,默认的编码是ANSI编码,而wchar_t字符数组存储的字符串编码一般为Unicode编码的UTF16存储方式。因此,使用wchar_t或wstring来存储字符串时,可以先将UTF16存储方式用WideCharToMultiByte函数转换为UTF8存储方式,最后再传入WriteString方法里
    // --------------------------------------------------

    rms.Copy(CF_RPGXPEVENTCOMMAND); // 复制到剪切板中,括号中是剪切板的格式编号

    return 0;
}

【运行程序后生成的剪切板内容】

2樓 巨大八爪鱼 2016-1-26 22:46
【基础类库】
// 目前我只完成了写的部分,还没完成读的部分
【头文件RubyMarshal.h】
#pragma once

#define MARSHAL_MAJOR 4
#define MARSHAL_MINOR 8

#define TYPE_NIL '0'
#define TYPE_TRUE 'T'
#define TYPE_FALSE 'F'
#define TYPE_FIXNUM 'i'
#define TYPE_EXTENDED 'e'
#define TYPE_UCLASS 'C'
#define TYPE_OBJECT 'o'
#define TYPE_DATA 'd'
#define TYPE_USERDEF 'u'
#define TYPE_USRMARSHAL 'U'
#define TYPE_FLOAT 'f'
#define TYPE_BIGNUM 'l'
#define TYPE_STRING '"'
#define TYPE_REGEXP '/'
#define TYPE_ARRAY '['
#define TYPE_HASH '{'
#define TYPE_HASH_DEF '}'
#define TYPE_STRUCT 'S'
#define TYPE_MODULE_OLD 'M'
#define TYPE_CLASS 'c'
#define TYPE_MODULE 'm'
#define TYPE_SYMBOL ':'
#define TYPE_SYMLINK ';'
#define TYPE_IVAR 'I'
#define TYPE_LINK '@'

#define ONIG_OPTION_IGNORECASE 0x01
#define ONIG_OPTION_EXTEND 0x02
#define ONIG_OPTION_MULTILINE 0x04

#define CF_RPGXPEVENTCOMMAND 50306

class RubyMarshal
{
private:
    std::ostream *filestream;

    int WriteString(char type, char *pStr);
public:
    RubyMarshal(std::ostream *stream);
    ~RubyMarshal(void);

    int BeginArray(long length);
    int BeginExtended(char *modulename);
    int BeginHash(long length, bool hasDefValue = false);
    int BeginMember(char *memname);
    int BeginObject(char *clsname, long memlen);
    void Copy(UINT format);
    int WriteBignum(long long num);
    int WriteBool(bool value);
    int WriteClass(char *clsname);
    int WriteFixnum(long num);
    int WriteFloat(double num);
    int WriteHeader(void);
    int WriteLong(long num);
    int WriteModule(char *name);
    int WriteNil(void);
    int WriteRegexp(char *pStr);
    int WriteString(char *pStr);
    int WriteSymbol(char *pStr);
    int WriteSymLink(long link);
};
3樓 巨大八爪鱼 2016-1-26 22:46
【源文件RubyMarshal.cpp】
#include "StdAfx.h"
#include "RubyMarshal.h"

using namespace std;

RubyMarshal::RubyMarshal(ostream *stream) : filestream(stream)
{
}


RubyMarshal::~RubyMarshal(void)
{
}

int RubyMarshal::BeginArray(long length)
{
    filestream->put(TYPE_ARRAY);
    return WriteLong(length) + 1;
}

int RubyMarshal::BeginExtended(char *modulename)
{
    filestream->put(TYPE_EXTENDED);
    return WriteSymbol(modulename) + 1;
}

int RubyMarshal::BeginHash(long length, bool hasDefValue)
{
    if (hasDefValue)
        filestream->put(TYPE_HASH_DEF);
    else
        filestream->put(TYPE_HASH);
    return WriteLong(length) + 1;
}

int RubyMarshal::BeginMember(char *memname)
{
    int len = strlen(memname);
    int count = len + 2;
    filestream->put(TYPE_SYMBOL);
    count += WriteLong(len + 1);
    filestream->put(TYPE_LINK);
    filestream->write(memname, len);
    return count;
}

int RubyMarshal::BeginObject(char *clsname, long memlen)
{
    int count = 1;
    filestream->put(TYPE_OBJECT);
    count += WriteSymbol(clsname);
    count += WriteLong(memlen);
    return count;
}

void RubyMarshal::Copy(UINT format)
{
    ostringstream *stream = reinterpret_cast<ostringstream *>(filestream);
    string &str = stream->str();
    int len = str.length();
    OpenClipboard(NULL);
    EmptyClipboard();
    HGLOBAL hMem = GlobalAlloc(GMEM_FIXED, len + 4);
    char *data = (char *)GlobalLock(hMem);
    data[0] = len & 0xff;
    data[1] = len >> 8 & 0xff;
    data[2] = len >> 16 & 0xff;
    data[3] = len >> 24 & 0xff;
    memcpy(data + 4, str.data(), len);

    GlobalUnlock(hMem);
    SetClipboardData(format, hMem);
    CloseClipboard();
}

int RubyMarshal::WriteBignum(long long num)
{
    char data[sizeof(long long)] = {0};
    int count = 2;
    int i;
    filestream->put(TYPE_BIGNUM);
    if (num >= 0)
        filestream->put('+');
    else
    {
        filestream->put('-');
        num = -num;
    }
    for (i = 0; i < sizeof(long long); i++)
    {
        data[i] = num & 0xff;
        num >>= 8;
        if (num == 0)
            break;
    }
    i = i / 2 + 1;
    count += WriteLong(i);
    i *= 2;
    filestream->write(data, i);
    count += i;
    return count;
}

int RubyMarshal::WriteBool(bool value)
{
    if (value)
        filestream->put(TYPE_TRUE);
    else
        filestream->put(TYPE_FALSE);
    return 1;
}

int RubyMarshal::WriteClass(char *clsname)
{
    return WriteString(TYPE_CLASS, clsname);
}

int RubyMarshal::WriteFixnum(long num)
{
    filestream->put(TYPE_FIXNUM);
    return WriteLong(num) + 1;
}


int RubyMarshal::WriteFloat(double num)
{
    ostringstream strstream;
    strstream << setiosflags(ios::fixed) << setprecision(16) << num;
    string str = strstream.str();
    int len = str.length();
   
    int count = len + 1;
    filestream->put(TYPE_FLOAT);
    count += WriteLong(len);
    filestream->write(str.c_str(), len);
    return count;
}

int RubyMarshal::WriteHeader(void)
{
    char header[] = {MARSHAL_MAJOR, MARSHAL_MINOR};
    filestream->write(header, sizeof(header));
    return sizeof(header);
}

int RubyMarshal::WriteLong(long num)
{
    char data[sizeof(long) + 1];
    int count = 1;
    int i;
    if (num == 0)
        data[0] = 0;
    else if (num > 0 && num < 123)
        data[0] = (char)(num + 5);
    else if (num > -124 && num < 0)
        data[0] = (char)((num - 5) & 0xff);
    else
    {
        for (i = 1; i < sizeof(long) + 1; i++)
        {
            data[i] = (char)(num & 0xff);
            num >>= 8;
            if (num == 0)
            {
                data[0] = i;
                break;
            }
            else if (num == -1)
            {
                data[0] = -i;
                break;
            }
        }
        count += i;
    }
    filestream->write(data, count);
    return count;
}

int RubyMarshal::WriteModule(char *name)
{
    return WriteString(TYPE_MODULE, name);
}

int RubyMarshal::WriteNil(void)
{
    filestream->put(TYPE_NIL);
    return 1;
}

int RubyMarshal::WriteRegexp(char *pStr)
{
    int start = 0, end;
    int len = strlen(pStr);
    int count = 2;
    if (pStr[0] == '/')
        start = 1;
    for (end = len - 1; pStr[end] != '/' && end >= 0; end--);
    if (end <= start)
        end = len;
    int regLen = end - start;
    filestream->put(TYPE_REGEXP);
    count += WriteLong(regLen);
    filestream->write(pStr + start, regLen);
    count += regLen;
   
    char flag = 0;
    for (pStr += end + 1; *pStr != '\0'; pStr++)
    {
        switch (*pStr)
        {
        case 'i':
            flag |= ONIG_OPTION_IGNORECASE;
            break;
        case 'm':
            flag |= ONIG_OPTION_MULTILINE;
            break;
        case 'x':
            flag |= ONIG_OPTION_EXTEND;
            break;
        }
    }
    filestream->put(flag);
    return count;
}

int RubyMarshal::WriteString(char *pStr)
{
    return WriteString(TYPE_STRING, pStr);
}

int RubyMarshal::WriteString(char type, char *pStr)
{
    int len = strlen(pStr);
    filestream->put(type);
    int count = WriteLong(len);
    filestream->write(pStr, len);
    count += len + 1;
    return count;
}

int RubyMarshal::WriteSymbol(char *pStr)
{
    return WriteString(TYPE_SYMBOL, pStr);
}

int RubyMarshal::WriteSymLink(long link)
{
    filestream->put(TYPE_SYMLINK);
    return WriteLong(link) + 1;
}
4樓 巨大八爪鱼 2016-1-26 22:47
【预编译头文件】
// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
//

#pragma once

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>

#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>

#include <Windows.h>

// TODO: 在此处引用程序需要的其他头文件

5樓 巨大八爪鱼 2016-1-26 22:49
整个剪切板就是一个RXData片段,里面的内容和rxdata文件的格式完全一样。
RubyMarshal类就是用来写rxdata文件的(目前读的部分还没做)
6樓 巨大八爪鱼 2016-1-26 22:59
示例程序及源代码下载地址:
http://zlk1214.ys168.com/
文件夹:C++
文件名:Cpp生成RMXP显示文章事件指令的示例代码.7z
文件大小:664KB
7樓 巨大八爪鱼 2016-1-27 10:11
【补充】
由于每次开机后rmxp向系统注册的剪切板格式编号不一样,但名字是相同的,所以应该把代码中的rms.Copy那句话改成:
UINT format = RegisterClipboardFormat(TEXT("RPGXP EVENT_COMMAND"));
rms.Copy(format);
并且去掉原先define的那个宏。
今天,我电脑上的编号已经变成50204了,不再是昨天晚上的50306了。
在Windows API中不能向剪切板中放置未注册格式的内容。
8樓 巨大八爪鱼 2016-1-27 10:15
【示例:复制等待300帧的事件指令】
int _tmain(int argc, _TCHAR* argv[])
{
    ostringstream stream;
    RubyMarshal rms(&stream);
    rms.WriteHeader();

    rms.BeginArray(1);
    rms.BeginObject("RPG::EventCommand", 3);
    rms.BeginMember("code");
    rms.WriteFixnum(106);
    rms.BeginMember("indent");
    rms.WriteFixnum(0);
   
    rms.BeginMember("parameters");
    rms.BeginArray(1);
    rms.WriteFixnum(300);

    UINT format = RegisterClipboardFormat(TEXT("RPGXP EVENT_COMMAND"));
    rms.Copy(format);

    return 0;
}
9樓 巨大八爪鱼 2016-1-27 10:25
【示例:复制两个事件指令。一个是等待300帧,另一个是等待20帧】
    rms.WriteHeader();
    rms.BeginArray(2);
   
    rms.BeginObject("RPG::EventCommand", 3);
    rms.BeginMember("code");
    rms.WriteFixnum(106);
    rms.BeginMember("indent");
    rms.WriteFixnum(0);
    rms.BeginMember("parameters");
    rms.BeginArray(1);
    rms.WriteFixnum(300);

    rms.BeginObject("RPG::EventCommand", 3);
    rms.BeginMember("code");
    rms.WriteFixnum(106);
    rms.BeginMember("indent");
    rms.WriteFixnum(0);
    rms.BeginMember("parameters");
    rms.BeginArray(1);
    rms.WriteFixnum(20);
10樓 巨大八爪鱼 2016-1-27 10:29
【示例:复制中断事件处理,这个事件指令无参数】
    rms.WriteHeader();
    rms.BeginArray(1);
   
    rms.BeginObject("RPG::EventCommand", 3);
    rms.BeginMember("code");
    rms.WriteFixnum(115);
    rms.BeginMember("indent");
    rms.WriteFixnum(0);
    rms.BeginMember("parameters");
    rms.BeginArray(0); // 无参数

回復帖子

內容:
用戶名: 您目前是匿名發表
驗證碼:
 
 
©2010-2024 Arslanbar [手機版] [桌面版]
除非另有聲明,本站採用創用CC姓名標示-相同方式分享 3.0 Unported許可協議進行許可。