A Mainframe IDE Powered By Unix Technology [16] - Compile local file with Rational Developer for System z

本文介绍如何使用Rational Developer for System z (RDZ) 和 vim 集成编译 PL/I 代码。通过安装 RDZ 并配置环境变量,可以利用 RDZ 的 pli.exe 进行本地编译,并通过自定义 shell 脚本 rdzpli.sh 实现自动化错误定位。最后,在 vim 中设置相应的编译选项和错误格式,即可实现在 vim 中快速查看和定位编译错误。

Here use PLI as example: 2 choices to integete compile results with vim:

 

.

1. Compile source on Mainframe then use XDC command to save results into dataset or use ftp and site command to fetch result from job's sysout. After this we can reformat result and integrate with vim.

   I already introduced that, first use one shell to reformat result that vim can read it, then use vim command to open error file in quickfix window.

2. Compile local file with Rational developer for System z(RDZ), this is much more fast than option 1.

 

.

Today, I will show you how to compile with RDZ.

 

.

You can download RDZ from ibm.com for 50 days' trial version. After installation, add X:/Program Files/IBM/SPD/bin/ into enviroment variable PATH. Then you can call pli.exe to compile pli source in command window with this format:

pli.exe file_name.pli (Compile time option

 

In order to integrate with vim, do the steps bellow:

1. Change $VIMRUNTIME/compiler/pli.vim:

let current_compiler = "pli"   “compiler type

CompilerSet makeprg=rdzpli.exe  "shell script to call pli.exe and pass compile time option to pli.exe

CompilerSet errorformat=%f.pli(%l:2)/ :/ IBM%nI/ %t/ %m  "error message file format

 

.

2.Create one shell script "rdzpli.sh" and use shc compile as executable file, then move to Cygwin/bin.

   So we can call rdzpli to compile pli source:

   rdzpli filename or rdzpli -i filename to throw out information level's msg.


pli.exe receive filename as parm and then search for filename.pli to compile, we almost use file without extention file name.

So copy filename to filename.pli then compile it.

/(include /(ext/(/' /',Inc,Cpy/)/) is compile time option pass to pli.exe, this configure copybook file's extention name, and search in sequence: blank, inc and cpy.

 

.

3. Add one system virable INCLUDE which value is the folder contains copybook. pli.exe search IBM.SYSLIB and then INCLUDE to find copybook.

 

.

4. Compile: I use the source from multics: www.multicians .org

    Use vim open it and edit, then use :make % command, % means current filename.

    Vim will call rdzpli.exe in this format: rdzpli.exe <current_filename>, the compilation result will be open in quickfix window automaticlly after compile complete.

 


 

Quickfix:

 

Maybe it's not the best way to compile pli, but it can integrate with vim to locate error position in quickfix then use vim's advantage. Perhaps we can integrate vim with RDZ based on ecplise in the future.

<think> 我们分析用户的问题:在MFC框架中,结构为MainFrame -> ChildFrame -> CView -> CSplitterWnd -> CWnd,如何从MainFrame给CWnd正确传值。 根据之前的讨论,直接跨层级访问对象会破坏MFC的文档/视图架构。正确的做法是通过层层传递,确保每一层只与直接下一层交互。 解决方案步骤: 1. MainFrame获取当前活动的ChildFrame(通过MDIGetActive)。 2. MainFrame调用ChildFrame的一个自定义方法,将数据传递给ChildFrame。 3. ChildFrame中,因为其持有一个CView(可能是分割窗口的父视图),所以需要进一步传递到CView。 4. CView再传递到分割窗口CSplitterWnd。 5. 最后,CSplitterWnd将数据传递到目标CWnd(窗格中的视图或控件)。 注意:实际中,CSplitterWnd通常包含多个窗格(每个窗格是一个视图),所以需要明确目标窗格。 为了减少耦合,我们可以采用以下方法: - 在ChildFrame中定义一个方法,用于接收来自MainFrame的数据,并将其转发给它的视图(CView)。 - 在CView中,再定义一个方法,将数据转发给分割窗口(CSplitterWnd)。 - 在CSplitterWnd中,再定义一个方法,将数据转发给指定的窗格(CWnd)。 但是,这样层层传递可能过于繁琐。另一种推荐的方法是使用MFC的消息机制(SendMessage/PostMessage)进行跨层级通信,这样各个类之间可以解耦。 下面给出两种实现方式: ### 方式1:通过方法调用层层传递(适合直接控制) #### 步骤1:在ChildFrame中定义方法 ```cpp // ChildFrame.h class CChildFrame : public CMDIChildWnd { public: void PassDataToView(const CString& strData); }; // ChildFrame.cpp void CChildFrame::PassDataToView(const CString& strData) { CView* pView = GetActiveView(); if (pView) { // 调用视图的方法 pView->SendDataToSplitter(strData); // 需要视图类有这个方法 } } ``` #### 步骤2:在CView中定义方法,传给分割窗口 ```cpp // MyView.h class CMyView : public CView { public: void SendDataToSplitter(const CString& strData); }; // MyView.cpp void CMyView::SendDataToSplitter(const CString& strData) { // 假设视图类持有一个分割窗口的指针(例如,在创建分割窗口时保存) if (m_pSplitter) { m_pSplitter->PassDataToPane(strData); // 需要分割窗口类有这个方法 } } ``` #### 步骤3:在CSplitterWnd中定义方法,传给目标窗格 ```cpp // MySplitter.h class CMySplitter : public CSplitterWnd { public: void PassDataToPane(const CString& strData); }; // MySplitter.cpp void CMySplitter::PassDataToPane(const CString& strData) { // 获取目标窗格(假设第0行第1列) CWnd* pWnd = GetPane(0, 1); if (pWnd) { // 这里假设目标窗格是一个自定义视图,有SetString方法 ((CMyPaneView*)pWnd)->SetString(strData); } } ``` #### 步骤4:在MainFrame中调用ChildFrame的方法 ```cpp void CMainFrame::OnPassData() { CMDIChildWnd* pChild = MDIGetActive(); if (pChild) { CChildFrame* pMyChild = DYNAMIC_DOWNCAST(CChildFrame, pChild); if (pMyChild) { pMyChild->PassDataToView(_T("Data from MainFrame")); } } } ``` ### 方式2:使用消息传递(解耦推荐) #### 步骤1:定义自定义消息 ```cpp #define WM_USER_PASS_DATA (WM_USER + 100) ``` #### 步骤2:在目标CWnd(窗格视图)中处理消息 ```cpp // 在窗格视图类的头文件中声明消息处理函数 afx_msg LRESULT OnPassData(WPARAM wParam, LPARAM lParam); // 在实现文件中添加映射 BEGIN_MESSAGE_MAP(CMyPaneView, CWnd) ON_MESSAGE(WM_USER_PASS_DATA, OnPassData) END_MESSAGE_MAP() // 实现消息处理 LRESULT CMyPaneView::OnPassData(WPARAM wParam, LPARAM lParam) { CString* pStr = (CString*)wParam; // 使用数据,注意:这里需要处理数据的生命周期,也可以使用其他方式传递数据 SetMyString(*pStr); return 0; } ``` #### 步骤3:从MainFrame发送消息 假设已知目标窗格的句柄(hwnd),但通常我们不知道。因此,需要先获取目标窗格的句柄。 如何获取?可以通过层层获取,但也可以提前在某个地方(如创建时)将目标窗格的句柄注册到MainFrame,或者通过消息广播。 但是,如果采用消息传递,我们也可以将消息发送给ChildFrame,然后ChildFrame转发给它的视图,再转发给分割窗口,最后到目标窗格。这样同样需要层层传递消息。 更直接的方式(如果知道目标窗格的路径): ```cpp void CMainFrame::OnPassData() { CMDIChildWnd* pChild = MDIGetActive(); if (pChild) { // 获取子框架的视图 CView* pView = pChild->GetActiveView(); if (pView) { // 假设我们知道分割窗口是视图的子窗口(例如,视图创建了分割窗口作为子窗口) CSplitterWnd* pSplitter = (CSplitterWnd*)pView->GetWindow(GW_CHILD); if (pSplitter && pSplitter->IsKindOf(RUNTIME_CLASS(CSplitterWnd))) { CWnd* pTargetWnd = pSplitter->GetPane(0, 1); if (pTargetWnd) { // 发送消息给目标窗格 CString strData = _T("Hello from MainFrame"); // 注意:这里直接发送字符串可能有问题,因为字符串是局部变量,在接收端可能已经被销毁。 // 解决方案:使用全局字符串、动态分配字符串(注意释放)或通过其他方式传递字符串(如共享内存、成员变量等) pTargetWnd->SendMessage(WM_USER_PASS_DATA, (WPARAM)&strData, 0); } } } } } ``` 注意:上面的消息传递中,直接传递局部字符串的地址是不安全的,因为当接收消息时,可能该字符串已经超出作用域。因此,需要确保接收方在字符串有效期内处理消息(如同步SendMessage),或者通过动态分配字符串,并在接收方处理后删除。但这样会增加复杂性。 ### 推荐做法 根据MVC原则,建议采用方式1的层层方法调用,或者在ChildFrame中提供对目标窗格的访问接口(封装),这样MainFrame只需调用ChildFrame的接口,由ChildFrame负责内部传递。 ### 结论 从MainFrame给CWnd传值,应通过ChildFrame中转,并最终由分割窗口传递给目标窗格。推荐在ChildFrame中封装一个方法,供MainFrame调用,内部实现数据传递到目标窗格。 §§相关问题§§ 1. 在MFC中,如何使用消息传递机制实现跨多个窗口层级的数据传输? 2. 使用SendMessage传递数据时,如何避免因数据生命周期导致的内存问题? 3. 在MFC的文档/视图架构中,MainFrame如何安全地获取和操作深层嵌套的视图对象? 4. 如何设计MFC应用程序的通信机制以减少层级间的耦合? 5. 使用CSplitterWnd创建的分割窗口中,如何动态获取特定窗格的指针? </think> ### 正确实现方案 在 MFC 框架中,MainFrame → ChildFrame → CView → CSplitterWnd → CWnd 的层级结构中,从 MainFrame 向最底层的 CWnd 传值需要遵循 MFC 文档/视图架构的分层原则。以下是安全可靠的实现方法: #### 推荐方案:通过消息机制传递(解耦最佳实践) ```cpp // 1. 定义自定义消息 (MainFrame.h) #define WM_USER_PASS_VALUE (WM_USER + 100) // 2. 在目标 CWnd 类中处理消息 (MyPaneWnd.h) class CMyPaneWnd : public CWnd { DECLARE_MESSAGE_MAP() afx_msg LRESULT OnPassValue(WPARAM wParam, LPARAM lParam); }; // (MyPaneWnd.cpp) BEGIN_MESSAGE_MAP(CMyPaneWnd, CWnd) ON_MESSAGE(WM_USER_PASS_VALUE, OnPassValue) END_MESSAGE_MAP() LRESULT CMyPaneWnd::OnPassValue(WPARAM wParam, LPARAM lParam) { CString* pStr = reinterpret_cast<CString*>(wParam); if (pStr) { SetWindowText(*pStr); // 实际使用值 delete pStr; // 释放动态内存 } return 0; } // 3. 在 ChildFrame 中封装访问方法 (ChildFrame.cpp) CWnd* CChildFrame::GetTargetPane() { if (CView* pView = GetActiveView()) { if (CSplitterWnd* pSplitter = dynamic_cast<CSplitterWnd*>(pView)) { return pSplitter->GetPane(0, 1); // 目标窗格 } } return nullptr; } // 4. MainFrame 中安全传值 (MainFrame.cpp) void CMainFrame::SendValueToPane(const CString& strValue) { if (CMDIChildWnd* pChild = MDIGetActive()) { if (CChildFrame* pChildFrame = dynamic_cast<CChildFrame*>(pChild)) { if (CWnd* pTarget = pChildFrame->GetTargetPane()) { // 动态分配确保线程安全 CString* pDynamicStr = new CString(strValue); pTarget->SendMessage( WM_USER_PASS_VALUE, reinterpret_cast<WPARAM>(pDynamicStr) ); } } } } ``` #### 备选方案:通过子框架中转(直接访问) ```cpp // 在 ChildFrame 中添加访问方法 (ChildFrame.cpp) void CChildFrame::SetPaneValue(const CString& strValue) { if (CSplitterWnd* pSplitter = dynamic_cast<CSplitterWnd*>(GetActiveView())) { if (CMyPaneWnd* pPane = dynamic_cast<CMyPaneWnd*>(pSplitter->GetPane(0, 1))) { pPane->SetValueDirectly(strValue); // 窗格自有方法 } } } // MainFrame 中调用 (MainFrame.cpp) void CMainFrame::OnPassValue() { if (CMDIChildWnd* pChild = MDIGetActive()) { if (CChildFrame* pFrame = dynamic_cast<CChildFrame*>(pChild)) { pFrame->SetPaneValue(_T("Data from MainFrame")); } } } ``` ### 关键原则 1. **分层访问**:MainFrame 只应与直接子级 ChildFrame 交互 2. **动态类型检查**:必须使用 `dynamic_cast` 或 `DYNAMIC_DOWNCAST` 3. **资源管理**: - 消息传递时使用 `new/delete` 管理字符串内存 - 使用 `SendMessage` 确保同步执行 4. **封装性**: - 窗格操作细节封装在 ChildFrame 中 - MainFrame 不应知晓 CSplitterWnd/CWnd 的存在 > **性能提示**:高频操作建议使用共享内存或文件映射,避免消息传递开销
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值