TN041: MFC/OLE1 โยกย้ายไป MFC/OLE 2

ปัญหาทั่วไปที่เกี่ยวข้องกับการโยกย้าย

หนึ่งในเป้าหมายออกแบบสำหรับระดับชั้น OLE 2 ใน MFC 2.5 (และสูงกว่า) เป็นการรักษามากของสถาปัตยกรรมเดียวกันที่เก็บไว้ใน MFC 2.0 สำหรับการสนับสนุน OLE 1.0 มีผล คลาสที่ OLE เดียวใน MFC 2.0 จำนวนมากยังคงอยู่ใน MFC (COleDocument, COleServerDoc, COleClientItem, COleServerItem) รุ่นนี้ นอกจากนี้ การ APIs ในชั้นเรียนเหล่านี้จำนวนมากเหมือนเหมือนกัน อย่างไรก็ตาม OLE 2 เป็น drastically แตกต่างจาก OLE 1.0 เพื่อให้คุณสามารถคาดว่า รายละเอียดบางอย่างมีการเปลี่ยนแปลง ถ้าคุณคุ้นเคยกับการสนับสนุน OLE1 MFC 2.0 คุณจะรู้สึกที่บ้าน โดยการสนับสนุนของ MFC 2.0?

ถ้าคุณกำลังใช้โปรแกรมประยุกต์ที่มีอยู่ของ MFC/OLE1 และเพิ่มฟังก์ชันการทำงาน OLE 2 คุณควรอ่านหมายเหตุนี้ครั้งแรก หมายเหตุนี้ครอบคลุมปัญหาทั่วไปบางอย่างคุณอาจพบขณะ++:การสร้างพอร์ตของฟังก์ชัน OLE1 MFC/OLE ที่ 2 และจากนั้น กล่าวถึงปัญหาเปิดเผยขณะ++:การสร้างพอร์ตโปรแกรมประยุกต์สองโปรแกรมที่รวมอยู่ใน MFC 2.0: ตัว MFC OLE อย่าง OCLIENTและ HIERSVR?

MFC/มุม มองเอกสารสถาปัตยกรรมที่สำคัญคือ

ถ้าโปรแกรมประยุกต์ของคุณไม่ได้ใช้ของ MFC/มุม มองเอกสารสถาปัตยกรรม และคุณต้องการเพิ่มโปรแกรมประยุกต์ของคุณสนับสนุน OLE 2 ตอนนี้เป็นเวลาที่การย้ายไปยังมุมมองเอกสาร / ประโยชน์ของคลาส OLE 2 ของ MFC จำนวนมากจะรับรู้เฉพาะเมื่อโปรแกรมประยุกต์ของคุณจะใช้สถาปัตยกรรมภายในและคอมโพเนนต์ของ MFC?

การใช้งานเซิร์ฟเวอร์หรือคอนเทนเนอร์โดยไม่ใช้สถาปัตยกรรม MFC จะเป็นไปได้ แต่ไม่แนะนำ?

ใช้ MFC ใช้งานแทนที่เป็นของคุณเอง

MFC "กระป๋องใช้งาน" เรียนเช่นCToolBar, CStatusBarและCScrollViewมีอยู่แล้วภายในกรณีรหัสพิเศษสำหรับการสนับสนุน OLE 2 ดังนั้น ถ้าคุณสามารถใช้คลาเหล่านี้ในโปรแกรมประยุกต์ของคุณ คุณจะประโยชน์จากความพยายามที่ใส่เข้าไปเพื่อให้ OLE ทราบ อีก จะสามารถ "โรของเอง" เรียนที่นี่สำหรับวัตถุประสงค์เหล่านี้ แต่ไม่แนะนำ ถ้าคุณต้องการใช้ฟังก์ชันการทำงานที่คล้ายคลึงกัน MFC โค้ดต้นฉบับเป็นการอ้างอิงที่ยอดเยี่ยมสำหรับใช้จัดการกับบางส่วนของจุดอย่างเข้มงวดขึ้นของ OLE (โดยเฉพาะอย่างยิ่งเมื่อมาเพื่อเปิดใช้งานในสถาน)?

ตรวจสอบตัวอย่างรหัส MFC

มีจำนวนตัวอย่าง MFC ที่มีฟังก์ชันการทำงาน OLE แต่ละโปรแกรมประยุกต์เหล่านี้ใช้ OLE จากมุมแตกต่างกัน:

HIERSVR - ส่วนใหญ่สำหรับใช้เป็นเซิร์ฟเวอร์โปรแกรมประยุกต์ จะถูกรวมอยู่ใน MFC 2.0 เป็นโปรแกรมประยุกต์ MFC/OLE1 และถูก ported MFC/OLE 2 และขยายเช่นว่านั้นใช้ OLE คุณลักษณะหลายอย่างใน OLE 2?

OCLIENT - นี้เป็นโปรแกรมประยุกต์แบบสแตนด์อโลนคอนเทนเนอร์ เพื่อแสดงคุณสมบัติ OLE จากการยืนคอนเทนเนอร์ มันเกินไปถูก ported จาก MFC 2.0 แล้ว ขยายการสนับสนุนขั้นสูงเพิ่มเติม OLE คุณลักษณะมากมาย เช่นรูปแบบการกำหนดเองคลิปบอร์ดและการเชื่อมโยงไปยังรายการที่ฝังตัว?

DRAWCLI - แอพลิเคชันนี้ใช้ OLE คอนเทนเนอร์สนับสนุนมากเหมือนไม่ OCLIENT ยกเว้นว่าภายในกรอบของโปรแกรมที่มีอยู่เชิงวัตถุรูปวาดนั้น แสดงวิธีอาจใช้ OLE คอนเทนเนอร์สนับสนุน และรวมลงในโปรแกรมประยุกต์ที่มีอยู่ของคุณ?

SUPERPAD - โปรแกรมประยุกต์นี้ ตลอดจนการประยุกต์แบบสแตนด์อโลนที่ดี มีเซิร์ฟเวอร์ OLE การสนับสนุนเซิร์ฟเวอร์ดังกล่าวใช้ได้ค่อนข้าง minimalist ความสนใจเฉพาะของวิธีใช้บริการคลิปบอร์ด OLE เพื่อคัดลอกข้อมูลไปยังคลิปบอร์ด แต่ใช้หน้าที่การใช้งานที่อยู่ภายใน Windows "แก้ไข" ควบคุมการใช้คลิปบอร์ดวางฟังก์ชัน นี้แสดงส่วนผสมน่าสนใจของการใช้งาน Windows API แบบดั้งเดิมรวมทั้งการรวมกับตัวใหม่ OLE APIs?

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับแอปพลิเคชั่นตัวอย่างดูวิธีการ "MFC ตัวอย่างใช้"?

กรณีศึกษา: OCLIENT จาก MFC 2.0

ตามที่กล่าวไว้ข้างต้น OCLIENTถูกรวมอยู่ใน MFC 2.0 และใช้งาน OLE กับ MFC/OLE1 ขั้นตอนที่โปรแกรมประยุกต์นี้ถูกเริ่มต้นด้วยแปลงการใช้คลาสที่ 2 MFC/OLE ถูกอธิบายไว้ด้านล่าง มีเพิ่มจำนวนของคุณลักษณะหลังจากพอร์ตเริ่มต้นเสร็จสมบูรณ์ดี แสดงคลาสที่ MFC/OLE คุณลักษณะเหล่านี้จะไม่สามารถครอบคลุมที่นี่ ดูตัวอย่างตัวเองสำหรับข้อมูลเพิ่มเติมเกี่ยวกับคุณลักษณะขั้นสูงเหล่านั้น?

หมายเหตุnbsp  ข้อผิดพลาดในการคอมไพล์เลอร์และกระบวนการขั้นตอนถูกสร้างขึ้น ด้วย Visual c ++ 2.0 ข้อความแสดงข้อผิดพลาดเฉพาะและตำแหน่งที่ตั้งอาจมีการเปลี่ยนแปลงกับ Visual c ++ 4.0 แต่ยังคงข้อมูลแนวคิดที่ถูกต้อง(&N)?

การตั้ง และการเรียกใช้

