Toon posts:

[C++] Bitmaps, GIFS, of Metafiles invoegen in een RichEdit

Pagina: 1
Acties:
  • 239 views sinds 30-01-2008
  • Reageer

Verwijderd

Topicstarter
Ik maak een tekstverwerker alla Word... tja ik weet het... ik vind het wiel opnieuw uit, maar dit is even een soort light-versie. Enfin, niet belangrijk. Wat wel belangrijk is is het feit dat ik ook bitmaps in wil kunnen voegen in deze verwerker. En later misschien zelfs wel meerdere objecten, dat gaat afhangen van mijn klassestructuur.

Ik gebruik Borland C++ Builder 5.0 en ik ben op de hoogte van een aantal componenten in bijvoorbeeld Delphi die dit standaard ondersteunen.
De RxRichEdit uit de RXLib (te vinden op Torry bijv.) is al een goed voorbeeld. Maar voordat ik die code ga omzetten naar C++ wilde ik eerst nog even zeker weten of er geen andere mogelijkheid is om een bitmap of wat dan ook (alla Word) in te voegen in een RichEdit (de normale van Builder).

Ik zit te denken aan OLE maar misschien zijn er nog andere mogelijkheden zoals streams ofzo. Ik noem maar iets.

Zijn er mensen die hier ervaring mee hebben c.q. dit eens hebben geschreven?
Zonder dat je dus gebruik maakt van componenten anders dan die van Borland zelf. Misschien dat deze hierover wat meer kwijt willen ook qua code O-)

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 21-08 17:14
Om een fatsoenlijke tekstverwerker te bouwen, zul je waarschijnlijk je eigen edit box moeten bouwen. Je beperkt jezelf nogal met een kant en klare edit control. Ik wil niet zeggen dat het onmogelijk is, maar meer als Wordpad gaat erg lastig worden.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Verwijderd

Topicstarter
Nou het kan wel. Maar ik moet mijn eigen IOleObject schrijven... ik ben al even bezig geweest, en bij CodeGuru stond dit stukkie code van een headerfile wat mij mogelijk een heel eind op weg helpt ;) Maar tja nou zitten we weer in de APIES...
En dat is ook weer lang geleden voor mij

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
class CImageDataObject : IDataObject
{
   public:
      static void InsertBitmap( IRichEditOle *pRichEditOle, HBITMAP hBitmap );

   private:
      ULONG m_ulRefCnt;
      BOOL m_bRelease;

      // Data which will be put into the richEdit
      STGMEDIUM m_stgmed;
      FORMATETC m_fromat;
   public:
    CImageDataObject() : m_ulRefCnt(0)
    {
        m_bRelease = FALSE;
    }

    ~CImageDataObject()
    {
        if (m_bRelease)
            ::ReleaseStgMedium(&m_stgmed);
    }

    // Methods of the IUnknown interface
    // 
    STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
    {
        if (iid == IID_IUnknown || iid == IID_IDataObject)
        {
            *ppvObject = this;
            AddRef();
            return S_OK;
        }
        else
            return E_NOINTERFACE;
    }
    STDMETHOD_(ULONG, AddRef)(void)
    {
        m_ulRefCnt++;
        return m_ulRefCnt;
    }
    STDMETHOD_(ULONG, Release)(void)
    {
        if (--m_ulRefCnt == 0)
        {
            delete this;
        }

        return m_ulRefCnt;
    }

