如何使用PIDL

使用Custom Build Rules

Display Name : 這是將在自訂建置規則中顯示的名稱。 例如) PIDL 規則 File Name : 建立規則檔名。 例如)PIDL_Custom_Build_Rule Directory : 指定規則檔案的儲存位置。 例如) C:\XXX\YYY

Custom Build Rule 設置

各項設定的詳細資訊如下。

Additional Dependencies : ..\..\..\util\PIDL.exe
Batching Separator :
Command Line : ..\..\..\util\PIDL.exe "$(InputPath)" -outdir .\
Display Name : PIDL
Execution Description : Compiling $(InputName).pidl ...
File Extensions : *.pidl
Name : PIDL Custom Build Rule
Outputs : $(InputDir)\$(InputName)_common.cpp;$(InputDir)\$(InputName)_common.h;$(InputDir)\$(InputName)_proxy.cpp;$(InputDir)\$(InputName)_proxy.h;$(InputDir)\$(InputName)_stub.cpp;$(InputDir)\$(InputName)_stub.h

完成設定後,在自訂建置規則中新增一條PIDL建置規則,如下所示。

Custom Build Rules

如果您檢查新建立的規則文件並在專案中建立文件,您將看到 PIDL 被自動選擇為建置工具。

使用命令提示字元(Command Prompt, cmd.exe)

如果 PIDL AddOn 或自訂建置規則不可用,您可以透過 Windows 作業系統上的命令提示字元進行編譯。

對於cs,可以透過新增PIDL -cs命令來編譯。

Common - 使用 PIDL 設定 outdir 後,將其設定為附加包含目錄。

您可以透過檢查產生的來源檔案(將它們包含在 Visual Studio 專案屬性視窗中,然後建置)來使用它。

使用Customizations

Visual Stuido 2005, 2008 版本

  • 可以使用Custom Build Rules建立規則檔案。

  • 1 個副檔名為 .rules 的規則文件

Visual Studio 2010 或更高版本

  • 可以使用/不能使用Custom Build Rules創建

  • 需要三個檔案:.props, .targets, .xml。 先前版本中建立的.rules 檔案不能按原樣使用。

2種使用customizations的方法

1. 在 Visual Studio 2005 或 2008 中建立專案後,建立 .rules 檔案並將其設定為使用,然後將專案轉換為 2010 或更高版本的方法 : 轉換專案時,.rules 檔案會自動轉換為 .props, .targets, .xml

2. 生成.props, .targets, .xml文件後直接編寫xml代碼使用的方法

Visual Studio 2005、2008和Visual Studio 2010之後的版本具有不同的定義宏觀。 如果該規則未以Visual Studio 2010後版本中使用的宏觀編寫,則轉換前應將其轉換爲Visual Studio 2010後版本中使用的宏觀,或轉換後分別修改.props, .targets, .xml

在 PIDL 內容中使用include或import

開發程序時,有時想要在.pidl文件中加入include或import語句。

#include "a/b/c.h"
 
class MyStub // PIDL 編譯輸出
{
    ...
}

為此,請在 PIDL 內容中使用以下內容:

#include "a/b/c.h" 
// for C++ language. semicolon is mandatory!

編組

在 RMI 中使用自訂類別類型

// MyType.h
 
namespace Proud
{
    // 被呼叫的RMI函數的內容被轉換為字串並輸出。
    // 建立日誌時很有用。
    void AppendTextOut(String &a,const MyType &b);
 
    // 從訊息緩衝區讀取自訂類型的內容。
    CMessage& operator>>(CMessage &a, MyType &b);
 
    // 將自訂類型內容插入訊息緩衝區。
    CMessage& operator<<(CMessage &a, const MyType &b);
}

在 ProudNet 的 RMI 功能中,我們使用 Proud.CMessage。 RMI 參數是透過重載上述函數來編組的。 這裡使用的是Proud.CMessageProud.CMessage包含ProudNet中用於將RMI轉換為訊息或從訊息中讀取參數的訊息數據,並用作流物件。

在封送處理函數中實現流的範例如下:

namespace Proud
{
    CMessage& operator>>(CMessage &a, MyType &b)
    {
        a>>b.x,b.y>>b.z>>b.w;
        return a;
    }
    CMessage& operator<<(CMessage &a, const MyType &b)
    {
        // 不要使用a.UseInternalBuffer()!
        a<<b.x,b.y<<b.z<<b.w;
        return a;
    }
    void AppendTextOut(String &a,const MyType &b)
    {
        String f;
        f.Format(L"{x=%f,y=%f,z=%f,w=%f}",b.x,b.y,b.z,b.w);
        a+=f;
    }
}

最後,在包含在 PIDL 編譯器中建立的代理程式和存根檔案之前,必須先包含宣告上述重載方法的頭檔。

// 例1
#include "MyType.h"
#include "MyPIDL_proxy.h"
 
// 例2
#include "MyType.h"
#include "MyPIDL_stub.h"

實際實現的範例請參考<安裝資料夾>/sample/CustomTypeMarshal<Sample/CasualGame/GCServer/FarmCommon.h>。 若要檢查您自己的編組函數是否有效,請使用 Proud.TestMarshal()

- 基於條件的編組方法

有一種方法可以在 RMI 參數中編組字元訊息,每個欄位在不同的字元類型之間有效或無效。 您可以使用 switch/case 語句或物件多態性來實現各種封送處理。

➡️ 使用 switch/case 的範例
namespace Proud
{
    enum UnitType
    {
        Zergling,     // 星際爭霸的雜技(地面型通商攻擊單元)
        Queen,        // 星際爭霸之王(飛行型特殊技術使用單元)
        Broodling    // 女王使用育雛技能創造的生存時間短的攻擊單位。
    };
 
    struct Unit
    {
        UnitType m_type;          // 單位類型
        Vector2D m_position;    // 單位所在地
        int m_energy;            // 單位的能量(或法力)->僅對皇后有效
        float m_lifeTime;        // 單位存活時間限制->僅對育雛有效
        int m_attackPower;        // 單位攻擊力 -> 只對雜技有效
    };
 
    CMessage& operator<<(CMessage& msg,const Unit& unit)
    {
        msg<<unit.m_type<<unit.m_position;
        switch(unit.m_type)
        {
        case Zergling:
            msg<<unit.m_attackPower;
            break;
        case Queen:
            msg<<unit.m_energy;
            break;
        case Broodling:
            msg<<unit.m_lifeTime;
            break;
        }
        return msg;
    }
 
    CMessage& operator>>(CMessage& msg,Unit& unit)
    {
        msg>>unit.m_type>>unit.m_position;
        switch(unit.m_type)
        {
        case Zergling:
            msg>>unit.m_attackPower;
            break;
        case Queen:
            msg>>unit.m_energy;
            break;
        case Broodling:
            msg>>unit.m_lifeTime;
            break;
        }
        return msg;
    }
}

- 以位元為單位編組數據

若要減少訊息中儲存的資料量,您可以逐位封送資料。 Proud.CMessage 有以下方法以位元為單位儲存資料。

方法
註釋

Proud.CMessage.ReadBits

以位元爲單位讀取

Proud.CMessage.WriteBits

以位元為單位寫入

➡️ 例子
namespace Proud
{
    struct MyType
    {
        int x,y,z;
    };
    CMessage& operator>>(CMessage &a, MyType &b)
    {
        // 6位元用於讀取x值
        a.ReadBits(b.x,6);
        // 3位元用於讀取y值
        a.ReadBits(b.y,3);
        // 15 位元用於讀取 z 值。 換句話說,總共使用了6+3+15=24bit(3位元組)。
        a.ReadBits(b.z,15);
        return a;
    }
    CMessage& operator<<(CMessage &a, const MyType &b)
    {
        a.WriteBits(b.x,6); // 以位元為單位儲存 x、y 和 z 值。
        a.WriteBits(b.y,3);
        a.WriteBits(b.z,15);
        return a;
    }
}

- 編組enum類型

若要封送enum類型,請實作下列函數。

enum type { ... } ;
 
namespace Proud
{
    inline CMessage& operator<<(CMessage& a,type b)
    {
        a<<(int)b;
        return a;
    }
    inline CMessage& operator>>(CMessage& a,type& b)
    {
        int x;
        a>>x;
        b=(type)x;
        return a;
    }
    inline void AppendTextOut(String &a,type b)
    {
        String txt;
        txt.Format(L"%d",(int)b);
        a+=txt;
    }
}