วิธีการดำเนินการกับพอร์ต OCLIENT ตัวอย่างการ MFC/OLE คือ เริ่มต้น ด้วยการสร้าง และแก้ไขข้อผิดพลาดของคอมไพเลอร์ชัดเจนซึ่งจะส่งผลให้ ถ้าคุณใช้ตัวอย่าง OCLIENT จาก MFC 2.0 และคอมไพล์ภายใต้ MFC รุ่นนี้ คุณจะพบว่า มีไม่แก้ไขข้อผิดพลาดของที่หลาย ข้อผิดพลาดในลำดับการเกิดขึ้นที่อธิบายไว้ด้านล่าง?

คอมไพล์และแก้ไขข้อผิดพลาด

\oclient\mainview.cpp(104): ข้อผิดพลาด C2660: 'วาด': ฟังก์ชันไม่มีพารามิเตอร์ที่ 4

ข้อผิดพลาดแรกเกี่ยวข้องCOleClientItem::Draw MFC/OLE1 ก็เอาพารามิเตอร์เพิ่มเติมมากกว่าที่ใช้รุ่น MFC/OLE พารามิเตอร์เพิ่มขึ้นมักจะไม่จำเป็น และโดยปกติแล้วค่า NULL (เช่นในตัวอย่างนี้) MFC รุ่นนี้โดยอัตโนมัติสามารถกำหนดว่าค่าของ lpWBounds เมื่อ CDC ที่กำลังมีลากการ metafile DC นอกจากนี้ พารามิเตอร์ pFormatDC ไม่จำเป็นเนื่องจากกรอบจะสร้างหนึ่งจาก "คุณลักษณะ DC" ของ pDC ส่งผ่าน ดังนั้นเพื่อแก้ไขปัญหานี้ คุณเพียงแค่เอาทั้งสองพิเศษไม่มีค่าพารามิเตอร์การเรียกรูปวาด?

\oclient\mainview.cpp(273): ข้อผิดพลาด C2065: 'OLE_MAXNAMESIZE': undeclared ระบุ
\oclient\mainview.cpp(273): ข้อผิดพลาด C2057: คาดว่าคงที่นิพจน์
\oclient\mainview.cpp(280): ข้อผิดพลาด C2664: 'CreateLinkFromClipboard': ไม่สามารถแปลงพารามิเตอร์ 1 จาก 'char [1]' เป็น ' enum:: tagOLERENDER '
\oclient\mainview.cpp(286): ข้อผิดพลาด C2664: 'CreateFromClipboard': ไม่สามารถแปลงพารามิเตอร์ 1 จาก 'char [1]' เป็น ' enum:: tagOLERENDER '
\oclient\mainview.cpp(288): ข้อผิดพลาด C2664: 'CreateStaticFromClipboard': ไม่สามารถแปลงพารามิเตอร์ 1 จาก 'char [1]' เป็น ' enum:: tagOLERENDER '

ข้อผิดพลาดข้างต้นส่งผลจากข้อเท็จจริงว่า ทั้งหมดของฟังก์ชันCOleClientItem::CreateXXXXใน MFC/OLE1 จำเป็นชื่อที่ไม่ซ้ำได้ผ่านการแสดงสินค้า นี้เป็นความต้องการของเครื่องต้นแบบ OLE API นี้ไม่จำเป็นใน MFC/OLE 2 ตั้งแต่ OLE 2 ไม่ใช้ DDE เป็นกลไกในการสื่อสารเป็นต้น (ชื่อที่ใช้ในการสนทนา DDE) เมื่อต้องการแก้ไขปัญหานี้ คุณสามารถเอาออกฟังก์ชันCreateNewNameการอ้างอิงทั้งหมดเป็นเช่นนั้น เป็นการง่ายในการค้นหาอะไรแต่ละฟังก์ชัน MFC/OLE ถูกต้องในรุ่นนี้โดยวางเคอร์เซอร์ของคุณในการเรียกสาย และกด F1 เพียง?

พื้นที่อื่นที่แตกต่างกันมากคือ การจัดการคลิปบอร์ด OLE 2 กับ OLE1 คุณใช้คลิปบอร์ด Windows APIs โต้ตอบกับคลิปบอร์ด 2 OLE นี้เสร็จ โดยกลไกที่แตกต่างกัน APIs MFC/OLE1 ที่ถือว่า คลิปบอร์ดถูกเปิดก่อนที่จะคัดลอกวัตถุCOleClientItemไปยังคลิปบอร์ด นี้ไม่จำเป็น และจะทำให้เกิดการดำเนินงานคลิปบอร์ด MFC/OLE ทั้งหมดล้มเหลว ขณะที่คุณแก้ไขรหัสเพื่อเอาการอ้างอิงบนCreateNewNameคุณยังควรเอารหัสที่เปิด และปิด Windows คลิปบอร์ด?

\oclient\mainview.cpp(332): ข้อผิดพลาด C2065: 'AfxOleInsertDialog': undeclared ระบุ
\oclient\mainview.cpp(332): ข้อผิดพลาด C2064: คำไม่ได้ประเมินไปยังฟังก์ชัน
\oclient\mainview.cpp(344): ข้อผิดพลาด C2057: คาดว่าคงที่นิพจน์
\oclient\mainview.cpp(347): ข้อผิดพลาด C2039: 'CreateNewObject': ไม่ใช่สมาชิกของ 'CRectItem'

ข้อผิดพลาดเหล่านี้เกิดจากตัวจัดการCMainView::OnInsertObject การจัดการคำสั่ง "แทรกวัตถุใหม่" เป็นพื้นที่อื่นซึ่งสิ่งที่มีการเปลี่ยนแปลงค่อนข้างเป็นบิต ในกรณีนี้ จะง่ายที่สุดเพียงผสานการใช้งานต้นฉบับ ด้วยที่มีให้สำหรับโปรแกรมประยุกต์ OLE คอนเทนเนอร์ใหม่ AppWizard ในความเป็นจริง นี้เป็นเทคนิคที่คุณสามารถใช้กับโปรแกรมประยุกต์อื่น ๆ ที่++:การสร้างพอร์ต MFC/OLE1 คุณแสดงการโต้ตอบ "แทรกวัตถุ" โดยการเรียกฟังก์ชันAfxOleInsertDialog ในรุ่นนี้ คุณสามารถสร้างวัตถุการโต้ตอบCOleInsertObjectและโทรDoModal นอกจากนี้ รายการใหม่ของ OLE ถูกสร้างกับCLSIDตัวแทนของสตริงที่ชื่อคลาส ผลลัพธ์สุดท้ายควรมีลักษณะดังนี้

กล่องโต้ตอบ COleInsertDialog
ถ้า (กล่องโต้ตอบDoModal() ! = IDOK)
 nbsp  กลับ

BeginWaitCursor()

CRectItem * pItem = NULL
ลอง
{
    / / สร้างวัตถุ c ++
    pItem = GetDocument() - > CreateItem()
    ASSERT_VALID(pItem)

/ / เตรียมใช้งานสินค้าจากข้อมูลโต้ตอบ
    ถ้า (! กล่องโต้ตอบCreateItem(pItem))
        AfxThrowMemoryException()
           / / ข้อยกเว้นใด ๆ จะทำ
    ASSERT_VALID(pItem)
        
    / / เรียกใช้วัตถุถ้าเหมาะสม
    ถ้า (กล่องโต้ตอบGetSelectionType() == COleInsertDialog::createNewItem)
        pItem - > DoVerb(OLEIVERB_SHOW, this)
        
    / / ปรับปรุงทันที
    pItem - > UpdateLink()
    pItem - > UpdateItemRectFromServer()
        
    / / การตั้งค่าการเลือกสินค้าใหม่แทรก
    SetSelection(pItem)
    pItem - > Invalidate()
}
จุดอ่อน (CException, e)
{ / / ล้างสินค้า
    ถ้า (pItem ! = NULL)
        GetDocument() - > DeleteItem(pItem)
            
    AfxMessageBox(IDP_FAILED_TO_CREATE)
}
END_CATCH
    
EndWaitCursor()

หมายเหตุnbsp  แทรกวัตถุใหม่อาจจะแตกต่างกันสำหรับโปรแกรมประยุกต์ของคุณ)(&N):

ก็ยังจำเป็นต้องรวม lt;afxodlgs.h > ซึ่งประกอบด้วยการประกาศคลาCOleInsertObjectโต้ตอบเช่นเดียวกับกล่องโต้ตอบการอื่น ๆ มาตรฐานแสดงโดย MFC?