    // Methods of the IDataObject Interface
    //
    STDMETHOD(GetData)(FORMATETC *pformatetcIn, STGMEDIUM *pmedium) {
        HANDLE hDst;
        hDst = ::OleDuplicateData(m_stgmed.hBitmap, CF_BITMAP, NULL);
        if (hDst == NULL)
        {
            return E_HANDLE;
        }

        pmedium->tymed = TYMED_GDI;
        pmedium->hBitmap = (HBITMAP)hDst;
        pmedium->pUnkForRelease = NULL;

        return S_OK;
    }
    STDMETHOD(GetDataHere)(FORMATETC* pformatetc, STGMEDIUM*  pmedium ) {
        return E_NOTIMPL;
    }
    STDMETHOD(QueryGetData)(FORMATETC*  pformatetc ) {
        return E_NOTIMPL;
    }
    STDMETHOD(GetCanonicalFormatEtc)(FORMATETC*  pformatectIn ,FORMATETC* pformatetcOut )   {
        return E_NOTIMPL;
    }
    STDMETHOD(SetData)(FORMATETC* pformatetc , STGMEDIUM*  pmedium , BOOL  fRelease ) {
        m_fromat = *pformatetc;
        m_stgmed = *pmedium;

        return S_OK;
    }
    STDMETHOD(EnumFormatEtc)(DWORD  dwDirection , IEnumFORMATETC**  ppenumFormatEtc ) {
        return E_NOTIMPL;
    }
    STDMETHOD(DAdvise)(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink,
        DWORD *pdwConnection) {
        return E_NOTIMPL;
    }
    STDMETHOD(DUnadvise)(DWORD dwConnection) {
        return E_NOTIMPL;
    }
    STDMETHOD(EnumDAdvise)(IEnumSTATDATA **ppenumAdvise) {
        return E_NOTIMPL;
    }

    // Some Other helper functions
    //
    void SetBitmap(HBITMAP hBitmap);
    IOleObject *GetOleObject(IOleClientSite *pOleClientSite, IStorage  *pStorage);

};



Dus ik denk dat ik nu wel weer een eindje verder kom. Maar mocht er nog iemand zijn die andere suggesties heeft, graag :*)

[ Voor 0% gewijzigd door Verwijderd op 19-10-2002 21:32 . Reden: Dit maal met snippet ;) ]


  • Reefer
  • Registratie: Mei 2000
  • Laatst online: 21-02-2025

Reefer

madness

Verwijderd schreef op 19 oktober 2002 @ 19:07:
Maar mocht er nog iemand zijn die andere suggesties heeft, graag :*)
TIP: zet je code tussen code-tags voor leesbaarheid ;)

A Breakbeat A Day Keeps Religion Away.


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Verwijderd schreef op 19 oktober 2002 @ 19:07:
Nou het kan wel. Maar ik moet mijn eigen IOleObject schrijven... ik ben al even bezig geweest, en bij CodeGuru stond dit stukkie code van een headerfile wat mij mogelijk een heel eind op weg helpt ;) Maar tja nou zitten we weer in de APIES...
Uhm als je niet extreem vloeiend bent in de API's zou ik dit hele onderwerp maar vergeten als ik jou was... maja ik heb toevallig een maand of 2 terug BCB code geschreven voor het gevraagde onderwerp, dus hierbij wat gestripte code-snippets... alleen te gebruiken natuurlijk met bedankje aan naam en toenaam :Y)

De volledige code doet ook complete drag&drop en alles, maar a) het is copyrighted code van me werk, b) daarbij gebruik ik allerhande custom classes die ik er niet bij wil geven en c) we zijn hier geen www.codevault.com waar je alles voorgekauwd krijgt O-)

Allereerst moet je zorgen dat je een RichEdit 2.0 of hoger opent, VCL standaard doet alleen 1.0. Hiervoor leid ik als volgt een class af:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//---------------------------------------------------------------------------
// TRichEdit20 class definition
//---------------------------------------------------------------------------

class TRichEdit20 : public TRichEdit
{
public:         // Methods
  __fastcall                      TRichEdit20(TComponent* p_Owner);
  virtual __fastcall             ~TRichEdit20();

  void                            InsertObjectAtCursor(const WideString &p_FileName);

protected:      // Methods
  virtual void __fastcall         CreateParams(Controls::TCreateParams &Params);
  virtual void __fastcall         CreateWnd(void);

private:        // Methods
  void                            HandleDropFiles(HDROP p_DropHandle);

private:        // Properties
  RIRichEditOle                   m_RichEditOle;
};

