pTextServices->TxSendMessage( EM_STREAMIN, ( WPARAM ) SF_RTF, ( LPARAM ) &editStream, &lResult ) does not call EditStreamInCallback - callback

When calling:
pTextServices->TxSendMessage( EM_STREAMIN, ( WPARAM ) SF_RTF, ( LPARAM ) &editStream, &lResult )
editSteam.EditStreamInCallback is not being called, but if SF_TEXT is used instead of SF_RTF, then editSteam.EditStreamInCallback gets called.
According to MS docs:
https://learn.microsoft.com/en-us/windows/win32/api/richedit/nc-richedit-editstreamcallback
An error occurs that prevents the rich edit control from transferring
data into or out of itself. Examples are out-of-memory situations,
failure of a system function, or an invalid character in the read
buffer.
In these cases editStream.dwError should contain a different value from zero, but it is zero.
This is the used RTF: "{\rtf1\ansi\pard test \par}" in the code escaped as:
"{\\rtf1\\ansi\\pard test \\par}"
Thank you

Fixed and working fine thanks to my friend Mr. Bruno Cantero (C3)
#include <Richedit.h>
#include <textserv.h>
typedef struct
{
char * szText;
LONG lSize;
LONG lCount;
} RTFTEXTINFO;
typedef HRESULT ( _stdcall * PCREATETEXTSERVICES ) ( IUnknown *, ITextHost *, IUnknown ** );
const IID IID_ITextServices = { 0x8d33f740, 0xcf58, 0x11ce, { 0xa8, 0x9d, 0x00, 0xaa, 0x00, 0x6c, 0xad, 0xc5 } };
class TTextHost : public ITextHost
{
public:
/* IUnknown */
STDMETHOD( QueryInterface )( REFIID, PVOID * ppvObject ) { * ppvObject = NULL; return S_FALSE; };
STDMETHOD_( ULONG, AddRef )( void ) { return 0; };
STDMETHOD_( ULONG, Release )( void ) { return 0; };
/* ITextHost */
HDC TxGetDC( void ) { return NULL; };
INT TxReleaseDC( HDC ) { return 1; };
BOOL TxShowScrollBar( INT, BOOL ) { return FALSE; };
BOOL TxEnableScrollBar( INT, INT ) { return FALSE; };
BOOL TxSetScrollRange( INT, LONG, INT, BOOL ) { return FALSE; };
BOOL TxSetScrollPos( INT, INT, BOOL ) { return FALSE; };
void TxInvalidateRect( LPCRECT, BOOL ) {};
void TxViewChange( BOOL ) {};
BOOL TxCreateCaret( HBITMAP, INT, INT ) { return FALSE; };
BOOL TxShowCaret( BOOL ) { return FALSE; };
BOOL TxSetCaretPos( INT, INT ) { return FALSE; };
BOOL TxSetTimer( UINT, UINT ) { return FALSE; };
void TxKillTimer( UINT ) {};
void TxScrollWindowEx( INT, INT, LPCRECT, LPCRECT, HRGN, LPRECT, UINT ) {};
void TxSetCapture( BOOL ) {};
void TxSetFocus( void ) {};
void TxSetCursor( HCURSOR, BOOL ) {};
BOOL TxScreenToClient( LPPOINT ) { return FALSE; };
BOOL TxClientToScreen( LPPOINT ) { return FALSE; };
HRESULT TxActivate( LONG * ) { return S_OK; };
HRESULT TxDeactivate( LONG ) { return S_OK; };
HRESULT TxGetClientRect( LPRECT prc ) { SetRectEmpty( prc ); return S_OK; };
HRESULT TxGetViewInset( LPRECT prc ) { SetRectEmpty( prc ); return S_OK; };
HRESULT TxGetCharFormat( const CHARFORMATW ** ppCF ) { * ppCF = FCharFormat; return S_OK; };
HRESULT TxGetParaFormat( const PARAFORMAT ** ppPF ) { * ppPF = FParaFormat; return S_OK; };
COLORREF TxGetSysColor( int iIndex ) { return GetSysColor( iIndex ); };
HRESULT TxGetBackStyle( TXTBACKSTYLE * pstyle ) { * pstyle = TXTBACK_TRANSPARENT; return S_OK; };
HRESULT TxGetMaxLength( DWORD * plength ) { * plength = INFINITE; return S_OK; };
HRESULT TxGetScrollBars( DWORD * pdwScrollBar ) { * pdwScrollBar = 0; return S_OK; };
HRESULT TxGetPasswordChar( _Out_ TCHAR * pch ) { return S_FALSE; };
HRESULT TxGetAcceleratorPos( LONG * pcp ) { * pcp = -1; return S_OK; };
HRESULT TxGetExtent( LPSIZEL ) { return E_NOTIMPL; };
HRESULT OnTxCharFormatChange( const CHARFORMATW * pCF ) { _bcopy( FCharFormat, ( void * ) pCF, pCF->cbSize ); return S_OK; };
HRESULT OnTxParaFormatChange( const PARAFORMAT * pPF ) { _bcopy( FParaFormat, ( void * ) pPF, pPF->cbSize ); return S_OK; };
HRESULT TxGetPropertyBits( DWORD, DWORD * pdwBits ) { * pdwBits = TXTBIT_RICHTEXT | TXTBIT_MULTILINE | TXTBIT_WORDWRAP | TXTBIT_USECURRENTBKG; return S_OK; };
HRESULT TxNotify( DWORD, void * ) { return S_OK; };
HIMC TxImmGetContext( void ) { return NULL; };
void TxImmReleaseContext( HIMC ) {};
HRESULT TxGetSelectionBarWidth( LONG * lSelBarWidth ) { * lSelBarWidth = 100; return S_OK; };
CHARFORMATW * FCharFormat;
PARAFORMAT * FParaFormat;
};
static DWORD CALLBACK EditStreamCallback( DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG * pcb )
{
RTFTEXTINFO * pRtfTextInfo;
pRtfTextInfo = ( RTFTEXTINFO * ) dwCookie;
if( pRtfTextInfo->lSize - pRtfTextInfo->lCount < cb )
* pcb = pRtfTextInfo->lSize - pRtfTextInfo->lCount;
else
* pcb = cb;
memcpy( pbBuff, pRtfTextInfo->szText, * pcb );
pRtfTextInfo->lCount += * pcb;
return 0;
}
extern "C" void SayRTF( void )
{
LRESULT lResult;
HDC hDC;
HFONT hFont;
HMODULE hDLL;
RECT stRect;
LOGFONT stLogFont;
EDITSTREAM stEditStream;
PCREATETEXTSERVICES pCreateTextServices;
CHARFORMATW stCharFormat;
PARAFORMAT stParaFormat;
RTFTEXTINFO sRtfTextInfo;
IUnknown * pUnknown;
ITextServices * pTextServices;
TTextHost * pTextHost;
/* HDC donde dibujar. */
hDC = ( HDC ) hb_parnl( 1 ); // the hDC where you want to show the RTF
// Comentamos para probar la transperencia Rectangle( hDC, 9, 9, 202, 202 );
stRect = { 10, 10, 200, 200 };
hDLL = LoadLibrary( "Riched20.dll" );
if( hDLL == NULL )
return;
pCreateTextServices = ( PCREATETEXTSERVICES ) GetProcAddress( hDLL, "CreateTextServices" );
if( pCreateTextServices == NULL )
{
FreeLibrary( hDLL );
return;
}
/* Obtenemos las características de la fuente del HDC. */
hFont = ( HFONT ) SelectObject( hDC, GetStockObject( SYSTEM_FONT ) );
GetObject( hFont, sizeof( LOGFONT ), &stLogFont );
SelectObject( hDC, hFont );
/* Creamos el formato de la fuente por defecto. */
memset( &stCharFormat, 0, sizeof( CHARFORMATW ) );
stCharFormat.cbSize = sizeof( CHARFORMATW );
stCharFormat.dwEffects = CFM_EFFECTS | CFE_AUTOBACKCOLOR;
stCharFormat.dwEffects &= ~( CFE_PROTECTED | CFE_LINK | CFE_AUTOCOLOR );
if( stLogFont.lfWeight < FW_BOLD )
stCharFormat.dwEffects &= ~CFE_BOLD;
if( !stLogFont.lfItalic )
stCharFormat.dwEffects &= ~CFE_ITALIC;
if( !stLogFont.lfUnderline )
stCharFormat.dwEffects &= ~CFE_UNDERLINE;
if( !stLogFont.lfStrikeOut )
stCharFormat.dwEffects &= ~CFE_STRIKEOUT;
stCharFormat.dwMask = CFM_ALL | CFM_BACKCOLOR | CFM_STYLE;
stCharFormat.bCharSet = stLogFont.lfCharSet;
stCharFormat.bPitchAndFamily = stLogFont.lfPitchAndFamily;
stCharFormat.yHeight = -stLogFont.lfHeight * 1440 / GetDeviceCaps( hDC, LOGPIXELSY );
MultiByteToWideChar( CP_ACP, 0, stLogFont.lfFaceName, LF_FACESIZE, stCharFormat.szFaceName, LF_FACESIZE );
/* Creamos el formato de párrafo por defecto. */
memset( &stParaFormat, 0, sizeof( PARAFORMAT ) );
stParaFormat.cbSize = sizeof( PARAFORMAT );
stParaFormat.dwMask = PFM_ALL;
stParaFormat.wAlignment = PFA_LEFT;
stParaFormat.cTabCount = 1;
stParaFormat.rgxTabs[ 0 ] = lDefaultTab;
/* Instanciamos nuestro objeto host. */
pTextHost = new TTextHost;
pTextHost->FCharFormat = &stCharFormat;
pTextHost->FParaFormat = &stParaFormat;
/* Creamos el objeto IUnknown y lo asociamos a nuestro objeto TTextHost. */
if( pCreateTextServices( NULL, pTextHost, &pUnknown ) != S_OK )
{
delete pTextHost;
FreeLibrary( hDLL );
return;
}
/* Obtenemos el interface ITextServices. */
pTextServices = NULL;
pUnknown->QueryInterface( IID_ITextServices, ( void ** ) &pTextServices );
/* Liberamos el objeto IUnknown. */
pUnknown->Release();
if( pTextServices != NULL )
{
// sRtfTextInfo.szText = "Plaint Text";
sRtfTextInfo.szText = "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 Tahoma;}{\\f1\\fswiss\\fcharset0 Arial;}}{\\colortbl ;\\red128\\green0\\blue0;\\red0\\green0\\blue128;\\red0\\green128\\blue0;}\\viewkind4\\uc1\\pard\\f0\\fs20 H\\fs24 E\\b L\\ul\\fs20 L\\i O\\ulnone\\b0\\i0 \\cf1 W\\b\\fs22 O\\cf2\\ul\\b0 R\\i\\fs28 L\\cf3\\ulnone\\b\\i0\\fs20 D\\cf0\\b0\\f1\\par}";
sRtfTextInfo.lSize = lstrlen( sRtfTextInfo.szText );
sRtfTextInfo.lCount = 0;
stEditStream.dwCookie = ( DWORD_PTR ) &sRtfTextInfo;
stEditStream.pfnCallback = EditStreamCallback;
// if( pTextServices->TxSendMessage( EM_STREAMIN, SF_TEXT, ( LPARAM ) &stEditStream, &lResult ) == S_OK )
if( pTextServices->TxSendMessage( EM_STREAMIN, SF_RTF, ( LPARAM ) &stEditStream, &lResult ) == S_OK )
pTextServices->TxDraw( DVASPECT_CONTENT, 0, NULL, NULL, hDC, NULL, ( RECTL * ) &stRect, NULL, NULL, NULL, 0, TXTVIEW_INACTIVE );
/* Liberamos el objeto ITextServices. */
pTextServices->Release();
}
delete pTextHost;
FreeLibrary( hDLL );
}