\oclient\mainview.cpp(367): ข้อผิดพลาด C2065: 'OLEVERB_PRIMARY': undeclared ระบุ
\oclient\mainview.cpp(367): ข้อผิดพลาด C2660: 'DoVerb': ฟังก์ชันไม่มีพารามิเตอร์ 1

ข้อผิดพลาดเหล่านี้มีสาเหตุมาจากข้อเท็จจริงที่มีการเปลี่ยนแปลงบางค่าคงที่ OLE1 ใน OLE 2 ถึงแม้ว่าแนวคิด พวกเดียวกัน ในกรณีนี้OLEVERB_PRIMARYได้เปลี่ยนเป็นOLEIVERB_PRIMARY ใน OLE1 และ OLE 2 กริยาหลักคือมักจะดำเนินการ โดยที่บรรจุเมื่อผู้ใช้ดับเบิลคลิบนรายการ?

นอกจากนี้DoVerbตอนนี้ใช้พารามิเตอร์แบบพิเศษ — ตัวชี้ไปมุมมอง (CView*) พารามิเตอร์นี้จะใช้การใช้ "การแก้ไขภาพ" (หรือการเปิดใช้งานในสถาน) เท่านั้น สำหรับตอนนี้ คุณตั้งค่าพารามิเตอร์ที่เป็น NULL เนื่องจากคุณไม่ได้ใช้คุณลักษณะนี้ในเวลานี้?

เพื่อให้แน่ใจว่าเปิดใช้ว่า กรอบไม่เคยพยายามในตำแหน่งงาน คุณควรแทนCOleClientItem::CanActivateเป็นดังนี้

 BOOL CRectItem::CanActivate()
{
 nbsp  ส่งกลับค่า FALSE
}

\oclient\rectitem.cpp(53): ข้อผิดพลาด C2065: 'GetBounds': undeclared ระบุ
\oclient\rectitem.cpp(53): ข้อผิดพลาด C2064: คำไม่ได้ประเมินไปยังฟังก์ชัน
\oclient\rectitem.cpp(84): ข้อผิดพลาด C2065: 'SetBounds': undeclared ระบุ
\oclient\rectitem.cpp(84): ข้อผิดพลาด C2064: คำไม่ได้ประเมินไปยังฟังก์ชัน(&N)

ใน MFC/OLE1, COleClientItem::GetBoundsและSetBoundsใช้สำหรับการสอบถาม และจัดการขอบเขตของสินค้า (สมาชิกด้านซ้ายและด้านบนถูกเสมอเป็นศูนย์) ใน 2 MFC/OLE นี้สามารถใช้เพิ่มเติมโดยตรงได้ โดยCOleClientItem::GetExtentและSetExtentซึ่งจัดการกับขนาดหรือCSizeแทน?

รหัสสำหรับ SetItemRectToServer ของคุณใหม่ และเรียก UpdateItemRectFromServer ที่มีลักษณะดังนี้:

BOOL CRectItem::UpdateItemRectFromServer()
{
 nbsp ASSERT(m_bTrackServerSize)
   ขนาด CSize
   if (!GetExtent(&size))
      ส่งกลับค่า FALSE    / / ว่างเปล่า

/ / แมปจาก HIMETRIC กับพิกัดของหน้าจอ
   {
      CClientDC screenDC(NULL)
      screenDC.SetMapMode(MM_HIMETRIC)
      screenDC.LPtoDP(&size)
   }
   / / เพียงตั้งค่าขนาดของสินค้า
   ถ้า (m_rectSize() ! =ขนาด)
   {
      / / โมฆะขนาด/ตำแหน่งเดิม
      Invalidate()
      m_rect.right = m_rect.left + size.cx
      m_rect.bottom = m_rect.top + size.cy
      / / ตลอดจนใหม่ขนาด/ตำแหน่ง
      Invalidate()
   }
   ส่งกลับ TRUE
}

BOOL CRectItem::SetItemRectToServer()
{
   / / การตั้งค่าขอบเขตอย่างเป็นทางการสำหรับรายการฝังตัว
   ขนาด CSize = m_rectSize()
   {
      CClientDC screenDC(NULL)
      screenDC.SetMapMode(MM_HIMETRIC)
      screenDC.DPtoLP(&size)
   }
   ลอง
   {
      SetExtent(size)  / / อาจทำให้การรอคอย
   }
   จุดอ่อน (CException, e)
   {
      ส่งกลับค่า FALSE  / / การเชื่อมโยงจะไม่อนุญาตให้ SetBounds
   }
   END_CATCH
   ส่งกลับ TRUE
}

\oclient\frame.cpp(50): ข้อผิดพลาด C2039: 'InWaitForRelease': ไม่ใช่สมาชิกของ 'COleClientItem'
\oclient\frame.cpp(50): ข้อผิดพลาด C2065: 'InWaitForRelease': undeclared ระบุ
\oclient\frame.cpp(50): ข้อผิดพลาด C2064: คำไม่ได้ประเมินไปยังฟังก์ชัน

ใน MFC/OLE1 แบบซิงโครนัส API เรียกจากที่บรรจุลงในเซิร์ฟเวอร์ถูกจำลองเนื่องจากถูก OLE1 inherently แบบอะซิงโครนัสในหลายกรณี ไม่จำเป็นต้องตรวจสอบการเรียกแบบอะซิงโครนัสค้างชำระในระหว่างดำเนินการก่อนที่จะประมวลผลคำสั่งจากผู้ใช้ MFC/OLE1 ให้ฟังก์ชันCOleClientItem::InWaitForReleaseสำหรับการทำเช่นนั้น ใน 2 MFC/OLE นี้ไม่จำเป็นต้อง ดังนั้นคุณสามารถลบการแทนของ OnCommand ใน CMainFrame ทั้งหมดเข้าด้วยกัน?

ณจุดนี้ จะรวบรวม และวิธีการเชื่อมโยง OCLIENT?

เปลี่ยนแปลงที่จำเป็นอื่น ๆ

มีบางสิ่งที่ทำไม่ได้ที่จะให้ OCLIENT ทำงาน อย่างไรก็ตาม ดีกว่าที่จะแก้ไขปัญหาเหล่านี้ขณะนี้แทนที่เป็นของรุ่นที่ใหม่กว่า?

ก่อนอื่น ก็จำเป็นในการเตรียมใช้งานไลบรารี OLE ทำได้ โดยการโทรAfxOleInitจากInitInstance:

if (!AfxOleInit())
{
  AfxMessageBox ("ไม่สามารถเตรียมใช้งาน OLE ไลบรารี");
  ส่งกลับค่า FALSE
}

ก็ยังควรตรวจสอบสำหรับฟังก์ชันเสมือนสำหรับการเปลี่ยนแปลงรายการพารามิเตอร์ ฟังก์ชันหนึ่งเช่นCOleClientItem::OnChangeแทนที่ในทุกโปรแกรมประยุกต์คอนเทนเนอร์ MFC/OLE ได้ ด้วยการดูที่วิธีใช้ออนไลน์ คุณจะเห็นได้ว่า ถูกเพิ่มเป็นพิเศษ 'DWORD dwParam' CRectItem::OnChange ใหม่มีลักษณะดังนี้

โมฆะ CRectItem::OnChange (OLE_NOTIFICATION wNotification, DWORD dwParam)
{
  ถ้า (m_bTrackServerSize แอมป์ &
        !UpdateItemRectFromServer())
  {
    / / วัตถุที่ว่างเปล่า
    ถ้า (wNotification == OLE_CLOSED)
    {
      / / ไม่มีข้อมูลที่ได้รับสำหรับวัตถุ - ทำลาย
      อ้าง (!IsVisible())
      GetDocument() - > DeleteItem(this)
      กลับ   / / ไม่มีโปรแกรมปรับปรุง (สินค้าอยู่แล้วในขณะนี้)
    }
  }
  ถ้า (wNotification ! = OLE_CLOSED)
      Dirty()
  Invalidate()  / / ทำการเปลี่ยนใด ๆ จะทำให้เกิดใหม่เป็น
}