RIRichEditOle is een custom class die ik je niet cadeau doe, maar het is iig een reference class naar een IRichEditOle* die automatisch opruiming en reference counting doet. Je kunt dat ook handmatig doen.

De class wordt als volgt geimplementeerd:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//---------------------------------------------------------------------------
// TRichEdit20 class implementation (empty constructor)
//---------------------------------------------------------------------------

__fastcall TRichEdit20::TRichEdit20(TComponent* p_Owner)
                       :TRichEdit(p_Owner)
{
}

//---------------------------------------------------------------------------
// CreateParams: Patches creation to invoke RichEdit 2.0
//---------------------------------------------------------------------------

void __fastcall TRichEdit20::CreateParams(Controls::TCreateParams &Params)
{
try
  {
  // Hack away at VCL to ensure RichEdit 2.0
  TCustomMemo::CreateParams(Params);
  CreateSubClass(Params, "RICHEDIT20A");
  Params.WindowClass.style &= ~(CS_HREDRAW | CS_VREDRAW);
  }
catch(...)
  {
  // Call direct base implementation if anything goes wrong to create a v1.0
  TRichEdit::CreateParams(Params);
  }
}

//---------------------------------------------------------------------------
// CreateWnd: Handles control creation and initializes OLE behaviours
//---------------------------------------------------------------------------

void __fastcall TRichEdit20::CreateWnd(void)
{
// Call inherited functionality
TRichEdit::CreateWnd();

// Retrieve the required COM interface
SendMessage(Handle, EM_GETOLEINTERFACE, 0, (LPARAM)&m_RichEditOle);
}

Dit was allemaal redelijk straightforward, hier komt de spannendste (wederom met een hoop reference classes naar OLE-interfaces, leef je uit ;) ). De filename mag naar ieder soort file wijzen dat automatisch OLE-embedded kan worden, ergo BMP's, GIF's, text files, Word-document, Excel-sheets en gaat u maar door:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//---------------------------------------------------------------------------
// InsertObjectAtCursor: Inserts named file at cursor position
//---------------------------------------------------------------------------

void TRichEdit20::InsertObjectAtCursor(const WideString &p_FileName)
{
RIStorage       l_Storage;
RIOleObject     l_OleObject;
RIOleClientSite l_ClientSite;
RILockBytes     l_LockBytes;
FORMATETC       l_FormatEtc       = {0};
BSTR            l_FileName;

// Create an IStorage implementation for the given file
if(CreateILockBytesOnHGlobal(NULL, TRUE, &l_LockBytes) != S_OK)
  return;
if(StgCreateDocfileOnILockBytes(l_LockBytes, STGM_SHARE_EXCLUSIVE | STGM_CREATE |
                                STGM_READWRITE, 0, &l_Storage) != S_OK)
  return;

// Fill the format structure and retrieve the client site
l_FormatEtc.cfFormat  = 0;
l_FormatEtc.ptd       = NULL;
l_FormatEtc.dwAspect  = DVASPECT_CONTENT;
l_FormatEtc.lindex    = -1;
l_FormatEtc.tymed     = TYMED_NULL;
m_RichEditOle->GetClientSite(&l_ClientSite);

// Attempt to create the object
l_FileName  = p_FileName.bstr();
if(OleCreateFromFile(CLSID_NULL, l_FileName, IID_IOleObject, OLERENDER_DRAW,
                     &l_FormatEtc, l_ClientSite, l_Storage, (void**)&l_OleObject) == S_OK)
  {
  REOBJECT        l_ReObject = { sizeof(REOBJECT), 0 };

  // Set the object mode to be contained then fill the RichEditObject struct
  OleSetContainedObject(l_OleObject, TRUE);
  l_OleObject->GetUserClassID(&l_ReObject.clsid);
  l_ReObject.cp         = REO_CP_SELECTION;
  l_ReObject.dvaspect   = DVASPECT_CONTENT;
  l_ReObject.dwFlags    = REO_RESIZABLE | REO_BELOWBASELINE;
  l_ReObject.poleobj    = l_OleObject;
  l_ReObject.polesite   = l_ClientSite;
  l_ReObject.pstg       = l_Storage;

  // Actually insert the object
  m_RichEditOle->InsertObject(&l_ReObject);
  }
}