Related

FreeRTOS: Queue did not work as expected

I am new to FreeRTOS. I have written an example using queue to transfer data between tasks. Nevertheless, the results displayed are wrong. May anyone help me to get over this problem?
Thanks!
Variables to be displayed:
unsigned int temperatureRaw = 25;
unsigned int flowRateRaw = 30;
unsigned int carbonLevelRaw = 250;
unsigned int salinityLevelRaw = 75;
Struct holding pointers to above variables:
struct RawData {
unsigned int *temperatureRaw;
unsigned int *flowRateRaw;
unsigned int *carbonLevelRaw;
unsigned int *salinityLevelRaw;
};
typedef struct RawData RawData;
Tasks' prototype
static void vOLEDTask( void *pvParameters );
static void vTask1( void *pvParameters );
static void prvSetupHardware( void );
Queue handles:
QueueHandle_t xOLEDQueue, xRawQueue;
Main:
int main( void )
{
prvSetupHardware();
/* Create queues */
xOLEDQueue = xQueueCreate( mainOLED_QUEUE_SIZE, sizeof( xOLEDMessage * ) );
xRawQueue = xQueueCreate( 3, sizeof( RawData * ) );
/* Check if queues are successfully created */
if( ( xOLEDQueue != 0 ) && ( xRawQueue != 0 ) ) {
// Declare variables
RawData xRawData = { &temperatureRaw, &flowRateRaw, &carbonLevelRaw, &salinityLevelRaw };
RawData *pxRawData = &xRawData;
/* Start the tasks defined within this file/specific to this demo. */
xTaskCreate( vOLEDTask, "OLED", mainOLED_TASK_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
xTaskCreate( vTask1, "Task1", 1000, ( void * )pxRawData, 1, NULL );
/* Start the scheduler. */
vTaskStartScheduler();
}
return 0;
}
Tasks' definition:
void prvSetupHardware( void )
{
/* If running on Rev A2 silicon, turn the LDO voltage up to 2.75V. This is
a workaround to allow the PLL to operate reliably. */
if( DEVICE_IS_REVA2 )
{
SysCtlLDOSet( SYSCTL_LDO_2_75V );
}
/* Set the clocking to run from the PLL at 50 MHz */
SysCtlClockSet( SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_8MHZ );
}
void vOLEDTask( void *pvParameters )
{
RawData *pxRawData = NULL;
unsigned long ulMaxY;
static char cMessage[ mainMAX_MSG_LEN ];
extern volatile unsigned long ulMaxJitter;
const unsigned char *pucImage;
/* Functions to access the OLED. The one used depends on the dev kit
being used. */
void ( *vOLEDInit )( unsigned long ) = NULL;
void ( *vOLEDStringDraw )( const char *, unsigned long, unsigned long, unsigned char ) = NULL;
void ( *vOLEDImageDraw )( const unsigned char *, unsigned long, unsigned long, unsigned long, unsigned long ) = NULL;
void ( *vOLEDClear )( void ) = NULL;
/* Map the OLED access functions to the driver functions that are appropriate
for the evaluation kit being used. */
switch( HWREG( SYSCTL_DID1 ) & SYSCTL_DID1_PRTNO_MASK )
{
case SYSCTL_DID1_PRTNO_6965 :
case SYSCTL_DID1_PRTNO_2965 : vOLEDInit = OSRAM128x64x4Init;
vOLEDStringDraw = OSRAM128x64x4StringDraw;
vOLEDImageDraw = OSRAM128x64x4ImageDraw;
vOLEDClear = OSRAM128x64x4Clear;
ulMaxY = mainMAX_ROWS_64;
pucImage = pucBasicBitmap;
break;
case SYSCTL_DID1_PRTNO_1968 :
case SYSCTL_DID1_PRTNO_8962 : vOLEDInit = RIT128x96x4Init;
vOLEDStringDraw = RIT128x96x4StringDraw;
vOLEDImageDraw = RIT128x96x4ImageDraw;
vOLEDClear = RIT128x96x4Clear;
ulMaxY = mainMAX_ROWS_96;
pucImage = pucBasicBitmap;
break;
default : vOLEDInit = vFormike128x128x16Init;
vOLEDStringDraw = vFormike128x128x16StringDraw;
vOLEDImageDraw = vFormike128x128x16ImageDraw;
vOLEDClear = vFormike128x128x16Clear;
ulMaxY = mainMAX_ROWS_128;
pucImage = pucGrLibBitmap;
break;
}
/* Initialise the OLED and display a startup message. */
vOLEDInit( ulSSI_FREQUENCY );
for( ;; )
{
xQueueReceive( xRawQueue, ( void * )&pxRawData, portMAX_DELAY );
/* Display the message. */
sprintf( cMessage, "%s %u C", "Temperature", *(pxRawData->temperatureRaw) );
vOLEDStringDraw( cMessage, 0, 10, mainFULL_SCALE );
sprintf( cMessage, "%s %u LPS", "Flow Rate", *(pxRawData->flowRateRaw) );
vOLEDStringDraw( cMessage, 0, 20, mainFULL_SCALE );
sprintf( cMessage, "%s %u ppm", "Carbon Level", *(pxRawData->carbonLevelRaw) );
vOLEDStringDraw( cMessage, 0, 30, mainFULL_SCALE );
sprintf( cMessage, "%s %u ppt", "Salinity Level", *(pxRawData->salinityLevelRaw) );
vOLEDStringDraw( cMessage, 0, 40, mainFULL_SCALE );
}
}
/*-----------------------------------------------------------*/
static void vTask1( void *pvParameters )
{
RawData *pxRawData = ( RawData * )pvParameters;
for( ;; ) {
xQueueSend( xRawQueue, ( void * )&pxRawData, portMAX_DELAY );
vTaskDelay( 1000/portTICK_RATE_MS );
}
}
I have not studied all the code, but the first problem I see is that you are passing pxRawData as a parameter to a task, pxRawData is a pointer to xRawData, but xRawData has a very narrow block scope, and the stack it is declared on is different to the stack used by the task, so the variable being pointed to will not exist when the task starts running - or if it does exist it is by luck and there is a risk it will get overwritten (depending on the FreeRTOS port being used).
Also, consider that xRawQueue is created to hold pointers to RawData, but I think your call to xQueueSend in vTask1 is passing the address of a pointer, so it is queuing a pointer to a pointer to RawData, not a pointer to RawData. Although that probably doesn't matter as its being received into a pointer to a pointer too, and then accessed as such.

Somthing confused with ole drag and drop implementation [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I wish to finish a little demo to implement OLE drag and drop(drag a file from my application to windows explorer).
But here comes a problem:DoDragDrop return DRAGDROP_S_DROP which means the ole drag and drop operation has successfully done,but also get DROPEFFECT_NONE which means drop target cannot accept the data.
I debug into it but I get a mess with them,help me,please:(
Here is the gui:
Critical code comes:
1.MainWindow.h
#ifndef MainWindowH
#define MainWindowH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <Ole2.h>
#include "MyDataObject.h"
#include "MyDropSource.h"
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TLabel *Label1;
void __fastcall Label1StartDrag(TObject *Sender, TDragObject *&DragObject);
void __fastcall Label1EndDrag(TObject *Sender, TObject *Target, int X, int Y);
void __fastcall FormCreate(TObject *Sender);
void __fastcall FormDestroy(TObject *Sender);
private: // User declarations
//准备两个接口实例
IDataObject *pDataObject;
IDropSource *pDropSource;
//
STGMEDIUM stgmed;
FORMATETC fmtetc;
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
2.DoDragDrop invoke in MainWindow.cpp
void __fastcall TForm1::Label1StartDrag(TObject *Sender, TDragObject *&DragObject)
{
Label1->Caption = "Start drag";
//Source file
char tFileName[256] = "D:\\119.dat";
//Prepare FOTMATETC
fmtetc.cfFormat = CF_HDROP;
fmtetc.dwAspect = DVASPECT_CONTENT;
fmtetc.lindex = -1;
fmtetc.ptd = (void*)0;
fmtetc.tymed = TYMED_HGLOBAL;
//Prepare DROPFILES
DROPFILES* tDropFiles;
//Fill the filename
HGLOBAL hGblFiles;
LPSTR lpData;
stgmed.hGlobal = GlobalAlloc(GHND, sizeof(DROPFILES)+strlen(tFileName)+ 2);
if(0 == stgmed.hGlobal)
MessageBoxA(NULL, "OUT_OF_MEMORY!!!", "OUT_OF_MEMORY", 0);
tDropFiles = (DROPFILES*)GlobalLock(stgmed.hGlobal);
ZeroMemory(tDropFiles, sizeof(DROPFILES)+strlen(tFileName)+2);
strcpy(((char*)tDropFiles)+sizeof(DROPFILES), tFileName);
GlobalUnlock(stgmed.hGlobal);
tDropFiles->fNC = true;
tDropFiles->fWide = false;
tDropFiles->pFiles = sizeof(DROPFILES);
tDropFiles->pt.x = 0;
tDropFiles->pt.y = 0;
//set hGlobal
stgmed.tymed = TYMED_HGLOBAL;
stgmed.hGlobal = tDropFiles;
stgmed.pUnkForRelease = 0;
//Create Instance of IDropSource and IDataObject
pDropSource = new MyDropSource();
pDropSource->AddRef();
pDataObject = new MyDataObject();
pDataObject->AddRef();
//SetData
pDataObject->SetData(&fmtetc, &stgmed, true);
OleInitialize(0);
//Invoke DoDragDrop
DWORD dwEffect;
HRESULT tResult = DoDragDrop((IDataObject*)pDataObject, (IDropSource*)pDropSource, DROPEFFECT_MOVE, &dwEffect);
//Ckeck drag&drop result
if(tResult != DRAGDROP_S_DROP)
{
if(tResult == DRAGDROP_S_CANCEL)
MessageBoxA(NULL, "DRAGDROP_S_CANCEL!", "DRAGDROP_S_DROP", 0);
else
MessageBoxA(NULL, "E_UNSPEC!", "DRAGDROP_S_DROP", 0);
return;
}
if((dwEffect & DROPEFFECT_MOVE) == DROPEFFECT_MOVE)
MessageBoxA(NULL, "Ole drag&drop OK!!", "DRAGDROP_S_DROP", 0);
else
{
if((dwEffect & DROPEFFECT_NONE) == DROPEFFECT_NONE)
MessageBoxA(NULL, "DROPEFFECT_NONE!!", "DRAGDROP_S_DROP", 0);
}
//Clean
pDropSource->Release();
pDataObject->Release();
OleUninitialize();
return;
}
3.MyDataObject.h
#ifndef _MYDATAOBJECT_H_
#define _MYDATAOBJECT_H_
#include <stdio.h>
#include "IDragDemo.h"
#include "MyDropSource.h"
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) { if(p){delete(p); (p)=NULL;} }
#endif
HRESULT CreateEnumFormatEtc(UINT cfmt, FORMATETC *afmt, IEnumFORMATETC **ppEnumFormatEtc);
class MyDataObject : public IDataObject
{
public:
//IUnknown implementation
ULONG __stdcall AddRef();
ULONG __stdcall Release();
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
//IDataObject members
STDMETHODIMP GetData (FORMATETC *pformatetcIn, STGMEDIUM *pmedium);
STDMETHODIMP GetDataHere (FORMATETC *pformatetc, STGMEDIUM *pmedium);
STDMETHODIMP QueryGetData (FORMATETC *pformatetc);
STDMETHODIMP GetCanonicalFormatEtc (FORMATETC *pformatectIn, FORMATETC *pformatetcOut);
STDMETHODIMP SetData (FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease);
STDMETHODIMP EnumFormatEtc (DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc);
STDMETHODIMP DAdvise (FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);
STDMETHODIMP DUnadvise (DWORD dwConnection);
STDMETHODIMP EnumDAdvise (IEnumSTATDATA **ppenumAdvise);
public:
MyDataObject();
~MyDataObject();
private:
LONG refcount;
FORMATETC* m_AcceptFormat;
STGMEDIUM* m_StorageMedium;
HGLOBAL DupGlobalMem(HGLOBAL hMem);
//Helper function
HRESULT CopyMedium(STGMEDIUM* pMedDest, STGMEDIUM* pMedSrc, FORMATETC* pFmtSrc);
HRESULT SetBlob(CLIPFORMAT cf, const void *pvBlob, UINT cbBlob);
LONG m_RefCount;
};
//----------------MyEnumFormatEtc-----------------------------------------------------------
class MyEnumFormatEtc : public IEnumFORMATETC
{
public:
// IUnknown members
HRESULT __stdcall QueryInterface (REFIID iid, void ** ppv)
{
if((iid==IID_IUnknown)||(iid==IID_IEnumFORMATETC))
{
*ppv=this;
AddRef();
return S_OK;
}
else
{
*ppv=NULL;
return E_NOINTERFACE;
}
}
ULONG __stdcall AddRef (void) { return ++_iRefCount; }
ULONG __stdcall Release (void) { if(--_iRefCount==0){delete this; return 0;} return _iRefCount; }
// IEnumFormatEtc members
HRESULT __stdcall Next (ULONG celt, FORMATETC * rgelt, ULONG * pceltFetched);
HRESULT __stdcall Skip (ULONG celt)
{
_nIndex += celt;
return (_nIndex <= _nNumFormats) ? S_OK : S_FALSE;
}
HRESULT __stdcall Reset (void)
{
_nIndex = 0;
return S_OK;
}
HRESULT __stdcall Clone (IEnumFORMATETC ** ppEnumFormatEtc)
{
HRESULT hResult;
hResult = CreateEnumFormatEtc(_nNumFormats, _pFormatEtc, ppEnumFormatEtc);
if(hResult == S_OK)
{
((MyEnumFormatEtc *)*ppEnumFormatEtc)->_nIndex = _nIndex;
}
return hResult;
}
// Construction / Destruction
MyEnumFormatEtc(FORMATETC *pFormatEtc, ULONG nNumFormats);
~MyEnumFormatEtc();
private:
LONG _iRefCount;
ULONG _nIndex;
ULONG _nNumFormats;
FORMATETC * _pFormatEtc;
};
//---------------------------------------------------------------------------
#endif
4.MyDataObject.cpp
#include "MyDataObject.h"
#include "MyDropSource.h"
#include <Urlmon.h>
MyDataObject::MyDataObject(MyDropSource* vDropSource)
{
m_RefCount = 0;
m_DropSource = vDropSource;
}
MyDataObject::~MyDataObject()
{
refcount = 0;
SAFE_DELETE(m_StorageMedium);
SAFE_DELETE(m_AcceptFormat);
}
ULONG __stdcall MyDataObject::AddRef()
{
return InterlockedIncrement(&m_RefCount);
}
ULONG __stdcall MyDataObject::Release()
{
ULONG nRefCount = InterlockedDecrement(&m_RefCount);
if (nRefCount == 0)
delete this;
return nRefCount;
}
STDMETHODIMP MyDataObject::QueryInterface(REFIID riid, void **ppvObject) {
if (!ppvObject)
return E_POINTER;
if (riid == IID_IDataObject)
*ppvObject = (IDataObject*)this;
else if (riid == IID_IUnknown)
*ppvObject = (IUnknown*)this;
else
{
*ppvObject = 0;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
STDMETHODIMP MyDataObject::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
{
if ( (NULL == pformatetcIn) || (NULL == pmedium) )
{
return E_INVALIDARG;
}
pmedium->hGlobal = NULL;
if( (pformatetcIn->tymed & m_AcceptFormat->tymed) &&
(pformatetcIn->dwAspect == m_AcceptFormat->dwAspect) &&
(pformatetcIn->cfFormat == m_AcceptFormat->cfFormat) )
{
return CopyMedium(pmedium, m_StorageMedium, m_AcceptFormat);
}
return DV_E_FORMATETC;
}
STDMETHODIMP MyDataObject::GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium)
{
return E_NOTIMPL;
}
STDMETHODIMP MyDataObject::QueryGetData(FORMATETC *pformatetc)
{
if(NULL == pformatetc )
{
return E_INVALIDARG;
}
if(!(DVASPECT_CONTENT & pformatetc->dwAspect))
{
return DV_E_DVASPECT;
}
HRESULT hr = DV_E_TYMED;
if(m_AcceptFormat->tymed & pformatetc->tymed )
{
if(m_AcceptFormat->cfFormat == pformatetc->cfFormat )
{
return S_OK;
}
else
{
hr = DV_E_CLIPFORMAT;
}
}
else
{
hr = DV_E_TYMED;
}
return hr;
}
STDMETHODIMP MyDataObject::GetCanonicalFormatEtc(FORMATETC *pformatectIn, FORMATETC *pformatetcOut)
{
pformatetcOut->ptd = NULL;
return E_NOTIMPL;
}
STDMETHODIMP MyDataObject::SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
{
if ( (NULL == pformatetc) || (NULL == pmedium) )
return E_INVALIDARG;
if ( pformatetc->tymed != pmedium->tymed )
return E_FAIL;
m_AcceptFormat = new FORMATETC;
m_StorageMedium = new STGMEDIUM;
ZeroMemory(m_AcceptFormat, sizeof(FORMATETC));
ZeroMemory(m_StorageMedium, sizeof(STGMEDIUM));
if ( TRUE == fRelease )
{
*m_StorageMedium = *pmedium;
}
else
{
CopyMedium(m_StorageMedium, pmedium, pformatetc);
}
return S_OK;
}
STDMETHODIMP MyDataObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc)
{
if(NULL == ppenumFormatEtc)
{
return E_INVALIDARG;
}
*ppenumFormatEtc = NULL;
HRESULT hr = E_NOTIMPL;
if (DATADIR_GET == dwDirection )
{
FORMATETC rgfmtetc[] =
{
{ CF_HDROP, NULL, DVASPECT_CONTENT, 0, TYMED_HGLOBAL },
};
hr = CreateEnumFormatEtc(ARRAYSIZE(rgfmtetc), rgfmtetc, ppenumFormatEtc);
}
return hr;
}
//Advises:OLE_E_ADVISENOTSUPPORTED
STDMETHODIMP MyDataObject::DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
{
UNREFERENCED_PARAMETER(pformatetc);
UNREFERENCED_PARAMETER(advf);
UNREFERENCED_PARAMETER(pAdvSink);
UNREFERENCED_PARAMETER(pdwConnection);
return E_NOTIMPL;
}
STDMETHODIMP MyDataObject::DUnadvise(DWORD dwConnection)
{
UNREFERENCED_PARAMETER(dwConnection);
return E_NOTIMPL;
}
STDMETHODIMP MyDataObject::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
{
UNREFERENCED_PARAMETER(ppenumAdvise);
return E_NOTIMPL;
}
//Advises:OLE_E_ADVISENOTSUPPORTED
HGLOBAL MyDataObject::DupGlobalMem(HGLOBAL hMem)
{
DWORD len = GlobalSize(hMem);
PVOID source = GlobalLock(hMem);
PVOID dest = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, len);
memcpy(dest, source, len);
GlobalUnlock(hMem);
return dest;
}
HRESULT MyDataObject::CopyMedium(STGMEDIUM* pMedDest, STGMEDIUM* pMedSrc, FORMATETC* pFmtSrc)
{
if ( (NULL == pMedDest) || (NULL ==pMedSrc) || (NULL == pFmtSrc) )
{
return E_INVALIDARG;
}
switch(pMedSrc->tymed)
{
case TYMED_HGLOBAL:
pMedDest->hGlobal = (HGLOBAL)OleDuplicateData(pMedSrc->hGlobal, pFmtSrc->cfFormat, NULL);
break;
case TYMED_GDI:
pMedDest->hBitmap = (HBITMAP)OleDuplicateData(pMedSrc->hBitmap, pFmtSrc->cfFormat, NULL);
break;
case TYMED_MFPICT:
pMedDest->hMetaFilePict = (HMETAFILEPICT)OleDuplicateData(pMedSrc->hMetaFilePict, pFmtSrc->cfFormat, NULL);
break;
case TYMED_ENHMF:
pMedDest->hEnhMetaFile = (HENHMETAFILE)OleDuplicateData(pMedSrc->hEnhMetaFile, pFmtSrc->cfFormat, NULL);
break;
case TYMED_FILE:
pMedSrc->lpszFileName = (LPOLESTR)OleDuplicateData(pMedSrc->lpszFileName, pFmtSrc->cfFormat, NULL);
break;
case TYMED_ISTREAM:
pMedDest->pstm = pMedSrc->pstm;
pMedSrc->pstm->AddRef();
break;
case TYMED_ISTORAGE:
pMedDest->pstg = pMedSrc->pstg;
pMedSrc->pstg->AddRef();
break;
case TYMED_NULL:
default:
break;
}
pMedDest->tymed = pMedSrc->tymed;
pMedDest->pUnkForRelease = NULL;
if(pMedSrc->pUnkForRelease != NULL)
{
pMedDest->pUnkForRelease = pMedSrc->pUnkForRelease;
pMedSrc->pUnkForRelease->AddRef();
}
return S_OK;
}
HRESULT MyDataObject::SetBlob(CLIPFORMAT cf, const void *pvBlob, UINT cbBlob)
{
void *pv = GlobalAlloc(GPTR, cbBlob);
HRESULT hr = pv ? S_OK : E_OUTOFMEMORY;
if ( SUCCEEDED(hr) )
{
CopyMemory(pv, pvBlob, cbBlob);
FORMATETC fmte = {cf, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
STGMEDIUM medium = {};
medium.tymed = TYMED_HGLOBAL;
medium.hGlobal = pv;
hr = this->SetData(&fmte, &medium, TRUE);
if (FAILED(hr))
{
GlobalFree(pv);
}
}
return hr;
}
HRESULT CreateEnumFormatEtc(UINT cfmt, FORMATETC *afmt, IEnumFORMATETC **ppEnumFormatEtc)
{
if (cfmt == 0 || afmt == 0 || ppEnumFormatEtc == 0)
return E_INVALIDARG;
*ppEnumFormatEtc = new MyEnumFormatEtc(afmt, cfmt);
return (*ppEnumFormatEtc) ? S_OK: E_OUTOFMEMORY;
}
void DeepCopyFormatEtc(FORMATETC *dest, FORMATETC *source)
{
*dest = *source;
if(source->ptd)
{
dest->ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(sizeof(DVTARGETDEVICE));
*(dest->ptd) = *(source->ptd);
}
}
MyEnumFormatEtc::MyEnumFormatEtc(FORMATETC *pFormatEtc, ULONG nNumFormats)
:_iRefCount(1),_nIndex(0),_nNumFormats(nNumFormats)
{
_pFormatEtc = new FORMATETC[nNumFormats];
// make a new copy of each FORMATETC structure
for(ULONG i = 0; i < nNumFormats; i++)
{
DeepCopyFormatEtc (&_pFormatEtc[i], &pFormatEtc[i]);
}
}
MyEnumFormatEtc::~MyEnumFormatEtc()
{
// first free any DVTARGETDEVICE structures
for(ULONG i = 0; i < _nNumFormats; i++)
{
if(_pFormatEtc[i].ptd)
CoTaskMemFree(_pFormatEtc[i].ptd);
}
// now free the main array
delete[] _pFormatEtc;
}
HRESULT __stdcall MyEnumFormatEtc::Next(ULONG celt, FORMATETC *pFormatEtc, ULONG *pceltFetched)
{
ULONG copied = 0;
// copy the FORMATETC structures into the caller's buffer
while (_nIndex < _nNumFormats && copied < celt)
{
DeepCopyFormatEtc (&pFormatEtc [copied], &_pFormatEtc [_nIndex]);
copied++;
_nIndex++;
}
// store result
if(pceltFetched != 0)
*pceltFetched = copied;
// did we copy all that was requested?
return (copied == celt) ? S_OK : S_FALSE;
}
5.MyDropSource.h
#ifndef _MYDROPSOURCE_H_
#define _MYDROPSOURCE_H_
#include <stdio.h>
#include "IDragDemo.h"
class MyDropSource : public IDropSource
{
public:
//IUnknown implementation
ULONG __stdcall AddRef();
ULONG __stdcall Release();
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
//IDropSource members
STDMETHODIMP QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState);
STDMETHODIMP GiveFeedback(DWORD dwEffect);
//Cons/Destructors
MyDropSource();
~MyDropSource();
private:
LONG refcount;
};
#endif
6.MyDropSource.cpp
#include "MyDataObject.h"
#include "MyDropSource.h"
#include <Urlmon.h>
//Constructors
MyDataObject::MyDataObject(MyDropSource* vDropSource)
{
m_RefCount = 0;
m_DropSource = vDropSource;
}
//Destructors
MyDataObject::~MyDataObject()
{
refcount = 0;
SAFE_DELETE(m_StorageMedium);
SAFE_DELETE(m_AcceptFormat);
}
//IUnkown implementation
ULONG __stdcall MyDataObject::AddRef()
{
return InterlockedIncrement(&m_RefCount);
}
ULONG __stdcall MyDataObject::Release()
{
ULONG nRefCount = InterlockedDecrement(&m_RefCount);
if (nRefCount == 0)
delete this;
return nRefCount;
}
STDMETHODIMP MyDataObject::QueryInterface(REFIID riid, void **ppvObject) {
if (!ppvObject)
return E_POINTER;
if (riid == IID_IDataObject)
*ppvObject = (IDataObject*)this;
else if (riid == IID_IUnknown)
*ppvObject = (IUnknown*)this;
else
{
*ppvObject = 0;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
STDMETHODIMP MyDataObject::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
{
//入参检查
if ( (NULL == pformatetcIn) || (NULL == pmedium) )
{
return E_INVALIDARG;
}
pmedium->hGlobal = NULL;
if( (pformatetcIn->tymed & m_AcceptFormat->tymed) &&
(pformatetcIn->dwAspect == m_AcceptFormat->dwAspect) &&
(pformatetcIn->cfFormat == m_AcceptFormat->cfFormat) )
{
return CopyMedium(pmedium, m_StorageMedium, m_AcceptFormat);
}
return DV_E_FORMATETC;
}
STDMETHODIMP MyDataObject::GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium)
{
return E_NOTIMPL;
}
STDMETHODIMP MyDataObject::QueryGetData(FORMATETC *pformatetc)
{
if(NULL == pformatetc )
{
return E_INVALIDARG;
}
if(!(DVASPECT_CONTENT & pformatetc->dwAspect))
{
return DV_E_DVASPECT;
}
HRESULT hr = DV_E_TYMED;
if(m_AcceptFormat->tymed & pformatetc->tymed )
{
if(m_AcceptFormat->cfFormat == pformatetc->cfFormat )
{
return S_OK;
}
else
{
hr = DV_E_CLIPFORMAT;
}
}
else
{
hr = DV_E_TYMED;
}
return hr;
}
STDMETHODIMP MyDataObject::GetCanonicalFormatEtc(FORMATETC *pformatectIn, FORMATETC *pformatetcOut)
{
pformatetcOut->ptd = NULL;
return E_NOTIMPL;
}
STDMETHODIMP MyDataObject::SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
{
if ( (NULL == pformatetc) || (NULL == pmedium) )
return E_INVALIDARG;
if ( pformatetc->tymed != pmedium->tymed )
return E_FAIL;
m_AcceptFormat = new FORMATETC;
m_StorageMedium = new STGMEDIUM;
ZeroMemory(m_AcceptFormat, sizeof(FORMATETC));
ZeroMemory(m_StorageMedium, sizeof(STGMEDIUM));
if ( TRUE == fRelease )
{
*m_StorageMedium = *pmedium;
}
else
{
CopyMedium(m_StorageMedium, pmedium, pformatetc);
}
return S_OK;
}
STDMETHODIMP MyDataObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc)
{
if(NULL == ppenumFormatEtc)
{
return E_INVALIDARG;
}
*ppenumFormatEtc = NULL;
HRESULT hr = E_NOTIMPL;
if (DATADIR_GET == dwDirection )
{
FORMATETC rgfmtetc[] =
{
{ CF_HDROP, NULL, DVASPECT_CONTENT, 0, TYMED_HGLOBAL },
};
hr = CreateEnumFormatEtc(ARRAYSIZE(rgfmtetc), rgfmtetc, ppenumFormatEtc);
}
return hr;
}
//Advises:OLE_E_ADVISENOTSUPPORTED
STDMETHODIMP MyDataObject::DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
{
UNREFERENCED_PARAMETER(pformatetc);
UNREFERENCED_PARAMETER(advf);
UNREFERENCED_PARAMETER(pAdvSink);
UNREFERENCED_PARAMETER(pdwConnection);
return E_NOTIMPL;
}
STDMETHODIMP MyDataObject::DUnadvise(DWORD dwConnection)
{
UNREFERENCED_PARAMETER(dwConnection);
return E_NOTIMPL;
}
STDMETHODIMP MyDataObject::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
{
UNREFERENCED_PARAMETER(ppenumAdvise);
return E_NOTIMPL;
}
//Advises:OLE_E_ADVISENOTSUPPORTED
HGLOBAL MyDataObject::DupGlobalMem(HGLOBAL hMem)
{
DWORD len = GlobalSize(hMem);
PVOID source = GlobalLock(hMem);
PVOID dest = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, len);
memcpy(dest, source, len);
GlobalUnlock(hMem);
return dest;
}
HRESULT MyDataObject::CopyMedium(STGMEDIUM* pMedDest, STGMEDIUM* pMedSrc, FORMATETC* pFmtSrc)
{
if ( (NULL == pMedDest) || (NULL ==pMedSrc) || (NULL == pFmtSrc) )
{
return E_INVALIDARG;
}
switch(pMedSrc->tymed)
{
case TYMED_HGLOBAL:
pMedDest->hGlobal = (HGLOBAL)OleDuplicateData(pMedSrc->hGlobal, pFmtSrc->cfFormat, NULL);
break;
case TYMED_GDI:
pMedDest->hBitmap = (HBITMAP)OleDuplicateData(pMedSrc->hBitmap, pFmtSrc->cfFormat, NULL);
break;
case TYMED_MFPICT:
pMedDest->hMetaFilePict = (HMETAFILEPICT)OleDuplicateData(pMedSrc->hMetaFilePict, pFmtSrc->cfFormat, NULL);
break;
case TYMED_ENHMF:
pMedDest->hEnhMetaFile = (HENHMETAFILE)OleDuplicateData(pMedSrc->hEnhMetaFile, pFmtSrc->cfFormat, NULL);
break;
case TYMED_FILE:
pMedSrc->lpszFileName = (LPOLESTR)OleDuplicateData(pMedSrc->lpszFileName, pFmtSrc->cfFormat, NULL);
break;
case TYMED_ISTREAM:
pMedDest->pstm = pMedSrc->pstm;
pMedSrc->pstm->AddRef();
break;
case TYMED_ISTORAGE:
pMedDest->pstg = pMedSrc->pstg;
pMedSrc->pstg->AddRef();
break;
case TYMED_NULL:
default:
break;
}
pMedDest->tymed = pMedSrc->tymed;
pMedDest->pUnkForRelease = NULL;
if(pMedSrc->pUnkForRelease != NULL)
{
pMedDest->pUnkForRelease = pMedSrc->pUnkForRelease;
pMedSrc->pUnkForRelease->AddRef();
}
return S_OK;
}
HRESULT MyDataObject::SetBlob(CLIPFORMAT cf, const void *pvBlob, UINT cbBlob)
{
void *pv = GlobalAlloc(GPTR, cbBlob);
HRESULT hr = pv ? S_OK : E_OUTOFMEMORY;
if ( SUCCEEDED(hr) )
{
CopyMemory(pv, pvBlob, cbBlob);
FORMATETC fmte = {cf, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
STGMEDIUM medium = {};
medium.tymed = TYMED_HGLOBAL;
medium.hGlobal = pv;
hr = this->SetData(&fmte, &medium, TRUE);
if (FAILED(hr))
{
GlobalFree(pv);
}
}
return hr;
}
HRESULT CreateEnumFormatEtc(UINT cfmt, FORMATETC *afmt, IEnumFORMATETC **ppEnumFormatEtc)
{
if (cfmt == 0 || afmt == 0 || ppEnumFormatEtc == 0)
return E_INVALIDARG;
*ppEnumFormatEtc = new MyEnumFormatEtc(afmt, cfmt);
return (*ppEnumFormatEtc) ? S_OK: E_OUTOFMEMORY;
}
void DeepCopyFormatEtc(FORMATETC *dest, FORMATETC *source)
{
// copy the source FORMATETC into dest
*dest = *source;
if(source->ptd)
{
// allocate memory for the DVTARGETDEVICE if necessary
dest->ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(sizeof(DVTARGETDEVICE));
// copy the contents of the source DVTARGETDEVICE into dest->ptd
*(dest->ptd) = *(source->ptd);
}
}
MyEnumFormatEtc::MyEnumFormatEtc(FORMATETC *pFormatEtc, ULONG nNumFormats)
:_iRefCount(1),_nIndex(0),_nNumFormats(nNumFormats)
{
_pFormatEtc = new FORMATETC[nNumFormats];
// make a new copy of each FORMATETC structure
for(ULONG i = 0; i < nNumFormats; i++)
{
DeepCopyFormatEtc (&_pFormatEtc[i], &pFormatEtc[i]);
}
}
MyEnumFormatEtc::~MyEnumFormatEtc()
{
// first free any DVTARGETDEVICE structures
for(ULONG i = 0; i < _nNumFormats; i++)
{
if(_pFormatEtc[i].ptd)
CoTaskMemFree(_pFormatEtc[i].ptd);
}
// now free the main array
delete[] _pFormatEtc;
}
HRESULT __stdcall MyEnumFormatEtc::Next(ULONG celt, FORMATETC *pFormatEtc, ULONG *pceltFetched)
{
ULONG copied = 0;
// copy the FORMATETC structures into the caller's buffer
while (_nIndex < _nNumFormats && copied < celt)
{
DeepCopyFormatEtc (&pFormatEtc [copied], &_pFormatEtc [_nIndex]);
copied++;
_nIndex++;
}
// store result
if(pceltFetched != 0)
*pceltFetched = copied;
// did we copy all that was requested?
return (copied == celt) ? S_OK : S_FALSE;
}
7.IDragDemo.h
#ifndef _DRAGDROP_H_
#define _DRAGDROP_H_
#include <windows.h>
#include <ole2.h>
#include <Shlobj.h>
#endif //_DRAGDROP_H_
Complete Code can be get here:https://github.com/cyfingm/cb_ole_dragdrop
OleIsCurrentClipboard() is returning S_FALSE because you are calling OleFlushClipboard() beforehand. Read the documentation:
OleFlushClipboard function
Carries out the clipboard shutdown sequence. It also releases the IDataObject pointer that was placed on the clipboard by the OleSetClipboard function.
...
OleFlushClipboard renders the data from a data object onto the clipboard and releases the IDataObject pointer to the data object.
...
Before calling OleFlushClipboard, you can easily determine if your data is still on the clipboard with a call to the OleIsCurrentClipboard function.
Basically, once you call OleFlushClipboard(), the clipboard no longer contains a pointer to your IDataObject. The CF_HDROP data gets copied directly onto the clipboard, and the IDataObject is removed.
Why are you involving the clipboard at all? You do not need to put the IDataObject on the clipboard in order to use DoDragDrop(), so stop doing that. You pass the IDataObject directly to DoDragDrop(), that is all you need to do.
There are other problems with this code as well.
This line is wrong:
strcpy((char*)(tDropFiles+sizeof(DROPFILES)), tFileName);
It should be this instead:
strcpy(((char*)tDropFiles)+sizeof(DROPFILES), tFileName);
Or this:
strcpy((char*)(tDropFiles+1), tFileName);
You are also not maintaining the IDataObject and IDropSource reference counts correctly. When you create those objects, their reference counts are 0. OleSetClipboard() will increment the IDataObject reference count, then OleFlushClipboard() will decrement it, freeing that object before DoDragDrop() is called. Label1EndDrag() needs to call AddRef() on both objects after creating them (it has a reference to them, afterall), and then call Release() when it is done using them.
pDropSource = new MyDropSource();
pDropSource->AddRef();
pDataObject = new MyDataObject((MyDropSource*)pDropSource);//(&fmtetc, &stgmed, 1);
pDataObject->AddRef();
...
pDropSource->Release();
pDataObject->Release();
Also, this will not work:
(MyDropSource*)pDropSource
You cannot create a MyDropSource instance, assign it to an IDropSource* pointer, and then type-cast it back to MyDropSource*. And besides, there is no good reason to have MyDataObject contain a pointer to MyDropSource (especially since it is not actually using it for anything, nor is it incrementing/decrementing the reference count), so you need to remove that altogether.
Lastly, your QueryInterface() implementations are not returning the correct output pointer address. It is not taking polymorphic vtables into account correctly. The implementation need to look more like this instead:
STDMETHODIMP MyDataObject::QueryInterface(REFIID riid, void **ppvObject)
{
if (!ppvObject)
return E_POINTER;
if (riid == IID_IDataObject)
*ppvObject = (IDataObject*)this;
else if (riid == IID_IUnknown)
*ppvObject = (IUnknown*)this;
else
{
*ppvObject = 0;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
I'm sure there are other flaws and leaks in this code, but I stopped reviewing after seeing these big flaws. It is not a very clean implementation in general.
Update: DROPEFFECT_NONE is defined as 0, so the statement
if((dwEffect & DROPEFFECT_NONE) == DROPEFFECT_NONE)
Will always evaluate as true, regardless of the value of dwEffect. Don't use the bitwise & operator to test for DROPEFFECT_NONE, use the == operator instead. Use & for all other values.
if(dwEffect == DROPEFFECT_NONE)
MessageBoxA(NULL, "Ole data not accepted!!", "DRAGDROP_S_DROP", 0);
else if((dwEffect & DROPEFFECT_MOVE) == DROPEFFECT_MOVE)
MessageBoxA(NULL, "Ole data moved!!", "DRAGDROP_S_DROP", 0);
else if((dwEffect & DROPEFFECT_COPY) == DROPEFFECT_COPY)
MessageBoxA(NULL, "Ole data copied!!", "DRAGDROP_S_DROP", 0);
...

JPEG streaming with live555

I want to stream JPEG images or motion-JPEG file through live 555. But the problem is that in live 555 implementation for Jpegs is not available. Anyone can help ??
You can find a implementation that was posted to the devel mailing list http://lists.live555.com/pipermail/live-devel/2012-February/014672.html.
The code and a sample is available but this modification was rejected by live555 maintainer.
First we need to implement an MJPEGVideoSource than can feed a JPEGVideoRTPSink.
#include "JPEGVideoSource.hh"
class MJPEGVideoSource : public JPEGVideoSource
{
public:
static MJPEGVideoSource* createNew (UsageEnvironment& env, FramedSource* source)
{
return new MJPEGVideoSource(env,source);
}
virtual void doGetNextFrame()
{
if (m_inputSource)
m_inputSource->getNextFrame(fTo, fMaxSize, afterGettingFrameSub, this, FramedSource::handleClosure, this);
}
virtual void doStopGettingFrames()
{
FramedSource::doStopGettingFrames();
if (m_inputSource)
m_inputSource->stopGettingFrames();
}
static void afterGettingFrameSub(void* clientData, unsigned frameSize,unsigned numTruncatedBytes,struct timeval presentationTime,unsigned durationInMicroseconds)
{
MJPEGVideoSource* source = (MJPEGVideoSource*)clientData;
source->afterGettingFrame(frameSize, numTruncatedBytes, presentationTime, durationInMicroseconds);
}
void afterGettingFrame(unsigned frameSize,unsigned numTruncatedBytes,struct timeval presentationTime,unsigned durationInMicroseconds)
{
int headerSize = 0;
bool headerOk = false;
fFrameSize = 0;
for (unsigned int i = 0; i < frameSize ; ++i)
{
// SOF
if ( (i+8) < frameSize && fTo[i] == 0xFF && fTo[i+1] == 0xC0 )
{
m_height = (fTo[i+5]<<5)|(fTo[i+6]>>3);
m_width = (fTo[i+7]<<5)|(fTo[i+8]>>3);
}
// DQT
if ( (i+5+64) < frameSize && fTo[i] == 0xFF && fTo[i+1] == 0xDB)
{
if (fTo[i+4] ==0)
{
memcpy(m_qTable, fTo + i + 5, 64);
m_qTable0Init = true;
}
else if (fTo[i+4] ==1)
{
memcpy(m_qTable + 64, fTo + i + 5, 64);
m_qTable1Init = true;
}
}
// End of header
if ( (i+1) < frameSize && fTo[i] == 0x3F && fTo[i+1] == 0x00 )
{
headerOk = true;
headerSize = i+2;
break;
}
}
if (headerOk)
{
fFrameSize = frameSize - headerSize;
memmove( fTo, fTo + headerSize, fFrameSize );
}
fNumTruncatedBytes = numTruncatedBytes;
fPresentationTime = presentationTime;
fDurationInMicroseconds = durationInMicroseconds;
afterGetting(this);
}
virtual u_int8_t type() { return 1; };
virtual u_int8_t qFactor() { return 128; };
virtual u_int8_t width() { return m_width; };
virtual u_int8_t height() { return m_height; };
u_int8_t const* quantizationTables( u_int8_t& precision, u_int16_t& length )
{
length = 0;
precision = 0;
if ( m_qTable0Init && m_qTable1Init )
{
precision = 8;
length = sizeof(m_qTable);
}
return m_qTable;
}
protected:
MJPEGVideoSource(UsageEnvironment& env, FramedSource* source) : JPEGVideoSource(env),
m_inputSource(source),
m_width(0),
m_height(0),
m_qTable0Init(false),
m_qTable1Init(false)
{
memset(&m_qTable,0,sizeof(m_qTable));
}
virtual ~MJPEGVideoSource()
{
Medium::close(m_inputSource);
}
protected:
FramedSource* m_inputSource;
u_int8_t m_width;
u_int8_t m_height;
u_int8_t m_qTable[128];
bool m_qTable0Init;
bool m_qTable1Init;
};
Next we can use it as a video source in order to build a simple RTSP server:
#include "liveMedia.hh"
#include "BasicUsageEnvironment.hh"
#include "GroupsockHelper.hh"
#include "MJPEGVideoSource.hh"
char const* inputFileName = "test.mjpeg";
int main(int argc, char** argv) {
// Begin by setting up our usage environment:
TaskScheduler* scheduler = BasicTaskScheduler::createNew();
UsageEnvironment* env = BasicUsageEnvironment::createNew(*scheduler);
// Create 'groupsocks' for RTP and RTCP:
struct in_addr destinationAddress;
destinationAddress.s_addr = chooseRandomIPv4SSMAddress(*env);
const unsigned short rtpPortNum = 18888;
const unsigned short rtcpPortNum = rtpPortNum+1;
const unsigned char ttl = 255;
const Port rtpPort(rtpPortNum);
const Port rtcpPort(rtcpPortNum);
Groupsock rtpGroupsock(*env, destinationAddress, rtpPort, ttl);
rtpGroupsock.multicastSendOnly(); // we're a SSM source
Groupsock rtcpGroupsock(*env, destinationAddress, rtcpPort, ttl);
rtcpGroupsock.multicastSendOnly(); // we're a SSM source
// Create a 'JPEG Video RTP' sink from the RTP 'groupsock':
RTPSink* videoSink = JPEGVideoRTPSink::createNew(*env, &rtpGroupsock);
// Create (and start) a 'RTCP instance' for this RTP sink:
const unsigned estimatedSessionBandwidth = 5000; // in kbps; for RTCP b/w share
const unsigned maxCNAMElen = 100;
unsigned char CNAME[maxCNAMElen+1];
gethostname((char*)CNAME, maxCNAMElen);
CNAME[maxCNAMElen] = '\0'; // just in case
RTCPInstance* rtcp = RTCPInstance::createNew(*env, &rtcpGroupsock,
estimatedSessionBandwidth, CNAME,
videoSink, NULL /* we're a server */,
True /* we're a SSM source */);
// Note: This starts RTCP running automatically
RTSPServer* rtspServer = RTSPServer::createNew(*env, 8554);
if (rtspServer == NULL) {
*env << "Failed to create RTSP server: " << env->getResultMsg() << "\n";
exit(1);
}
ServerMediaSession* sms = ServerMediaSession::createNew(*env, "testStream", inputFileName,"Session streamed by \"testMJPEGVideoStreamer\"",
True /*SSM*/);
sms->addSubsession(PassiveServerMediaSubsession::createNew(*videoSink, rtcp));
rtspServer->addServerMediaSession(sms);
char* url = rtspServer->rtspURL(sms);
*env << "Play this stream using the URL \"" << url << "\"\n";
delete[] url;
// Start the streaming:
*env << "Beginning streaming...\n";
// Open the input file as a 'byte-stream file source':
ByteStreamFileSource* fileSource = ByteStreamFileSource::createNew(*env, inputFileName);
if (fileSource == NULL) {
*env << "Unable to open file \"" << inputFileName
<< "\" as a byte-stream file source\n";
exit(1);
}
// Create the MJPEG video source:
MJPEGVideoSource* videoSource = MJPEGVideoSource::createNew(*env, fileSource);
// Finally, start playing:
*env << "Beginning to read from file...\n";
videoSink->startPlaying(*videoSource, NULL, NULL);
env->taskScheduler().doEventLoop();
return 0;
}
Hope you have done it but if not-
see this Jpeg Streaming using live555
This is doing the same thing as you have asked to stream the images/Jpegs.
For MJpegs you'll have to do the same process.

Are there simple examples of how to parse a simple JSON file using the C-based YAJL library?

I know there is an Objective-C wrapper around YAJL, but this is a really fat thing which blows up the whole JASON parser to a ridiculous huge amount of 21 files, many of them with tiny scroll bars.
So to keep my app binary small I'd like to stick with the C-version of that parser. But I'm having a hard time finding any useful documentation for this rather than the wrapper.
Maybe someone who used the C-base can point out such a tutorial or documentation?
The documentation with C examples can be found here: http://lloyd.github.com/yajl/
The github repository with examples can be found here : https://github.com/lloyd/yajl
Here is a C example that reformats JSON from stdin:
#include <yajl/yajl_parse.h>
#include <yajl/yajl_gen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int reformat_null(void * ctx)
{
yajl_gen g = (yajl_gen) ctx;
return yajl_gen_status_ok == yajl_gen_null(g);
}
static int reformat_boolean(void * ctx, int boolean)
{
yajl_gen g = (yajl_gen) ctx;
return yajl_gen_status_ok == yajl_gen_bool(g, boolean);
}
static int reformat_number(void * ctx, const char * s, size_t l)
{
yajl_gen g = (yajl_gen) ctx;
return yajl_gen_status_ok == yajl_gen_number(g, s, l);
}
static int reformat_string(void * ctx, const unsigned char * stringVal,
size_t stringLen)
{
yajl_gen g = (yajl_gen) ctx;
return yajl_gen_status_ok == yajl_gen_string(g, stringVal, stringLen);
}
static int reformat_map_key(void * ctx, const unsigned char * stringVal,
size_t stringLen)
{
yajl_gen g = (yajl_gen) ctx;
return yajl_gen_status_ok == yajl_gen_string(g, stringVal, stringLen);
}
static int reformat_start_map(void * ctx)
{
yajl_gen g = (yajl_gen) ctx;
return yajl_gen_status_ok == yajl_gen_map_open(g);
}
static int reformat_end_map(void * ctx)
{
yajl_gen g = (yajl_gen) ctx;
return yajl_gen_status_ok == yajl_gen_map_close(g);
}
static int reformat_start_array(void * ctx)
{
yajl_gen g = (yajl_gen) ctx;
return yajl_gen_status_ok == yajl_gen_array_open(g);
}
static int reformat_end_array(void * ctx)
{
yajl_gen g = (yajl_gen) ctx;
return yajl_gen_status_ok == yajl_gen_array_close(g);
}
static yajl_callbacks callbacks = {
reformat_null,
reformat_boolean,
NULL,
NULL,
reformat_number,
reformat_string,
reformat_start_map,
reformat_map_key,
reformat_end_map,
reformat_start_array,
reformat_end_array
};
static void
usage(const char * progname)
{
fprintf(stderr, "%s: reformat json from stdin\n"
"usage: json_reformat [options]\n"
" -m minimize json rather than beautify (default)\n"
" -u allow invalid UTF8 inside strings during parsing\n",
progname);
exit(1);
}
int
main(int argc, char ** argv)
{
yajl_handle hand;
static unsigned char fileData[65536];
/* generator config */
yajl_gen g;
yajl_status stat;
size_t rd;
int retval = 0;
int a = 1;
g = yajl_gen_alloc(NULL);
yajl_gen_config(g, yajl_gen_beautify, 1);
yajl_gen_config(g, yajl_gen_validate_utf8, 1);
/* ok. open file. let's read and parse */
hand = yajl_alloc(&callbacks, NULL, (void *) g);
/* and let's allow comments by default */
yajl_config(hand, yajl_allow_comments, 1);
/* check arguments.*/
while ((a < argc) && (argv[a][0] == '-') && (strlen(argv[a]) > 1)) {
unsigned int i;
for ( i=1; i < strlen(argv[a]); i++) {
switch (argv[a][i]) {
case 'm':
yajl_gen_config(g, yajl_gen_beautify, 0);
break;
case 'u':
yajl_config(hand, yajl_dont_validate_strings, 1);
break;
default:
fprintf(stderr, "unrecognized option: '%c'\n\n",
argv[a][i]);
usage(argv[0]);
}
}
++a;
}
if (a < argc) {
usage(argv[0]);
}
for (;;) {
rd = fread((void *) fileData, 1, sizeof(fileData) - 1, stdin);
if (rd == 0) {
if (!feof(stdin)) {
fprintf(stderr, "error on file read.\n");
retval = 1;
}
break;
}
fileData[rd] = 0;
stat = yajl_parse(hand, fileData, rd);
if (stat != yajl_status_ok) break;
{
const unsigned char * buf;
size_t len;
yajl_gen_get_buf(g, &buf, &len);
fwrite(buf, 1, len, stdout);
yajl_gen_clear(g);
}
}
stat = yajl_complete_parse(hand);
if (stat != yajl_status_ok) {
unsigned char * str = yajl_get_error(hand, 1, fileData, rd);
fprintf(stderr, "%s", (const char *) str);
yajl_free_error(hand, str);
retval = 1;
}
yajl_gen_free(g);
yajl_free(hand);
return retval;
}

class has no member problem (code works find in VS, but failed in Ubuntu)

all
I got a piece of code about sparse matrix, it works fine in VISUAL STUDIO 2008, but when I want to port it to ubuntu environment, the compiler report the following errors:
../include/spmatrix.h(123): error:
class template "numc::CSRMatrix"
has no member "resize"
../include/spmatrix.h(170): error:
expected a ";"
../include/spmatrix.h(171): error:
identifier "it" is undefined
../include/spmatrix.h(176): error:
expected a ";"
../include/spmatrix.h(178): error:
identifier "it" is undefined
../include/spmatrix.h(183): error:
identifier "size" is undefined
../include/spmatrix.h(185): error:
expected a ";"
../include/spmatrix.h(185): error:
identifier "it" is undefined
.> ./include/spmatrix.h(186): error:
expected a ";"
../include/spmatrix.h(187): error:
identifier "cit" is undefined
../include/spmatrix.h(205): error:
expected a ";"
../include/spmatrix.h(205): error:
identifier "it" is undefined
../include/spmatrix.h(218): error:
expected a ";"
../include/spmatrix.h(218): error:
identifier "it" is undefined
../include/spmatrix.h(222): error:
expected a ";"
../include/spmatrix.h(223): error:
identifier "f" is undefined
../include/spmatrix.h(224): error:
identifier "make_pair" is undefined
../include/spmatrix.h(224): error:
type name is not allowed
../include/spmatrix.h(224): error:
type name is not allowed
../include/spmatrix.h(245): error:
identifier "RowType" is undefined
../include/spmatrix.h(246): error:
name followed by "::" must be a class
or namespace name
../include/spmatrix.h(246): error:
expected a ";"
../include/spmatrix.h(246): error:
identifier "it" is undefined
../include/spmatrix.h(269): error:
identifier "RowType" is undefined
../include/spmatrix.h(270): error:
name followed by "::" must be a class
or namespace name
../include/spmatrix.h(270): error:
expected a ";"
../include/spmatrix.h(271): error:
identifier "it" is undefined
../include/spmatrix.h(276): error:
identifier "RowType" is undefined
../include/spmatrix.h(276): error:
identifier "crow" is undefined
../include/spmatrix.h(277): error:
name followed by "::" must be a class
or namespace name
../include/spmatrix.h(277): error:
expected a ";"
../include/spmatrix.h(279): error:
identifier "it" is undefined
../include/spmatrix.h(311): error:
expected a ";"
../include/spmatrix.h(311): error:
identifier "it" is undefined
../include/spmatrix.h(350): error:
expected a ";"
../include/spmatrix.h(350): error:
identifier "it" is undefined
../include/spmatrix.h(423): error:
expected a ";"
../include/spmatrix.h(424): error:
identifier "it" is undefined
../include/spmatrix.h(484): error:
expected a ";"
../include/spmatrix.h(485): error:
identifier "it" is undefined
../include/spmatrix.h(518): error:
expected a ";"
../include/spmatrix.h(520): error:
identifier "it" is undefined
I try to figure out where the problem is, but failed. Hope you can give me some hint where the problem is. Thanks in advance for your help!
Below is the code of this sparse matrix, it is just a header file:
#pragma warning(disable: 4786)
#ifndef NUMC_CSRMATRIX_H
#define NUMC_CSRMATRIX_H
#include <cmath>
#include <map>
#include <vector>
#include <limits>
#include <algorithm>
#ifndef _NUMC_BEGIN
#define _NUMC_BEGIN namespace numc {
#define _NUMC_END }
#endif
_NUMC_BEGIN
using std::vector;
using std::map;
using std::swap;
using std::lower_bound;
template<typename R> class CSRMatrix;
template<typename R> struct RowMat;
template<typename R> void CreateCSRMatrixFromRowMap(CSRMatrix<R>&, const RowMat<R>&);
t emplate<typename R> void CSRMatrixTranspose (const CSRMatrix<R>&, CSRMatrix<R>&);
template<typename R> bool Mul2MatricesSymmResult (const CSRMatrix<R>&, const CSRMatrix<R>&, RowMat<R>&);
template<typename R> bool Mul2MatricesSymmResult (const CSRMatrix<R>&, const CSRMatrix<R>&, CSRMatrix<R>&);
template<typename R> bool Mul2Matrices (const CSRMatrix<R>&, const CSRMatrix<R>&, RowMat<R>&);
template<typename R> bool Mul2Matrices (const CSRMatrix<R>&, const CSRMatrix<R>&, CSRMatrix<R>&);
template<typename R>
class CSRMatrix
{
public:
enum MatType{ RealStrucSymm=1, RealSymmPosDef=2, RealSymmIndef=-2,
CompStrucSymm=3, CompHermPosDef=4, CompHermIndef=-4,
CompSymm=6, RealUnSymm=11, CompUnSymm=13};
std::vector<R> mAv;
std::vector<int> mAi, mAj;
CSRMatrix():mNRow(0),mNCol(0),mMtype(RealUnSymm) {};
CSRMatrix(const RowMat<R> &rm):mMtype(RealUnSymm) { CreateCSRMatrixFromRowMap(*this, rm); }
MatType mMtype;
#if ( defined(_MSC_VER)&&(_MSC_VER>1300) )
//template<typename T> class CSRMatrix;
#define FFM <> // FFM FRIEND_FUNCTION_MAGIC
#else
#define FFM
#endif
friend void CreateCSRMatrixFromRowMap FFM(CSRMatrix<R>&, const RowMat<R>&);
friend void CSRMatrixTranspose FFM(const CSRMatrix<R>&, CSRMatrix<R>&);
friend bool Mul2MatricesSymmResult FFM(const CSRMatrix<R>&, const CSRMatrix<R>&, RowMat<R>&);
friend bool Mul2MatricesSymmResult FFM(const CSRMatrix<R>&, const CSRMatrix<R>&, CSRMatrix<R>&);
friend bool Mul2Matrices FFM(const CSRMatrix<R>&, const CSRMatrix<R>&, RowMat<R>&);
friend bool Mul2Matrices FFM(const CSRMatrix<R>&, const CSRMatrix<R>&, CSRMatrix<R>&);
#undef FFM
private:
int mNRow, mNCol;
public:
inline int nRow() const { return mNRow; }
inline int nCol() const { return mNCol; }
inline int empty() const { return (0==nRow() || 0==nCol()) ;}
inline bool onebase() const { return (!mAi.empty()) && (mAi[0]==1); } //default: zerobase, including empty matrix!
inline MatType mtype() const { return mMtype; }
inline bool issymm() const
{ return (RealSymmIndef==mMtype || RealSymmPosDef==mMtype || CompSymm==mMtype); }
inline void clear()
{ mNRow = 0; mNCol = 0; mMtype = RealUnSymm; mAv.clear(); mAi.clear(); mAj.clear(); }
R getElementV(int x, int y) const{
double *p = const_cast<CSRMatrix*>(this)->getElementP(x, y);
return (NULL==p)?0:*p;
}
R* getElementP(int x, int y) {
if (x<0||y<0) return NULL;
if ( issymm() && x>y) swap(x, y);
const int off = onebase();
std::vector<int>::const_iterator it = lower_bound(mAj.begin()+mAi[x]-off, mAj.begin()+(mAi[x+1]-off), y+off);
if (it==mAj.begin()+(mAi[x+1]-off) || *it!=(y+off) ) return NULL;
return &mAv.front() + ( it-mAj.begin() );
}
void MultiVect(R* in, R *out) const;
bool ChangeBase(bool oneBase) {
if( onebase() == oneBase ) return true;
int ii;
if (oneBase) {
if (mAi[0] != 0){
fprintf(stderr, "error matrix!");
return false;
}
for (ii=0; ii<mAi.back(); ii++) mAj[ii]++;
for (ii=0; ii<mNRow+1; ii++) mAi[ii]++;
}
else {
if (mAi[0] != 1){
fprintf(stderr, "error matrix!");
return false;
}
for (ii=0; ii<mAi.back()-1; ii++) mAj[ii]--;
for (ii=0; ii<mNRow+1; ii++) mAi[ii]--;
}
return true;
}
void GetSubMat(const std::vector<int> &xi, const std::vector<int> &yi, CSRMatrix& mat){
mat.resize( yi.size() );
for(int j=0; j<yi.size(); j++){
for(int i=0; i<xi.size(); i++){
}
}
}
void print(FILE *f=stdout){
fprintf(f, "The matrix:\n");
for(int i=0; i<nRow(); i++){
fprintf(f, "%2d#:", i);
for(int j=0; j<nCol(); j++) {
fprintf(f, "\t%.3e", getElementV(i, j) );
}
fprintf(f, "\n");
}
}
};
template<typename R>
struct RowMat:public vector<map<int, R> >
{
typedef map<int, R> RowType;
typedef vector<RowType> BaseType;
int mNCol;
RowMat(int nrow=0, int ncol=0):BaseType(nrow),mNCol(ncol) { }
~RowMat() { }
RowMat(const CSRMatrix<R> &mat)
{
resize(mat.nCol(), mat.nRow());
int off = mat.onebase()?1:0;
for(unsigned int i=0; i+1<mat.mAi.size(); i++){
for(int j=mat.mAi[i]; j<mat.mAi[i+1]; j++){
(*this)(i, mat.mAj[j-off]-off) = mat.mAv[ j-off ];
}
}
}
virtual bool symmetric() const {return false;}
virtual inline R operator()(int i, int j) const{
const RowType &crow = (*this)[i];
RowType::const_iterator it = crow.find(j);
return ( it==crow.end() )?0:it->second;
}
virtual inline R& operator()(int i, int j){
RowType &crow = (*this)[i];
RowType::iterator it = crow.find(j);
return ( it==crow.end() )?crow.insert( std::pair<int,R>(j, 0) ).first->second:it->second;
}
int clearZero() {
int nZero;
for (size_t i=0; i<size(); i++) {
RowType &r = (*this)[i];
for (RowType::const_iterator it=r.begin(); it!=r.end(); ) {
RowType::const_iterator cit = it++;
if(fabs(cit->second) < std::numeric_limits<R>::epsilon()){
r.erase(cit);
++nZero;
}
}
}
return nZero;
}
inline void resize(int nrow, int ncol=0) { BaseType::resize(nrow); mNCol = ncol>0?ncol:mNCol; }
inline int nRow() const { return BaseType::size(); }
inline int nCol() const { return mNCol; }
int operator+=(const RowMat<R>& r) { return add(r, 1); }
void operator *= (const double v) {
for(int i=0; i<nRow(); i++){
map<int, R>& crow = (*this)[i];
for(map<int,R>::iterator it=crow.begin(); it!=crow.end(); ++it){
it->second *= v;
}
}
}
int add(const RowMat<R>& r, R k){
const int h = nRow();
if( r.nRow() != h ) return -1;
for(int i=0; i<h; i++){
const map<int, R>& rrow = r[i];
map<int, R>& lrow = (*this)[i];
for(RowType::const_iterator it=rrow.begin(); it!=rrow.end(); ++it){
int col = it->first;
R val = it->second * k;
map<int,R>::iterator f = lrow.find(col);
if( f != lrow.end() ) f->second += val;
lrow.insert( make_pair<int, R>(col, val) );
}
}
return 0;
}
};
template<typename R>
struct RowMatSym : public RowMat<R>
{
typedef RowMat<R> Base;
RowMatSym(int nrow=0, int ncol=0):Base(nrow, ncol) {}
~RowMatSym() { }
RowMatSym(const RowMat<R> &rm){
resize(rm.nCol(), rm.nRow());
for(unsigned int i=0; i<rm.nRow(); i++){
const RowType &crow = rm[i];
for(RowType::const_iterator it=crow.begin(); it!=crow.end(); ++it){
(*this)(i, it->first) = it->second;
}
}
}
RowMatSym(const CSRMatrix<R> &mat)
{
resize(mat.nCol(), mat.nRow());
int off = mat.onebase()?1:0;
for(unsigned int i=0; i+1<mat.mAi.size(); i++){
for(int j=mat.mAi[i]; j<mat.mAi[i+1]; j++){
const int k = mat.mAj[j-off]-off;
(*this)(i, k) = mat.mAv[ j-off ];
}
}
}
virtual bool symmetric() const {return true;}
inline R operator()(int i, int j) const{
if(i>j) std::swap(i, j);
const RowType &crow = (*this)[i];
RowType::const_iterator it = crow.find(j);
return ( it==crow.end() )?0:it->second;
}
inline R& operator()(int i, int j){
if(i>j) std::swap(i, j);
RowType &crow = (*this)[i];
RowType::iterator it = crow.find(j);
return ( it==crow.end() )?crow.insert( std::pair<int,R>(j, 0) ).first->second
:it->second;
}
};
//////////////////////////////////////////////////////////////////////////
/// Get SubMatrix from rowmap
//////////////////////////////////////////////////////////////////////////
template <typename R>
void GetSubRowMap(const RowMat<R>& src,
const std::vector<int> &xi, const std::vector<int> &yi,
RowMat<R>& dst)
{
assert( xi.size()>0 && yi.size()>0 );
assert( yi.back() < (int)src.size() );
if( xi.empty() || yi.empty() || yi.back() >= (int)src.size() ){
fprintf(stderr, "\nerror matrix!");
return;
}
typedef std::map<int, R> row;
dst.resize( yi.size() );
for(unsigned int j=0; j<yi.size(); j++){
const row &srow = src[ yi[j] ];
row &drow = dst[j];
const int* pxi = &xi.front();
for(row::const_iterator it=srow.begin(); it!=srow.end(); ++it ){
pxi = std::lower_bound(pxi, &xi.back(), it->first);
if(*pxi != it->first){ // done
continue;
}
int col = pxi - &xi.front();
drow[col] = it->second;
}
}
}
//////////////////////////////////////////////////////////////////////////
/// Create CSR matrix from vector of rowmap
//////////////////////////////////////////////////////////////////////////
template <typename R>
void CreateCSRMatrixFromRowMap(CSRMatrix<R> &matC, const RowMat<R>& rowC)
{
if(rowC.mNCol <= 0){
fprintf(stderr, "\nnumber of column not specified in the RowMat, exit!");
return;
}
matC.clear();
matC.mNRow = rowC.nRow();
matC.mNCol = rowC.nCol();
matC.mAi.reserve(matC.nRow()+1);
int i,nnz=0;
for (i=0; i<matC.nRow(); i++) {
nnz += rowC[i].size();
}
matC.mAj.reserve(nnz);
matC.mAv.reserve(nnz);
// copy rows into matC
matC.mAi.push_back(0);
for (i=0; i<matC.nRow(); i++) {
matC.mAi.push_back(matC.mAi.back());
for (std::map<int, R>::const_iterator it=rowC[i].begin(); it!=rowC[i].end(); it++) {
matC.mAi.back()++;
matC.mAj.push_back(it->first);
matC.mAv.push_back(it->second);
}
}
}
//////////////////////////////////////////////////////////////////////////
/// Computes the transpose of a matrix.
template <typename R>
void CSRMatrixTranspose(const CSRMatrix<R> &matA, CSRMatrix<R> &matAT)
{
if (matA.issymm()) { // symmetric - just copy the matrix
matAT = matA;
return;
}
matAT.mNRow = matA.nCol();
matAT.mNCol = matA.nRow();
matAT.mMtype = matA.mMtype;
// non-symmetric matrix -> need to build data structure.
// we'll go over the columns and build the rows
int off = matA.onebase()?1:0;
RowMat<R> rowC(matA.nCol(), matA.nRow());
for (int i=0; i<matA.nRow(); i++) {
for (int j=matA.mAi[i]; j<matA.mAi[i+1]; j++) {
rowC[matA.mAj[j-off]-off][i] = matA.mAv[j-off];
}
}
CreateCSRMatrixFromRowMap(matAT, rowC);
}
//////////////////////////////////////////////////////////////////////////
// multiplication of sparse matrix
// Assuming nothing about the result (the result is not stored symmetric)
//////////////////////////////////////////////////////////////////////////
template <typename R>
bool Mul2Matrices(const CSRMatrix<R> &matA, const CSRMatrix<R> &matB,
RowMat<R> &rowsC)
{
if(matA.onebase() || matB.onebase() ){
fprintf(stderr, "\nmatrix saved in 1-based format, pleased converted it to 0-based and try again!");
return false;
}
// Compatibility of dimensions
if (matA.nCol() != matB.nRow())
return false;
// (m x n)*(n x k) = (m x k)
const int m=matA.nRow();
const int n=matA.nCol();
const int k=matB.nCol();
rowsC = RowMat<R>(m, k); // clean all coefficients
R aiv, valB;
int colInd, colB;
for (int i=0; i<m; ++i) { // creating row i of C
std::map<int, R> &mapRow2Val = rowsC[i];
for (int iAi = matA.mAi[i]; iAi < matA.mAi[i+1]; ++iAi) { // travel on ai
colInd = matA.mAj[iAi];
aiv = matA.mAv[iAi];
// make aiv*b_{rowInd} and insert into mapRow2Val
for (int iB=matB.mAi[colInd]; iB<matB.mAi[colInd+1]; ++iB) {
colB=matB.mAj[iB];
valB=matB.mAv[iB];
// insert valA*aiv into map
std::map<int, R>::iterator it = mapRow2Val.find(colB);
if (it == mapRow2Val.end()) { // first time
mapRow2Val[colB] = valB*aiv;
}
else {
it->second = it->second + valB*aiv;
}
}
}
}// now column i is created
return true;
}
template <typename R>
bool Mul2Matrices(const CSRMatrix<R> &matA, const CSRMatrix<R> &matB, CSRMatrix<R> &matC)
{
RowMat<R> rowsC;
if( !Mul2Matrices(matA, matB, rowsC) ) return false;
const int k=matB.mNCol;
rowsC.mNCol = k;
CreateCSRMatrixFromRowMap(matC, rowsC); // modified by jianwei hu # 16/09/07
return true;
}
//////////////////////////////////////////////////////////////////////////
// multiplication of sparse matrix
// The result is symmetric
//////////////////////////////////////////////////////////////////////////
template <typename R>
bool Mul2MatricesSymmResult(const CSRMatrix<R> &matA, const CSRMatrix<R> &matB,
RowMat<R> &rowsC)
{
if(matA.onebase() || matB.onebase()){
fprintf(stderr, "\nmatrix saved in 1-based format, pleased converted it to 0-based and try again!");
return false;
}
// Compatibility of dimensions
if(matA.nCol() != matB.nRow() || matA.nRow() != matB.nCol()) return false;
// (m x n)*(n x m) = (m x m)
const int m=matA.nRow();
const int n=matA.nCol();
rowsC = RowMat<R>(m, m); // clean all coefficients
R aiv, valB;
int colInd, colB;
for(int i=0; i<m; ++i) { // creating row i of C
std::map<int, R> &mapRow2Val = rowsC[i];
for (int iAi = matA.mAi[i]; iAi < matA.mAi[i+1]; ++iAi) { // travel on ai
colInd = matA.mAj[iAi];
aiv = matA.mAv[iAi];
// make aiv*b_{colInd} and insert into mapRow2Val
for (int iB=matB.mAi[colInd]; iB<matB.mAi[colInd+1]; ++iB) {
colB=matB.mAj[iB];
if (colB >= i) {
valB=matB.mAv[iB];
// insert valA*aiv into map
std::map<int, R>::iterator it = mapRow2Val.find(colB);
if (it == mapRow2Val.end()) { // first time
mapRow2Val[colB] = valB*aiv;
}
else {
it->second = it->second + valB*aiv;
}
}
}
}
}// now column i is created
return true;
}
template <typename R>
bool Mul2MatricesSymmResult(const CSRMatrix<R> &matA, const CSRMatrix<R> &matB, CSRMatrix<R> &matC)
{
RowMat<R> rowsC;
if( !Mul2MatricesSymmResult(matA, matB, rowsC) ) return false;
rowsC.mNCol = matA.nCol();
CreateCSRMatrixFromRowMap(matC, rowsC);
matC.mMtype = CSRMatrix<R>::RealSymmIndef;
return true;
}
template<typename R>
void DebugShowRowMatrix(const std::vector<std::map<int,R> > &rowA)
{
printf("\n");
for(unsigned int i=0; i<rowA.size(); i++){
printf("\n%3d#", i);
std::map<int,R>::const_iterator it=rowA[i].begin();
int j=0;
for(; it!=rowA[i].end(); ++it){
for(int k=j; k<it->first; k++){
printf("\t%3.2f", 0);
}
j=it->first+1;
printf("\t%3.2f", it->second);
}
}
}
typedef CSRMatrix<float> CSRMatrixf;
typedef CSRMatrix<double> CSRMatrixd;
_NUMC_END
#endif // NUMC_CSRMATRIX_H
Line 123: the CSRMatrix::resize method is undefined, and since CSRMatrix has no base class, it's not inherited.
Line 171: Using a typedef's nested type, like RowType::const_iterator, is a Visual Studio extension, it may not work in other compilers. You should replace these and similar usages with other typedefs, like so:
typedef typename map<int,R>::const_iterator RowTypeConstIterator;
UPDATE: The typename keyword is required (just learned it!)