ใน MFC/OLE1 แอปพลิเคชันของคอนเทนเนอร์มาคลาสเอกสารจากCOleClientDoc ใน MFC/OLE 2 ชั้นนี้ถูกเอาออก และแทนที่ด้วยCOleDocument (องค์กรใหม่นี้ช่วยให้สร้างโปรแกรมประยุกต์คอนเทนเนอร์/เซิร์ฟเวอร์) มีการกำหนด#ที่แมปCOleClientDocไปที่COleDocumentเพื่อทำให้ง่ายขึ้น++:การสร้างพอร์ตของโปรแกรมประยุกต์ MFC/OLE1 MFC/OLE 2 เช่น OCLIENT หนึ่งในคุณลักษณะที่ไม่มาCOleDocumentที่ได้รับจากCOleClientDocเป็นคำสั่งมาตรฐานข้อความแผนผังรายการ สามารถทำได้เพื่อให้โปรแกรมเซิร์ฟเวอร์ ซึ่งยัง ใช้COleDocument (ทางอ้อม), ไม่กระทำกับค่าใช้จ่ายในที่ของตัวจัดการคำสั่งเหล่านี้ยกเว้นว่าพวกเขาเป็นโปรแกรมประยุกต์แบบคอนเทนเนอร์/เซิร์ฟเวอร์ ดังนั้น คุณต้องเพิ่มรายการต่อไปในการแมปข้อความ CMainDoc

ON_UPDATE_COMMAND_UI (ID_EDIT_PASTE, OnUpdatePasteMenu)
ON_UPDATE_COMMAND_UI (ID_EDIT_PASTE_LINK, OnUpdatePasteLinkMenu)
ON_UPDATE_COMMAND_UI (ID_OLE_EDIT_LINKS, OnUpdateEditLinksMenu)
ON_COMMAND (ID_OLE_EDIT_LINKS, COleDocument::OnEditLinks)
ON_UPDATE_COMMAND_UI (ID_OLE_VERB_FIRST, OnUpdateObjectVerbMenu)
ON_UPDATE_COMMAND_UI (ID_OLE_EDIT_CONVERT, OnUpdateObjectVerbMenu)
ON_COMMAND (ID_OLE_EDIT_CONVERT, OnEditConvert)

การใช้งานคำสั่งเหล่านี้ทั้งหมดอยู่ในCOleDocumentซึ่งเป็นคลาสพื้นฐานสำหรับเอกสารของคุณ?

ณจุดนี้ OCLIENT เป็นคอนเทนเนอร์โปรแกรมประยุกต์ OLE ทำงาน คุณจะสามารถแทรกสินค้าทุกชนิด (OLE1 หรือ OLE 2) เนื่องจากไม่มีการใช้งานรหัสจำเป็นในการเปิดใช้งานการเปิดใช้งานในสถาน มีแก้ไขรายการในหน้าต่างแยกต่างหากมากชอบ ด้วย OLE1 ส่วนถัดไปกล่าวถึงการเปลี่ยนแปลงที่จำเป็นเพื่อเปิดใช้งานการแก้ไขแบบแทนที่ (บางครั้งเรียก "การแก้ไข Visual")?

เพิ่ม "การแก้ไขภาพ"

หนึ่งในคุณลักษณะที่น่าสนใจมากที่สุดของ OLE ถูกเปิดใช้งานแบบแทนที่ (หรือ "แก้ไข Visual") คุณลักษณะนี้ช่วยให้เซิร์ฟเวอร์แอพลิเคชันเพื่อใช้ผ่านส่วนติดต่อผู้ใช้ของคอนเทนเนอร์ที่มีอินเทอร์เฟซการแก้ไขรื่นให้สำหรับผู้ใช้ การนำมาใช้ในสถานที่เปิดใช้งานการ OCLIENT ทรัพยากรบางพิเศษต้องเพิ่ม รวมทั้งรหัสเพิ่มเติมบางอย่าง ทรัพยากรเหล่านี้และรหัสได้ตามปกติโดย AppWizard — ในความเป็นจริง รหัสที่นี่มากถูกยืมโดยตรงจากโปรแกรมประยุกต์ AppWizard สดกับ "Container" สนับสนุน?

ครั้งแรกของทั้งหมด เป็นความจำเป็นในการเพิ่มเมนูทรัพยากรที่จะใช้เมื่อมีรายการที่ใช้งานอยู่ในสถาน คุณสามารถสร้างทรัพยากรนี้เมนูพิเศษใน Visual c ++ โดยคัดลอกทรัพยากร IDR_OCLITYPE และเอาแต่ popups แฟ้มและหน้าต่างทั้งหมด แทรกแถบตัวแยกที่สองระหว่าง popups แฟ้มและหน้าต่างเพื่อบ่งชี้ระยะห่างของกลุ่ม (ควรมีลักษณะเช่น: แฟ้ม || หน้าต่าง) สำหรับข้อมูลเพิ่มเติมเกี่ยวกับสิ่งเหล่านี้ตัวคั่นหมายและวิธีผสานเมนู server และคอนเทนเนอร์ดู "เมนูและทรัพยากร:เมนูผสาน" ในOLE 2 ชั้น?

เมื่อคุณมีเมนูเหล่านี้สร้าง คุณจำเป็นต้องแจ้งให้ทราบรายละเอียดกรอบ สามารถทำได้ โดยการเรียกCDocTemplate::SetContainerInfoสำหรับแม่แบบเอกสารก่อนที่คุณเพิ่มลงในรายการแม่แบบเอกสารใน InitInstance ของคุณ รหัสใหม่เพื่อลงทะเบียนแม่แบบเอกสารที่มีลักษณะดังนี้

 CDocTemplate * pTemplate =(CMultiDocTemplate ใหม่
 nbsp  IDR_OLECLITYPE
    RUNTIME_CLASS(CMainDoc)
    RUNTIME_CLASS(CMDIChildWnd), / / มาตรฐานเฟรมลูก MDI
    RUNTIME_CLASS(CMainView))
pTemplate - > SetContainerInfo(IDR_OLECLITYPE_INPLACE)
AddDocTemplate(pTemplate)

IDR_OLECLITYPE_INPLACE ทรัพยากรคือ ทรัพยากรในสถานพิเศษที่สร้างขึ้นใน Visual c ++?

เมื่อต้องการเปิดใช้งานการเปิดใช้งานในสถาน มีบางสิ่งที่จำเป็นต้องเปลี่ยนแปลงในทั้งสองCView (CMainView) มาชั้นเช่นเดียวกับคลาCOleClientItemมา (CRectItem) เหล่านี้แทนที่ทั้งหมดโดย AppWizard และการใช้งานส่วนใหญ่จะมาโดยตรงจากโปรแกรมประยุกต์ที่ AppWizard เป็นค่าเริ่มต้น?

ในขั้นตอนแรกของพอร์ตนี้ การเปิดใช้งานแบบแทนที่ถูกปิดใช้งานทั้งหมด โดยแทนที่COleClientItem::CanActivate การแทนที่นี้ควรถูกเอาออกไปเพื่ออนุญาตให้มีการเปิดใช้งานในสถาน นอกจากนี้ NULL ถูกส่งผ่านไปทั้งหมดเรียกDoVerb (มีสองของพวกเขา) เนื่องจากให้มุมมองเท่านั้นไม่จำเป็นสำหรับการเปิดใช้งานในสถาน การเปิดใช้งานในสถานที่นำมาใช้อย่างเต็มรูปแบบ ก็จำเป็นต้องผ่านมุมมองถูกต้องในการเรียกDoVerb สายเหล่านี้อย่างหนึ่งคือในCMainView::OnInsertObject

pItem-gt; DoVerb(OLEIVERB_SHOW, this)(&G)

หนึ่งคือในCMainView::OnLButtonDblClk

m_pSelection-gt; DoVerb(OLEIVERB_PRIMARY, this)(&G)

ก็จำเป็นต้องแทนที่COleClientItem::OnGetItemPosition นี่บอกเซิร์ฟเวอร์จะย้ายหน้าต่างของสัมพันธ์กับหน้าต่างของคอนเทนเนอร์ที่เมื่อสินค้าถูกเปิดใช้งานในสถานที่ใด สำหรับ OCLIENT ใช้งานเป็นเรื่องขี้ปะติ๋ว

โมฆะ CRectItem::OnGetItemPosition (CRectamp; rPosition)
{
    rPosition = m_rect
}(&A)