Kijk, dit is het echte feesten... U was bang voor API's zei u? 8)

Verder kun je nog wat dingetjes doen met de IRichEditOleCallback interface zoals automatisch gegeneerde contextmenu's afhankelijk van het embedded object, wat ik hier tactisch uit heb gesneden (we zijn wederom geen codevault.com ;) ). Een van de andere dingen die je daarmee goed kunt doen is external drag&drops afhandelen om bestanden in te kunnen leggen, echter dit kun je via standaard messages (even WndProc overloaden) ook doen, dan krijg je bij WM_DROPFILES een HDROP naar de files. Om deze vervolgens in te voegen:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//---------------------------------------------------------------------------
// HandleDropFiles: Implementation for WM_DROPFILES messages
//---------------------------------------------------------------------------

void TRichEdit20::HandleDropFiles(HDROP p_DropHandle)
{
t_Char*     l_String;
t_UInt4     l_Count;
t_UInt4     l_Size;

// Retrieve the amount of files dropped
l_Count       = DragQueryFile(p_DropHandle, 0xFFFFFFFF, NULL, 0);
while(l_Count--)
  {
  // Retrieve and add each dropped file
  l_Size      = DragQueryFile(p_DropHandle, l_Count, NULL, 0) + 1;
  l_String    = new t_Char[l_Size];
  DragQueryFile(p_DropHandle, l_Count, l_String, l_Size);
  InsertObjectAtCursor(l_String);
  delete [] l_String;
  }

// Release the drop handle
DragFinish(p_DropHandle);
}

Nu heb je wel weer genoeg code gehad, ik hoor het wel als er verder problemen zijn :P

ps. zodra je dit weg hebt gekopieerd wijzig ik deze post zodat alle code weg is, ik hou er niet zo van om semi-copyrighted code te laten slingeren :z

Professionele website nodig?


Verwijderd

Topicstarter
Dank je wel curry648 ik heb het gekopieerd en wel. Verwijder maar naar eigen inzicht.
Enne mooie code ;)

Reefer, je opmerking klopt inderdaad, toen ik het had gepost zag ik ook dat het een enorme bende was :P Zal er de volgende keer rekening mee houden.

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Heej, ik kan wel coden ondertussen na 18 jaar :)

Maar serieus, het is heel belangrijk als programmeur om mooie layout aan te houden in je code. Boeie dat de compiler het negeert, het is voor jezelf en anderen veel makkelijker om na een half jaar de code terug te lezen als je alles netjes gelijk indenteert, alle lokale variabelen aan het begin van de functie plaats, consequent becommentariseert per 'functioneel blok' and so on. Learn it and enjoy :Y)

ps. laat de code nog wel ff staan, misschien dat iemand anders er nog iets aan heeft.

Professionele website nodig?


Verwijderd

Topicstarter
Heel fijn, ik heb het aan de praat _/-\o_ Tot nu toe werkt de bitmap. De rest moet ik nog even inbouwen. Maar nu ik dit allemaal al weer weet lukt dat ook wel.
Die API's vallen nog wel mee ;)
Hoe het precies zit met OLE, tja er staat een hele hoop op MSDN... ik vraag me alleen af of sommige foutcodes gestandariseerd zijn of niet. Ik gebruik nu gewoon mijn eigen. Dat werkt ook nog goed.

Nogmaals mijn hartelijke dank aan zulke hulp hebbie tenminste nog wat :) :)

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Uhm ja in OLE zijn standaardcodes *enorm* gestandaardiseerd, ik zou ze dus maar gebruiken :)

Professionele website nodig?

Pagina: 1