Finally finished with the RE control this evening. Just to give you an idea what it's like to write an OLE callback interface and accept drag and drop objects in the RE control.
Not that you need to ever write it...since it's part of the control now ;)
This is something that was nearly impossible in IBasic Pro. In Standard it was written in C++ and the conversion was relatively simple.
EDIT :This code is just for discussion and won't compile. If you want the entire file it is in the source archive
/*all of this needed to provide inplace OLE objects in a RichEdit control */
import int InterlockedIncrement(pointer pAddend);
import int InterlockedDecrement(pointer pAddend);
import int CreateILockBytesOnHGlobal (unsigned int hGlobal, int fDeleteOnRelease,
pointer *pplkbyt);
import int StgCreateDocfileOnILockBytes(pointer plkbyt,
int grfMode,
int reserved,
pointer *ppstgOpen);
#typedef OLECHAR word
#define E_NOTIMPL 0x80004001u
#define E_NOINTERFACE 0x80004002u
#define S_OK 0
/* Storage instantiation modes */
#define STGM_DIRECT 0x00000000u
#define STGM_TRANSACTED 0x00010000u
#define STGM_SIMPLE 0x08000000u
#define STGM_READ 0x00000000u
#define STGM_WRITE 0x00000001u
#define STGM_READWRITE 0x00000002u
#define STGM_SHARE_DENY_NONE 0x00000040u
#define STGM_SHARE_DENY_READ 0x00000030u
#define STGM_SHARE_DENY_WRITE 0x00000020u
#define STGM_SHARE_EXCLUSIVE 0x00000010u
#define STGM_PRIORITY 0x00040000u
#define STGM_DELETEONRELEASE 0x04000000u
#define STGM_NOSCRATCH 0x00100000u
#define STGM_CREATE 0x00001000u
#define STGM_CONVERT 0x00020000u
#define STGM_FAILIFTHERE 0x00000000u
#define STGM_NOSNAPSHOT 0x00200000u
struct GUID,1
{
int data1;
word data2;
word data3;
byte data4[8];
}
EXTERN _IID_IUnknown as GUID;
EXTERN _IID_IRichEditOleCallback as GUID;
interface IUnknown
{
/*** IUnknown methods ***/
declare virtual QueryInterface(riid as POINTER, ppvObj as POINTER),int;
declare virtual AddRef(),int;
declare virtual Release(),int;
}
interface ILockBytes : IUnknown
{
//were only using the IUnknown method Release...so no need for the rest of the interface def.
}
interface IStorage : IUnknown
{
declare virtual CreateStream(
/* [string][in] */ pointer pwcsName,
/* [in] */ int grfMode,
/* [in] */ int reserved1,
/* [in] */ int reserved2,
/* [out] */ pointer *ppstm),int;
declare virtual /* [local] */ OpenStream(
/* [string][in] */ OLECHAR *pwcsName,
/* [unique][in] */ void *reserved1,
/* [in] */ int grfMode,
/* [in] */ int reserved2,
/* [out] */ pointer *ppstm),int;
declare virtual CreateStorage(
/* [string][in] */ OLECHAR *pwcsName,
/* [in] */ int grfMode,
/* [in] */ int dwStgFmt,
/* [in] */ int reserved2,
/* [out] */ pointer *ppstg),int;
declare virtual OpenStorage(
/* [string][unique][in] */ OLECHAR *pwcsName,
/* [unique][in] */ pointer pstgPriority,
/* [in] */ int grfMode,
/* [unique][in] */ pointer snbExclude,
/* [in] */ int reserved,
/* [out] */ pointer *ppstg),int;
declare virtual CopyTo(
/* [in] */ int ciidExclude,
/* [size_is][unique][in] */ GUID *rgiidExclude,
/* [unique][in] */ pointer snbExclude,
/* [unique][in] */ pointer pstgDest),int;
declare virtual MoveElementTo(
/* [string][in] */ OLECHAR *pwcsName,
/* [unique][in] */ pointer pstgDest,
/* [string][in] */ OLECHAR *pwcsNewName,
/* [in] */ int grfFlags),int;
declare virtual Commit(
/* [in] */ int grfCommitFlags),int;
declare virtual Revert(),int;
declare virtual /* [local] */ EnumElements(
/* [in] */ int reserved1,
/* [size_is][unique][in] */ void *reserved2,
/* [in] */ int reserved3,
/* [out] */ pointer *ppenum),int;
declare virtual DestroyElement(
/* [string][in] */ OLECHAR *pwcsName),int;
declare virtual RenameElement(
/* [string][in] */ OLECHAR *pwcsOldName,
/* [string][in] */ OLECHAR *pwcsNewName),int;
declare virtual SetElementTimes(
/* [string][in] */ OLECHAR *pwcsName,
/* [in] */ pointer pctime,
/* [in] */ pointer patime,
/* [in] */ pointer pmtime),int;
declare virtual SetClass(
/* [in] */ GUID *clsid),int;
declare virtual SetStateBits(
/* [in] */ int grfStateBits,
/* [in] */ int grfMask),int;
declare virtual Stat(
/* [out] */ pointer pstatstg,
/* [in] */ int grfStatFlag),int;
}
interface IRichEditOLECallback : IUnknown
{
// *** IRichEditOleCallback methods ***
declare virtual GetNewStorage( pointer *lplpstg),int;
declare virtual GetInPlaceContext( pointer *lplpFrame,pointer *lplpDoc,pointer lpFrameInfo),int;
declare virtual ShowContainerUI(int fShow),int;
declare virtual QueryInsertObject( pointer lpclsid, pointer lpstg,int cp),int;
declare virtual DeleteObject( pointer lpoleobj),int;
declare virtual QueryAcceptData( pointer lpdataobj,CLIPFORMAT *lpcfFormat, int reco,int fReally, unsigned int hMetaPict),int;
declare virtual ContextSensitiveHelp( int fEnterMode),int;
declare virtual GetClipboardData( CHARRANGE *lpchrg, int reco,pointer *lplpdataobj),int;
declare virtual GetDragDropEffect( int fDrag, int grfKeyState,pointer pdwEffect),int;
declare virtual GetContextMenu( WORD seltype, pointer lpoleobj,CHARRANGE *lpchrg,unsigned int *lphmenu),int;
}
class REOLECallBack : IRichEditOLECallback
{
declare REOLECallBack();
declare _REOLECallBack();
declare virtual QueryInterface(riid as POINTER, ppvObj as POINTER),int;
declare virtual AddRef(),int;
declare virtual Release(),int;
declare virtual GetNewStorage( pointer *lplpstg),int;
declare virtual GetInPlaceContext( pointer *lplpFrame,pointer *lplpDoc,pointer lpFrameInfo),int;
declare virtual ShowContainerUI(int fShow),int;
declare virtual QueryInsertObject( pointer lpclsid, pointer lpstg,int cp),int;
declare virtual DeleteObject( pointer lpoleobj),int;
declare virtual QueryAcceptData( pointer lpdataobj,pointer lpcfFormat, int reco,int fReally, unsigned int hMetaPict),int;
declare virtual ContextSensitiveHelp( int fEnterMode),int;
declare virtual GetClipboardData( CHARRANGE *lpchrg, int reco,pointer *lplpdataobj),int;
declare virtual GetDragDropEffect( int fDrag, int grfKeyState,pointer pdwEffect),int;
declare virtual GetContextMenu( WORD seltype, pointer lpoleobj,CHARRANGE *lpchrg,unsigned int *lphmenu),int;
int mRefCounter;
IStorage *fStorage;
int nItemcount;
}
REOLECallBack::REOLECallBack()
{
mRefCounter = 0;
}
REOLECallBack::_REOLECallBack()
{
}
REOLECallBack::QueryInterface(riid as POINTER, ppvObj as POINTER),int
{
if(CompGuid(*(GUID)riid,_IID_IUnknown) or CompGuid(*(GUID)riid,_IID_IRichEditOleCallback))
return S_OK;
return E_NOINTERFACE;
}
REOLECallBack::AddRef(),int
{
InterlockedIncrement(&mRefCounter); return mRefCounter;
}
REOLECallBack::Release(),int
{
if ( InterlockedDecrement(&mRefCounter) <= 0 )
{
delete this;
return 0;
}
return mRefCounter;
}
REOLECallBack::GetNewStorage( pointer *lplpstg),int
{
// Initialize a Storage Object from a DocFile in memory
ILockBytes *lpLockBytes = NULL;
int sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);
if (sc <> S_OK) return sc;
sc = ::StgCreateDocfileOnILockBytes(lpLockBytes, STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, lplpstg);
if (sc <> S_OK) lpLockBytes->Release();
return sc;
}
REOLECallBack::GetInPlaceContext( pointer *lplpFrame,pointer *lplpDoc,pointer lpFrameInfo),int {return E_NOTIMPL;}
REOLECallBack::ShowContainerUI(int fShow),int {return E_NOTIMPL;}
REOLECallBack::QueryInsertObject( pointer lpclsid, pointer lpstg,int cp),int {return S_OK;}
REOLECallBack::DeleteObject( pointer lpoleobj),int {return E_NOTIMPL;}
REOLECallBack::QueryAcceptData( pointer lpdataobj,pointer lpcfFormat, int reco,int fReally, unsigned int hMetaPict),int {return E_NOTIMPL;}
REOLECallBack::ContextSensitiveHelp( int fEnterMode),int {return E_NOTIMPL;}
REOLECallBack::GetClipboardData( CHARRANGE *lpchrg, int reco,pointer *lplpdataobj),int {return E_NOTIMPL;}
REOLECallBack::GetDragDropEffect( int fDrag, int grfKeyState,pointer pdwEffect),int {return E_NOTIMPL;}
REOLECallBack::GetContextMenu( WORD seltype, pointer lpoleobj,CHARRANGE *lpchrg,unsigned int *lphmenu),int {return E_NOTIMPL;}
sub CompGuid(GUID g1,GUID g2),int
{
int x;
if g1.data1 = g2.data2
{
if g1.data2 = g2.data2
{
if g1.data3 = g2.data3
{
for x=0;x<8;x++
{
if g1.data4[x] <> g2.data4[x]
return 0;
}
return 1;
}
}
}
return 0;
}
Tried Rich Edit with an image.
If I load an image(jpg) into an image editor and then do a ctrl-c while in the editor; I can then run the rich edit demo and do a ctrl-v and the image will appear.
If I drag the image from explorer to the richedit control all I get is an image name inside a small rectangle with no image.
Is that how drag and drop is suppose to work? ???
Yes. The default drag and drop in Windows is to create a link. Try holding down the CTRL key while dragging.
If I try to drag a bitmap with and w/o ctrl I get a distorted image and the name of the file(yes, it is a link)
If I try a tiff with and w/o ctrl I get the name of the file(yes, it is a link)
Using ctrl and dragging a jpg i get just the file name and it must be trying to open the editor because I get one of those "poor baby...tell MS all about it" error messages.
Is there some way to force it to act the way it does when you copy the image to the clipboard and then paste from there?
Or is the proper way to get what I want done:
ÂÃ, Ã‚Ã, button to insert image that calls following routine:
ÂÃ, Ã‚Ã, 1. filerequest to pick image I want
ÂÃ, Ã‚Ã, 2. load image as a bitmap
ÂÃ, Ã‚Ã, 3. save bitmap to clipboard
ÂÃ, Ã‚Ã, 4. copy clipboard to richedit
Perhaps using PasteSpecial would do it. Search MSDN.
I guess it depends on what your trying to do with the RE control in the first place ;) Drag and drop works with OLE and objects. Dragging from the shell interface, such as a file view of explorer, you are dragging just a file name around.
I really want to select a file using filerequest and have the selected image inserted in a Richedit control at the current location. I want that image to appear full size(determined by stored image) I DON'T want any link to the image or to be able to edit the image or anything like that from the richedit.
My wants are pretty simple(or should I say 'straight-forward'). Gettin' there is the trick! ;D
Editing is part of the RE control functionality...so your stuck with the double click opening Paint (or whatever the default is).
Quote from: tlmccaughn on February 19, 2006, 04:29:53 PM
I really want to select a file using filerequest and have the selected image inserted in a Richedit control at the current location. I want that image to appear full size(determined by stored image) I DON'T want any link to the image or to be able to edit the image or anything like that from the richedit.
My wants are pretty simple(or should I say 'straight-forward'). Gettin' there is the trick! ;D
You can copy the image to the clipboard and then paste it into the RichText document. That should overcome your problem. When that method is used it will not be considered an OLE object.
Sorry I don't have sample code in Aurora for you but this is how I accomplished it in VB.
tlmccaughn, here's your solution with system IPicture class
#define RICHEDIT_1 1
#define BUTTON_2 2
#define BUTTON_3 3
#use "oleaut32.lib"
class dlg:CDialog
{
declare OnInitDialog(),int;
declare OnClose(),int;
declare OnControl(int nID, int nNotifyCode, unsigned int hControl),int;
declare OnSize(int nType,int cx,int cy),int;
declare InsertFile(string Path, CRichEdit *re1);
declare InsertImage(string Path, CRichEdit *re1);
}
global sub main()
{
dlg d1;
d1.Create(0,0,363,270,0x80CF0880,0,"Caption",0);
d1.AddControl(CTRICHEDIT,"",8,6,341,233,0x50B110C4,0x200,RICHEDIT_1);
d1.AddControl(CTBUTTON,"Add file...",10,244,120,22,0x50010000,0x0,BUTTON_2);
d1.AddControl(CTBUTTON,"Add image...",174,244,120,22,0x50010000,0x0,BUTTON_3);
d1.DoModal();
return true;
}
dlg::OnClose(),int
{
CloseDialog(1);
return true;
}
dlg::OnInitDialog(),int
{
return true;
}
dlg :: OnSize(int nType,int cx,int cy),int
{
CWindow *ctl = GetControl(RICHEDIT_1);
ctl->SetSize(6,6,cx-12,cy-40);
ctl = GetControl(BUTTON_2);
ctl->SetSize(10,cy-26,120,22);
ctl = GetControl(BUTTON_3);
ctl->SetSize(cx-130,cy-26,120,22);
return 0;
}
dlg::OnControl(int nID, int nNotifyCode, unsigned int hControl),int
{
select nID
{
case BUTTON_2:
if(nNotifyCode = 0)
{
InsertFile(FILEREQUEST("Select image",this, true,
"All supported types (bmp,jpg,gif,wmf,ico)|*.bmp;*.jpg;*.gif;*.wmf;*.ico||",""),
GetControl(RICHEDIT_1));
}
case BUTTON_3:
if(nNotifyCode = 0)
{
InsertImage(FILEREQUEST("Select image",this, true,
"All supported types (bmp,jpg,gif,wmf,ico)|*.bmp;*.jpg;*.gif;*.wmf;*.ico||",""),
GetControl(RICHEDIT_1));
}
}
return true;
}
CONST EM_PASTESPECIAL = 0x400 + 64;
struct DROPFILES {
int pFiles;
POINT pt;
int fNC;
int fWide;
// any custom data here
dstring path[260]; // any size path|null {,path|null, ...} null
}
import int SendMessage alias SendMessageA(int q,int w,int e,void *r);
#define WM_DROPFILES 0x233
dlg :: InsertFile(string Path, CRichEdit *re1)
{
// Path or re1 = null?
DROPFILES *df = new(DROPFILES,1); // memory is GPTR
df->pFiles = &df->path - df; // offset to path member
df->fWide = false;
df->path = Path;
SendMessage(re1->m_hwnd, WM_DROPFILES,df,0);
delete df;
return;
}
#typedef HBITMAP int
#typedef HRESULT int
#typedef OLESTR pointer
#typedef STDAPI int
#typedef LONG int
#typedef BOOL int
#typedef HWND int
#typedef UINT int
#typedef HANDLE int
#typedef OLE_COLOR int
#typedef DWORD int
#typedef HGDIOBJ int
#define S_OK 0
#define CF_BITMAP 2
// temporary guids
struct GUID {int x[4];}
struct REFIID {int x[4];}
interface IUnknown
{
declare virtual QueryInterface(REFIID *riid, void *lplpObj),HRESULT;
declare virtual AddRef(),LONG;
declare virtual Release(),LONG;
}
interface IPicture : IUnknown
{
declare virtual get_Handle(/*out*/OLE_HANDLE *pHandle),HRESULT;
declare virtual get_hPal(/*out*/OLE_HANDLE *phPal),HRESULT;
declare virtual get_Type(/*out*/SHORT *pType),HRESULT;
declare virtual get_Width(/*out*/OLE_XSIZE_HIMETRIC *pWidth),HRESULT;
declare virtual get_Height(/*out*/OLE_YSIZE_HIMETRIC *pHeight),HRESULT;
declare virtual Render(
/* [in] */ HDC hDC,LONG x,LONG y,LONG cx,LONG cy,
/* [in] */ OLE_XPOS_HIMETRIC xSrc,
/* [in] */ OLE_YPOS_HIMETRIC ySrc,
/* [in] */ OLE_XSIZE_HIMETRIC cxSrc,
/* [in] */ OLE_YSIZE_HIMETRIC cySrc,
/* [in] */ RECT *pRcWBounds),HRESULT;
declare virtual set_hPal(OLE_HANDLE hPal),HRESULT;
declare virtual get_CurDC(/*out*/ HDC *phDC),HRESULT;
declare virtual SelectPicture(HDC hDCIn,/*out*/HDC *phDCOut,/*out*/OLE_HANDLE *phBmpOut),HRESULT;
declare virtual get_KeepOriginalFormat(/* [out] */ BOOL *pKeep),HRESULT;
declare virtual put_KeepOriginalFormat(BOOL keep),HRESULT;
declare virtual PictureChanged(),HRESULT;
declare virtual SaveAsFile(IStream pStream,BOOL fSaveMemCopy,/* [out] */ LONG *pCbSize),HRESULT;
declare virtual get_Attributes(/*out*/DWORD *pDwAttr),HRESULT;
}
declare import, OleLoadPicturePath(
OLESTR *szURLorPath,
IUnknown *punkCaller,
DWORD dwReserved,
OLE_COLOR clrReserved,
REFIID *riid,
void *ppvRet
),STDAPI;
declare import, DeleteObject(HGDIOBJ hObject),BOOL;
extern int swprintf(...);
declare import, CoInitialize(opt void *pvReserved),HRESULT;
declare import, CoUninitialize();
declare import,OpenClipboard(opt HWND hWndNewOwner),BOOL;
declare import,CloseClipboard(),BOOL;
declare import,EmptyClipboard(),BOOL;
declare import,SetClipboardData(UINT uFormat,opt HANDLE hMem),HANDLE;
extern _IID_IPicture as GUID;
dlg :: InsertImage(string Path, CRichEdit *re1)
{
HBITMAP hBitmap = 0;
IPicture *pic;
CoInitialize(0);
OLESTR olepath = AllocHeap(len(Path)*2 +1);
swprintf(olepath, "%\x00S\x00\x00", Path); // make unicode
if S_OK=OleLoadPicturePath(olepath, 0, 0, 0, _IID_IPicture, &pic) {
pic->get_Handle(&hBitmap);
OpenClipboard(m_hwnd);
EmptyClipboard();
SetClipboardData(CF_BITMAP, hBitmap);
CloseClipboard();
SendMessage(re1->m_hwnd, EM_PASTESPECIAL, CF_BITMAP, null);
DeleteObject(hBitmap);
pic->Release();
}
else {
messagebox(this,"OleLoadPicturePath failed","");
}
FreeHeap(olepath);
CoUninitialize();
}
Sapero,
You come through again! :o
Many Thanks!!
swprintf should be declared as cdecl.
import int cdecl swprintf(...);
Doesn't the compiler automatically choose cdecl when variable parameters are used?
Good point ;)