เซิร์ฟเวอร์ส่วนใหญ่ยังใช้สิ่งที่เรียกว่า "แบบแทนการปรับขนาด นี้ทำให้หน้าต่าง server จะมีขนาด และย้ายในขณะที่ผู้ใช้เป็นการแก้ไขสินค้า คอนเทนเนอร์ที่ต้องการมีส่วนร่วมในการกระทำนี้ เนื่องจากการเคลื่อนย้าย หรือปรับขนาดหน้าต่างมักจะมีผลต่อการตำแหน่งและขนาดต่าง ๆ ภายในคอนเทนเนอร์เอกสารเอง ใช้งานสำหรับ OCLIENT โดย m_rect ด้วยตำแหน่งใหม่และขนาดสี่เหลี่ยมภายในทำให้ตรงกัน?

 BOOL CRectItem::OnChangeItemPosition(const CRectamp; rectPos)
{
    ASSERT_VALID(this)

if (!COleClientItem::OnChangeItemPosition(rectPos))
        ส่งกลับค่า FALSE

Invalidate()
    m_rect = rectPos
    Invalidate()
    GetDocument() - > SetModifiedFlag()

ส่งกลับ TRUE
}

ณจุดนี้ มีรหัสเพียงพอเพื่อให้สินค้าที่จะ เปิดใช้งานในสถาน และจัดการกับการปรับขนาด และย้ายสินค้าเมื่อมีการใช้งาน แต่มีไม่มีรหัสที่จะอนุญาตให้ผู้ใช้ออกจากเซสชันการแก้ไข นั้น แม้ว่าบางเซิร์ฟเวอร์จะมีฟังก์ชันนี้เอง โดยการจัดการคีย์การหลบหนี มันจะแนะนำคอนเทนเนอร์มีสองวิธีในการยกเลิกใช้รายการ: (1) โดยคลิกที่ภายนอกสินค้า และ (2) โดยการกดปุ่มคีย์การหลบหนี?

สำหรับการหลบหนี การเร่ง ด้วย Visual c ++ที่แมปคีย์การ VK_ESCAPE ให้กับคำสั่ง เพิ่มคีย์ ID_CANCEL_EDIT จะถูกเพิ่มทรัพยากรคุณ ตัวจัดการสำหรับคำสั่งนี้เป็นไปตาม:

/ / ตัวจัดการคำสั่งต่อไปนี้ให้เป็นมาตรฐาน
/ / อินเทอร์เฟซผู้ใช้ยกเลิกแบบแทนที่แป้นพิมพ์
/ / แก้ไข session.void CMainView::OnCancelEdit()
{
 nbsp  / / ปิดรายการใช้งานอยู่สถานที่ในมุมมองนี้
    COleClientItem * pActiveItem = GetDocument() - > GetInPlaceActiveItem(this)
    ถ้า (pActiveItem ! = NULL)
        pActiveItem - > Close()
    ASSERT(GetDocument()-> GetInPlaceActiveItem(this) == NULL);
}

การจัดการกรณีที่ผู้ใช้คลินอกสินค้า คุณเพิ่มรหัสต่อไปนี้ในการเริ่มต้นของCMainView::SetSelection

ถ้า (pNewSel ! = m_pSelection || pNewSel == NULL)
{
 nbsp  COleClientItem * pActiveItem = GetDocument() - > GetInPlaceActiveItem(this)
    ถ้า (pActiveItem ! = NULL & & pActiveItem ! = pNewSel)
        pActiveItem - > Close()
}
  & nbsp
 

เมื่อสินค้าถูกใช้งานอยู่ในสถาน ควรมีโฟกัส เพื่อให้แน่ใจว่า เป็นกรณีนี้ คุณจัดการ OnSetFocus เพื่อให้โฟกัสอยู่เสมอโอนไปยังกองสินค้าใช้งานอยู่เมื่อมุมมองของคุณได้รับโฟกัส:

/ / จำเป็นต้องมีการจัดการพิเศษของ OnSetFocus และ OnSize / / เมื่อวัตถุกำลังถูกแก้ไขในแทน
โมฆะ CMainView::OnSetFocus (CWnd * pOldWnd)
{
 nbsp  COleClientItem * pActiveItem = GetDocument() - > GetInPlaceActiveItem(this)
    ถ้า (pActiveItem ! = NULL & &
    pActiveItem - > GetItemState() == COleClientItem::activeUIState)
    {
        / / ต้องการตั้งโฟกัสไปยังรายการนี้ถ้าเป็นมุมมองเดียวกัน
        CWnd * pWnd = pActiveItem - > GetInPlaceWindow()
        ถ้า (pWnd ! = NULL)
        {
            pWnd - > SetFocus()  / / ไม่เรียกคลาสพื้นฐาน
            กลับ
        }
    }

CView::OnSetFocus(pOldWnd)
}

เมื่อมุมมองที่ถูกปรับขนาด คุณจำเป็นต้องแจ้งให้ทราบถึงรายการใช้งานอยู่ที่มีการเปลี่ยนแปลงรูปวาดสี่เหลี่ยม การทำเช่นนี้คุณมีตัวจัดการสำหรับOnSize:

โมฆะ CMainView::OnSize (UINT nType, int cx, int cy)
{
 nbsp  CView::OnSize (nType, cx, cy);
    COleClientItem * pActiveItem = GetDocument() - > GetInPlaceActiveItem(this)
    ถ้า (pActiveItem ! = NULL)
        pActiveItem - > SetItemRects()
}

กรณีศึกษา: HIERSVR จาก MFC 2.0

HIERSVRถูกรวมไว้ใน MFC 2.0 และใช้งาน OLE กับ MFC/OLE1 หมายเหตุนี้อธิบายถึงขั้นตอนต่าง ๆ ที่โปรแกรมประยุกต์นี้ถูกเริ่มต้นด้วยแปลงการใช้คลาสที่ 2 MFC/OLE สั้น ๆ มีเพิ่มจำนวนของคุณลักษณะหลังจากพอร์ตเริ่มต้นเสร็จสมบูรณ์ดี แสดงคลาสที่ 2 MFC/OLE คุณลักษณะเหล่านี้จะไม่สามารถครอบคลุมที่นี่ ดูตัวอย่างตัวเองสำหรับข้อมูลเพิ่มเติมเกี่ยวกับคุณลักษณะขั้นสูงเหล่านั้น?

หมายเหตุnbsp  ข้อผิดพลาดในการคอมไพล์เลอร์และกระบวนการขั้นตอนถูกสร้างขึ้น ด้วย Visual c ++ 2.0 ข้อความแสดงข้อผิดพลาดเฉพาะและตำแหน่งที่ตั้งอาจมีการเปลี่ยนแปลงกับ Visual c ++ 4.0 แต่ยังคงข้อมูลแนวคิดที่ถูกต้อง(&N)?

การตั้ง และการเรียกใช้

วิธีการดำเนินการกับพอร์ต HIERSVR ตัวอย่างการ MFC/OLE คือ เริ่มต้น ด้วยการสร้าง และแก้ไขข้อผิดพลาดของคอมไพเลอร์ชัดเจนซึ่งจะส่งผลให้ ถ้าคุณใช้ตัวอย่าง HIERSVR จาก MFC 2.0 และคอมไพล์ภายใต้ MFC รุ่นนี้ คุณจะพบว่า มีไม่ผิดพลาดมากมายเพื่อแก้ไข (แม้ว่าจะมีมากกว่า ด้วยตัวอย่าง OCLIENT) ข้อผิดพลาดในใบสั่งที่มันจะเกิดขึ้นได้อธิบายไว้ด้านล่าง?

คอมไพล์และแก้ไขข้อผิดพลาด

\hiersvr\hiersvr.cpp(83): ข้อผิดพลาด C2039: 'RunEmbedded': ไม่ใช่สมาชิกของ 'COleTemplateServer'

ข้อผิดพลาดนี้แรกชี้ออกมากใหญ่ปัญหาด้วยฟังก์ชันInitInstanceสำหรับเซิร์ฟเวอร์ เตรียมใช้งานที่จำเป็นสำหรับเซิร์ฟเวอร์ OLE ได้คงการเปลี่ยนแปลงที่ใหญ่ที่สุดที่คุณจะต้องทำการโปรแกรมประยุกต์ของคุณ MFC/OLE1 เพื่อให้มันทำงานอย่างใดอย่างหนึ่ง สิ่งดีที่สุดทำอย่างไรจะดูอะไรที่ AppWizard สร้างสำหรับเซิร์ฟเวอร์ OLE และปรับเปลี่ยนรหัสของคุณได้ตามความเหมาะสม นี่คือบางจุดเพื่อระลึกถึง:

ความจำเป็นในการเตรียมใช้งานไลบรารี OLE โดยการเรียกAfxOleInit

เรียกใช้ SetServerInfo บนวัตถุแม่แบบเอกสารเพื่อตั้งค่าเซิร์ฟเวอร์ทรัพยากรจับและ runtime ชั้นข้อมูลที่คุณไม่สามารถตั้งค่าได้ ด้วยการกำหนดCDocTemplate?

ไม่ต้องแสดงหน้าต่างหลักของโปรแกรมประยุกต์ของคุณถ้า /Embedding อยู่บนบรรทัดคำสั่ง?

คุณจำเป็นต้องGUIDสำหรับเอกสารของคุณ นี้เป็นตัวระบุที่ไม่ซ้ำกันสำหรับชนิดของเอกสาร (128 บิต) AppWizard จะสร้างให้คุณ — ดังนั้นถ้าคุณใช้เทคนิคอธิบายไว้ที่นี่การคัดลอกรหัสใหม่จากเซิร์ฟเวอร์โปรแกรมประยุกต์ AppWizard ที่สร้างขึ้นใหม่ คุณสามารถเพียงแค่ "ขโมย" GUID จากโปรแกรมประยุกต์นั้น ถ้า ไม่ คุณสามารถใช้ GUIDGENโปรแกรมอรรถประโยชน์ EXE ในไดเรกทอรีของช่องเก็บ?

จำเป็นต้อง "เชื่อมต่อ" วัตถุของคุณCOleTemplateServerลงในแม่แบบเอกสาร โดยการเรียกCOleTemplateServer::ConnectTemplate?

ปรับปรุงรีจิสทรีของระบบเมื่อโปรแกรมประยุกต์ของคุณมีการเรียกใช้แบบสแตนด์อโลน วิธีนี้ ถ้าผู้ใช้ย้ายEXE สำหรับโปรแกรมประยุกต์ของคุณ ทำงานจากตำแหน่งที่ตั้งใหม่จะปรับปรุงฐานข้อมูลการลงทะเบียนระบบ Windows ให้ชี้ไปที่ตำแหน่งใหม่?

หลังจากการใช้ทั้งหมดของการเปลี่ยนแปลงเหล่านี้ยึดตามสิ่งที่ AppWizard สร้างสำหรับInitInstance, InitInstance (และเกี่ยวข้อง GUID) สำหรับ HIERSVR ควรอ่านเป็นดังนี้:

// this is the GUID for HIERSVR documents
static const GUID BASED_CODE clsid =
    { 0xA0A16360L, 0xC19B, 0x101A, { 0x8C, 0xE5, 0x00, 0xDD, 0x01, 0x11, 0x3F, 0x12 } };
    
/////////////////////////////////////////////////////////////////////////////
// COLEServerApp initialization

BOOL COLEServerApp::InitInstance()
{
    // OLE 2 initialization
    if (!AfxOleInit())
    {
        AfxMessageBox("Initialization of the OLE failed!");
        return FALSE;
    }

    // Standard initialization
    LoadStdProfileSettings(); // Load standard INI file options 

    // Register document templates
    CDocTemplate* pDocTemplate;
    pDocTemplate = new CMultiDocTemplate(IDR_HIERSVRTYPE,
        RUNTIME_CLASS(CServerDoc),   
        RUNTIME_CLASS(CMDIChildWnd),
        RUNTIME_CLASS(CServerView));
    pDocTemplate->SetServerInfo(IDR_HIERSVRTYPE_SRVR_EMB);
    AddDocTemplate(pDocTemplate);

    // create main MDI Frame window
    CMainFrame* pMainFrame = new CMainFrame;
    if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
        return FALSE;
    m_pMainWnd = pMainFrame;

    SetDialogBkColor();   // gray look

    // enable file manager drag/drop and DDE Execute open
    m_pMainWnd->DragAcceptFiles();
    EnableShellOpen();
    
    m_server.ConnectTemplate(clsid, pDocTemplate, FALSE);
    COleTemplateServer::RegisterAll();

    // try to launch as an OLE server
    if (RunEmbedded())
    {
        // "short-circuit" initialization -- run as server!
        return TRUE;
    }
    m_server.UpdateRegistry();
    RegisterShellFileTypes();

    // not run as OLE server, so show the main window
    if (m_lpCmdLine[0] == '\0')
    {
        // create a new (empty) document
        OnFileNew();
    }
    else
    {
        // open an existing document
        OpenDocumentFile(m_lpCmdLine);
    }

    pMainFrame->ShowWindow(m_nCmdShow);
    pMainFrame->UpdateWindow();
    
    return TRUE;
}

คุณจะสังเกตเห็นว่า รหัสข้างต้นหมายถึงทรัพยากร ID ใหม่ IDR_HIERSVRTYPE_SRVR_EMB นี่คือทรัพยากรที่จะใช้เมื่อมีแก้ไขเอกสารที่ถูกฝังในคอนเทนเนอร์อีกเมนู ใน MFC/OLE1 รายการเมนูเฉพาะเมื่อต้องการแก้ไขรายการฝังตัวถูกปรับเปลี่ยนบนตัวแมลงวัน ใช้เป็นโครงสร้างเมนูที่แตกต่างกันทั้งหมดเมื่อแก้ไขรายการฝังตัวแทนของการแก้ไขเอกสารที่ใช้แฟ้มทำให้ง่ายขึ้นมากเพื่อให้มีอินเทอร์เฟซผู้ใช้ที่แตกต่างกันสำหรับโหมดแยกต่างหากสองเหล่านี้ คุณจะเห็นในภายหลัง ทรัพยากรเมนูทั้งหมดแยกต่างหากจะใช้เมื่อทำการแก้ไขวัตถุฝังตัวแบบแทนที่?

การสร้างทรัพยากรนี้ โหลดทรัพยากรสคริปต์ลงใน Visual c ++ และคัดลอกทรัพยากร IDR_HIERSVRTYPE เมนูที่มีอยู่ การเปลี่ยนชื่อทรัพยากรใหม่ IDR_HIERSVRTYPE_SRVR_EMB (เป็นแบบแผนการตั้งชื่อเดียวกันที่ใช้ AppWizard) ถัดไป เปลี่ยน "แฟ้มบันทึก" การ "ปรับปรุงแฟ้ม" ให้สั่ง ID ID_FILE_UPDATE ยัง เปลี่ยน "แฟ้มบันทึกเป็น" "แฟ้มบันทึกสำเนาเป็น" ให้สั่ง ID ID_FILE_SAVE_COPY_AS กรอบแสดงการใช้งานคำสั่งเหล่านี้ทั้งสอง?

\hiersvr\svritem.h(60): ข้อผิดพลาด C2433: 'OLESTATUS': 'เสมือน' ไม่ได้รับอนุญาตบนข้อมูลประกาศ
\hiersvr\svritem.h(60): ข้อผิดพลาด C2501: 'OLESTATUS': decl-specifiers ที่ขาดหายไป
\hiersvr\svritem.h(60): ข้อผิดพลาด C2146: ข้อผิดพลาดไวยากรณ์: หายไป ก่อนที่ จะระบุ 'OnSetData'
\hiersvr\svritem.h(60): ข้อผิดพลาด C2061: ข้อผิดพลาดไวยากรณ์: ตัวระบุ 'OLECLIPFORMAT'
\hiersvr\svritem.h(60): ข้อผิดพลาด C2501: 'OnSetData': decl-specifiers ที่ขาดหายไป

มีข้อผิดพลาดที่เกิดจากการแทนของOnSetDataเนื่องจากมันถูกอ้างอิงถึงชนิดOLESTATUSจำนวนหนึ่ง OLESTATUSวิธีการ OLE1 ส่งกลับข้อผิดพลาดได้ นี้มีการเปลี่ยนแปลงการhresult ในใน OLE 2 ถึงแม้ว่า MFC แปลงhresult ในมักจะเป็นCOleExceptionที่ประกอบด้วยข้อผิดพลาด ในกรณีนี้เฉพาะ การแทนที่ของOnSetDataไม่จำเป็น ดังนั้นสิ่งที่ง่ายที่สุดที่จะทำคือการ เอาออก?

 \hiersvr\svritem.cpp(30): ข้อผิดพลาด C2660: 'COleServerItem::COleServerItem': ฟังก์ชันไม่มีพารามิเตอร์ 1