透過使用ProudNet中已定義的巨集PROUDNET_SERIALIZE_ENUM,可以如下輕鬆完成上述實作。

PROUDNET_SERIALIZE_ENUM(type)

- 編組集合(陣列等)

ProudNet 已準備好編組幾種基本集合(陣列等)類型。 支援 Proud.CFastArray, Proud.CFastMap, std.vector , CAtlArray

參考marshaler.h中的operator>>, operator<<超載

// 下面是在 PIDL 中聲明數組類型的範例。
Foo([in] Proud::CFastArray<MyType> a, [in] std::vector<MyType> b);

如果需要 marshaler.h 中預設定義的集合類型以外的集合類型,則需要實現與所需集合相對應的重載。為此,請參閱使用 RMI 的自訂類別類型marshaler.h 以了解已實現的範例。

當您想要封送 ProudNet 尚未支援的集合類型時,請參閱下列例程。

➡️ std.vector marshalling 示例
namespace Proud
{
    // 向量中可用的序列化函數
    // for output to stream
    template<typename elem>
    inline CMessage& operator>>(CMessage &a, std::vector<elem> &b)
    {
        // 獲得大小。
        int size;
        a >> size;
 
        // 如果大小不能接受,則會產生例外。
        // 可能有人懷疑它被駭客入侵了。
        if (size<0 ||size >= CNetConfig::MessageMaxLength)
            ThrowExceptionOnReadArray(size);
 
        // 減少記憶體碎片
        b.reserve(size);
        b.resize(0);
 
        // 一項一項地讀取每個數組項。
        elem e;
        for (int i = 0;i < size;i++)
        {
            a >> e;
            b.push_back(e);
        }
        return a;
    }
 
    // 可在vector、 list等unary item elem等 
    // 使用的 serialization functions
    // for input from stream
    template<typename elem>
    inline CMessage& operator<<(CMessage &a, const std::vector<elem> &b)
    {
        // 記錄數組大小。
        int size = (int)b.size();
        a << size;
        
        // 記錄每個數組參數。
        for (std::vector<elem>::const_iterator i = b.begin();i != b.end();i++)
        {
            a << (*i);
        }
        return a;
    }
 
    template<typename elem>
    inline void AppendTextOut(String &a, std::vector<elem> &b)
    {
        a += L"<vector>";
    }
}

關鍵字列表

關鍵字名稱
註釋
用法範例

access

[C#] 設定命名空間中代理程式和存根類別的存取權限

[access=權限名稱]

byval

將參數作為值傳遞

P2PChat([in] Proud::String a, [in, byval] int b);

global

命名空間存取權限(目前僅支援全域)

global Simple 2000 { ... }

in

輸入參數

Chat([in] string txt);

include

[C#] 將包含插入到輸出中

#include "a/b/c.cpp"

marshaler

[C#] 用於使用者定義類型的封送拆收器

[marshaler(cs) = SimpleCSharp.CMyMarshaler]

mutable

將參數作為可變參數傳遞(:=引用)

Chat([in, mutable] string txt);

private

[C#] 設定命名空間中代理程式和存根類別的存取權限

[access=private]

protected

[C#] 設定命名空間中代理程式和存根類別的存取權限

[access=protected]

public

[C#] 設定命名空間中代理程式和存根類別的存取權限

[access=public]

rename

在特定環境下透過替換編譯

rename cs(Proud::String, System.String);

using

[C#] 將 using 關鍵字插入輸出中

using(cs) System.XXX;

[C#] 想要傳遞多種參數時

global 名稱空間名稱 2000 
{
    函數名稱([in] int 變數名);
}

當PIDL如上所寫時,PIDL編譯器編譯基本類型如下。

namespace 名稱空間名稱
{
    class Proxy : public ::Proud::IRmiProxy
    {
    public:
        virtual bool 函數名稱( ::Proud::HostID remote, ::Proud::RmiContext& rmiContext , const int& 變數名) PN_SEALED; 
        ...
    }
}

想要更改傳遞方式時,請使用以下關鍵詞。

關鍵字名稱
例子(PIDL)
例子(輸出結果)

Chat([in] int val);

...Chat(..., const int& val)...

byval

Chat([in, byval] int val);

...Chat(..., const int val)...

mutable

Chat([in, mutable] int val);

...Chat(..., int& val)...


⬅️ 返回

Last updated