目前共有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許可協議進行許可。