พารามิเตอร์COleServerItemที่ใช้พารามิเตอร์ 'BOOL' เป็นพิเศษ ธงนี้กำหนดวิธีการจัดการหน่วยความจำจะทำบนวัตถุCOleServerItem ด้วยการตั้งค่าเป็น TRUE กรอบงานจัดการการจัดการหน่วยความจำของวัตถุเหล่านี้ — ลบออกเมื่อพวกเขาไม่จำเป็นต้อง HIERSVR ใช้วัตถุCServerItem (มาจากCOleServerItem) เป็นส่วนหนึ่งของข้อมูลท้องถิ่น ดังนั้นคุณสามารถกำหนดค่าสถานะนี้เป็น FALSE ซึ่งช่วยให้ HIERSVR ที่กำหนดเมื่อมีลบสินค้าแต่ละเซิร์ฟเวอร์?

\hiersvr\svritem.cpp(44): ข้อผิดพลาด C2259: 'CServerItem': ความพยายามที่ไม่ถูกต้องเมื่อต้องการสร้างอินสแตนซ์ของคลาสนามธรรม
\hiersvr\svritem.cpp(44): ข้อผิดพลาด C2259: 'CServerItem': ความพยายามที่ไม่ถูกต้องเมื่อต้องการสร้างอินสแตนซ์ของคลาสนามธรรม

ตามนัยข้อผิดพลาดเหล่านี้ มีฟังก์ชันบางฟังก์ชัน 'บริสุทธิ์เสมือน' ซึ่งไม่มีการแทนใน CServerItem ส่วนใหญ่นี้เกิดจากข้อเท็จจริงที่มีการเปลี่ยนแปลงรายการพารามิเตอร์ของ OnDraw เมื่อต้องการแก้ไขข้อผิดพลาดนี้ เปลี่ยนCServerItem::OnDrawเป็นดังนี้ (รวมทั้งการประกาศใน svritem.h)

BOOL CServerItem::OnDraw(CDC* pDC, CSizeamp; rSize)
{
    / / ทำการร้องขอจาก OLE วาดโหน
    pDC - > SetMapMode(MM_TEXT) / / เสมอ ในพิกเซล
    กลับ DoDraw (pDC, CPoint(0,0), FALSE);
}

พารามิเตอร์ใหม่คือ 'rSize' นี้ช่วยให้คุณสามารถกรอกข้อมูลในขนาดของรูปวาด ถ้าสะดวก ขนาดนี้ต้องอยู่ในHIMETRICกัน ในกรณีนี้ จะไม่สะดวกในการกรอกข้อมูลค่านี้ใน ดังนั้นกรอบเรียกOnGetExtentเพื่อดึงขอบเขต ที่ทำงาน คุณจะต้องใช้OnGetExtent:

BOOL CServerItem::OnGetExtent(DVASPECT dwDrawAspect, CSizeamp; rSize)
{
    ถ้า (dwDrawAspect ! = DVASPECT_CONTENT)
        กลับ COleServerItem::OnGetExtent (dwDrawAspect, rSize);
        
    rSize = CalcNodeSize()
    ส่งกลับ TRUE
}

\hiersvr\svritem.cpp(104): ข้อผิดพลาด C2065: 'm_rectBounds': undeclared ระบุ
\hiersvr\svritem.cpp(104): ข้อผิดพลาด C2228: ด้านซ้ายของ 'SetRect' ต้องมี คลา/struct/สหภาพ ชนิด
\hiersvr\svritem.cpp(106): ข้อผิดพลาด C2664: ' โมฆะ __pascal __far DPtoLP (struct:: tagPOINT __far *, int) __far const ': ไม่สามารถแปลงพารามิเตอร์ 1 จาก ' int __far *' กับ ' struct:: tagPOINT __far *'(&A)

ใน CServerItem::CalcNodeSize ฟังก์ชันขนาดของสินค้าถูกแปลงเป็นHIMETRICและเก็บไว้ในm_rectBounds ไม่มีสมาชิกของCOleServerItemอย่างชาญฉลาด 'm_rectBounds' (มันมาบางส่วนแทนm_sizeExtentแต่ใน OLE 2 สมาชิกนี้มีการใช้งานที่แตกต่างกันเล็กน้อยกว่าm_rectBoundsได้ใน OLE1) ตั้งค่าขนาดHIMETRICเข้าไปในตัวแปรนี้สมาชิก คุณจะกลับก็ ค่าที่ส่งคืนนี้ถูกใช้ในOnGetExtentการใช้งานก่อนหน้านี้?

CSize CServerItem::CalcNodeSize()
{
 nbsp  CClientDC dcScreen(NULL)

m_sizeNode = dcScreen.GetTextExtent (m_strDescription
      m_strDescription.GetLength())
    m_sizeNode += CSize (CX_INSET * 2, CY_INSET * 2);

/ / การตั้งค่าที่แนะนำ HIMETRIC ขนาด
    CSize ขนาด (m_sizeNode.cx, m_sizeNode.cy);
    dcScreen.SetMapMode(MM_HIMETRIC)
    dcScreen.DPtoLP(&size)
    ส่งกลับค่าขนาด
}

นอกจากนี้ CServerItem ยังแทนCOleServerItem::OnGetTextData ฟังก์ชันนี้ล้าสมัยใน MFC/OLE และถูกแทนที่ โดยกลไกที่แตกต่างกัน ตัว MFC OLE อย่างรุ่น MFC 3.0 HIERSVRใช้ฟังก์ชันนี้ โดยการแทนที่COleServerItem::OnRenderFileData ฟังก์ชันนี้ไม่สำคัญสำหรับพอร์ตนี้พื้นฐาน ดังนั้นคุณสามารถลบการแทน OnGetTextData?

มีหลายอย่างเพิ่มเติมผิดใน svritem.cpp ที่ยังไม่ถูกส่งถึงกัน เหล่านั้นไม่ใช่ข้อผิดพลาด "จริง" — เพียงข้อผิดพลาดที่เกิดจากข้อผิดพลาดก่อนหน้านี้?

\hiersvr\svrview.cpp(325): ข้อผิดพลาด C2660: 'CopyToClipboard': ฟังก์ชันไม่มีพารามิเตอร์ที่ 2

COleServerItem::CopyToClipboardไม่สนับสนุนค่าสถานะ 'bIncludeNative' ข้อมูลดั้งเดิม (ข้อมูลที่เขียนตามฟังก์ชั่น Serialize ของสินค้าเซิร์ฟเวอร์) ถูกคัดลอกเสมอมา ดังนั้นคุณลบพารามิเตอร์แรก นอกจากนี้CopyToClipboardจะโยนข้อยกเว้นเมื่อมีข้อผิดพลาดเกิดขึ้นแทนที่ของส่งกลับ FALSE เปลี่ยนรหัสสำหรับ CServerView::OnEditCopy เป็นดังนี้

โมฆะ CServerView::OnEditCopy()
{
 nbsp  ถ้า (m_pSelectedNode == NULL)
        AfxThrowNotSupportedException()
        
    ลอง
    {
        m_pSelectedNode - > CopyToClipboard(TRUE)
    }
    CATCH_ALL(e)
    {
        AfxMessageBox ("คัดลอกไปที่คลิปบอร์ดล้มเหลว");
    }
    END_CATCH_ALL }

แม้ว่ามีข้อผิดพลาดเพิ่มเติมที่เป็นผลมาจากการคอมไพล์ของรุ่น MFC 2.0 HIERSVR กว่าที่มีสำหรับ OCLIENT รุ่นเดียวกัน ไม่มีน้อยลงจริง ๆ การเปลี่ยนแปลง?

ณจุดนี้ HIERSVR จะคอมไพล์ และการเชื่อมโยง และทำงาน เป็นเซิร์ฟเวอร์ OLE แต่ ไม่สถานที่แก้ไข คุณลักษณะ ซึ่งจะนำมาใช้ถัดไป?

เพิ่ม "การแก้ไขภาพ"

เพิ่ม "การแก้ไขภาพ" (หรือการเปิดใช้งานในสถาน) ไปยังโปรแกรมประยุกต์เซิร์ฟเวอร์นี้ มีเพียงไม่กี่สิ่งคุณต้องดูแล:

ง่ายต่อการสร้างทรัพยากรเมนูได้ เรียกใช้งาน Visual c ++ คัดลอกทรัพยากรเมนู IDR_HIERSVRTYPE ให้กับทรัพยากรของเมนูที่เรียกว่า IDR_HIERSVRTYPE_SRVR_IP ปรับเปลี่ยนเมนูเพื่อให้อยู่ชิดซ้ายเท่านั้นแก้ไขและวิธีใช้เมนู popups เพิ่มตัวคั่นที่สองให้กับเมนูในระหว่างเมนูวิธีใช้และการแก้ไข (ควรมีลักษณะเช่น: แก้ไข || วิธีใช้) ดูข้อมูลเพิ่มเติมในสิ่งเหล่านี้ตัวคั่นหมายและวิธีผสานเมนู server และคอนเทนเนอร์ "เมนูและทรัพยากร:เมนูผสาน" ในOLE 2 ชั้น?

บิตแมปสำหรับแถบเครื่องมือของเซตย่อยสามารถสร้างได้ง่ายขึ้น โดยการคัดลอกมาจากโปรแกรมประยุกต์สร้าง AppWizard แบบสดด้วยตัวเลือก "Server" ในการตรวจสอบ บิตแมปนี้แล้วสามารถถูกนำเข้าลงใน Visual c ++ ต้องแน่ใจว่าการให้บิตแมปที่มี ID ของ IDR_HIERSVRTYPE_SRVR_IP?

เรียนมาจากCOleIPFrameWndสามารถคัดลอกจากโปรแกรมประยุกต์ AppWizard ที่สร้างขึ้นด้วยการสนับสนุนของเซิร์ฟเวอร์ด้วย คัดลอกไฟล์ทั้งสอง IPFRAMECPP และ IPFRAMEH และเพิ่มลงในโครงการ ตรวจสอบให้แน่ใจว่า การโทรLoadBitmapถึง IDR_HIERSVRTYPE_SRVR_IP บิตแมปที่สร้างขึ้นในขั้นตอนก่อนหน้า?

ขณะที่ทรัพยากรใหม่และชั้นเรียนทั้งหมดถูกสร้างขึ้น เพิ่มรหัสที่จำเป็นเพื่อให้รู้เกี่ยวกับกรอบ (และรู้ว่า โปรแกรมประยุกต์นี้ขณะนี้สนับสนุนการแก้ไขแบบแทน) ทำได้ โดยการเพิ่มพารามิเตอร์บางอย่างเพิ่มเติมเพื่อSetServerInfoการโทรในฟังก์ชันInitInstance:

pDocTemplate-gtSetServerInfo (IDR_HIERSVRTYPE_SRVR_EMB
    IDR_HIERSVRTYPE_SRVR_IP, RUNTIME_CLASS(CInPlaceFrame))(&G)

เป็นตอนนี้พร้อมที่จะเรียกใช้ในสถานในคอนเทนเนอร์ใด ๆ ซึ่งยัง สนับสนุนการเปิดใช้งานในตำแหน่งนั้น แต่ มีข้อบกพร่องเล็กน้อยหนึ่งยังคง lurking ในรหัส HIERSVR สนับสนุนบริบทเมนู แสดงเมื่อผู้ใช้กดปุ่มเมาส์ด้านขวา เมนูนี้ทำงานเมื่อ HIERSVR เปิดเต็ม แต่ไม่ทำงานเมื่อแก้ไขฝังแบบแทนที่ เหตุผลสามารถยึดหมุดลงไปนี้บรรทัดเดียวของรหัสใน CServerView::OnRButtonDown

pMenu-gtTrackPopupMenu(TPM_CENTERALIGN | TPM_RIGHTBUTTON
    point.x, point.y, AfxGetApp() - > m_pMainWnd)

สังเกตการอ้างอิงไป() AfxGetApp-gt; m_pMainWnd เมื่อเซิร์ฟเวอร์ การเปิดใช้งานในสถาน มีหน้าต่างหลัก และ m_pMainWnd ถูกตั้งค่า แต่ก็มักจะมองไม่เห็น นอกจากนี้ หน้าต่างนี้อ้างอิงถึงหน้าต่างหลักของโปรแกรมประยุกต์ MDI กรอบหน้าต่างที่ปรากฏเมื่อเซิร์ฟเวอร์อย่างเต็มรูปแบบเปิด หรือเรียกใช้แบบสแตนด์อโลน ไม่ได้อ้างอิงไปยังหน้าต่างเฟรมที่ใช้งานอยู่ — ซึ่งเมื่อสถานที่ทำงานเป็นหน้าต่างเฟรมมาจากCOleIPFrameWnd เพื่อเรียกหน้าต่างที่ใช้งานถูกต้องแม้ว่าแบบแทนการแก้ไข MFC รุ่นนี้เพิ่มฟังก์ชันใหม่AfxGetMainWnd โดยทั่วไปแล้ว คุณควรใช้ฟังก์ชันนี้แทนAfxGetApp() - > m_pMainWnd รหัสนี้ต้องเปลี่ยนเป็นดังนี้:

 pMenu-gtTrackPopupMenu(TPM_CENTERALIGN | TPM_RIGHTBUTTON
    point.x, point.y, AfxGetMainWnd(&))

ขณะนี้ คุณมีเซิร์ฟเวอร์ OLE minimally เปิดใช้สำหรับการเปิดใช้งานในสถานที่ทำงาน แต่ไม่มียังคุณลักษณะต่าง ๆ 2 MFC/OLE ที่ไม่พร้อมใช้งานใน MFC/OLE1 ดูตัวอย่าง HIERSVR สำหรับข้อคิดเห็นเพิ่มเติมเกี่ยวกับคุณลักษณะต่าง ๆ ที่คุณอาจต้องการใช้ บางคุณลักษณะ HIERSVR ใช้อยู่ด้านล่าง:

ตัวอย่าง HIERSVR ใน MFC 3.0 ยังใช้การออกแบบที่แตกต่างกันเล็กน้อยสำหรับสินค้าของเซิร์ฟเวอร์ นี้ช่วยประหยัดหน่วยความจำ และทำให้การเชื่อมโยงของคุณมีความยืดหยุ่น กับ HIERSVR รุ่น 2.0 แต่ละโหนดในทรีเป็น-a COleServerItem COleServerItemดำเนินตามค่าใช้จ่ายเพิ่มเติมบิตในมากกว่าที่จำเป็นสำหรับแต่ละโหนเหล่านี้อย่างเคร่งครัด แต่COleServerItemจำเป็นสำหรับแต่ละการเชื่อมโยงที่ใช้งานอยู่ แต่สำหรับส่วนใหญ่ มีการเชื่อมโยงที่ใช้งานน้อยมากเวลาที่กำหนด เมื่อต้องการทำสิ่งนี้ให้มีประสิทธิภาพมากขึ้น การ HIERSVR ของ MFC รุ่นนี้แยกโหนดจากCOleServerItem มีทั้งแบบ CServerNode และคลาCServerItem CServerItem (มาจากCOleServerItem) ถูกสร้างเมื่อจำเป็นเท่านั้น เมื่อคอนเทนเนอร์ (หรือคอนเทนเนอร์) หยุดใช้เฉพาะที่การเชื่อมโยงไปที่โหนเฉพาะ CServerItem วัตถุที่เชื่อมโยงกับ CServerNode จะถูกลบ การออกแบบนี้คือมีความยืดหยุ่น และมีประสิทธิภาพมากขึ้น ความยืดหยุ่นของมาในเมื่อทำงานกับหลายการเชื่อมโยงการเลือก HIERSVR รุ่นสองเหล่านี้ไม่สนับสนุนการเลือกหลาย แต่มันจะง่ายขึ้นมากเมื่อต้อง การเพิ่ม (และ เพื่อสนับสนุนการเชื่อมโยงให้เลือกเช่น) กับ HIERSVR เนื่องจากCOleServerItemถูกแยกจากข้อมูลท้องถิ่นรุ่น MFC 3.0?

หมายเหตุด้านเทคนิคตามหมายเลข|nbsp หมายเหตุด้านเทคนิคตามประเภท(&N)

Index