How to overlay a picture over a video stream with Gstreamer in C? - overlay

I want to overlay a ".png" picture over a stream coming from an IP Camera using Gstreamer.
A working pipeline for my hardware is:
gst-launch-1.0
rtspsrc location=rtsp://user:pass#IP:port/channel latency=400 ! rtph264depay !
vpudec use-vpu-memory=false ! imxvideoconvert_ipu
! video/x-raw,format=I420 ! gdkpixbufoverlay
location=/home/user/folder/image.png offset-x=100 offset-y=100 ! overlaysink
The problem comes when I try to translate this pipeline in C.
The code I wrote for this pipeline runs, but there is no video playback on the display. The player stuck itself before setting the pipeline on "playing" state.
Here, there is a simple version of my C implementation:
#include <gst/gst.h>
#include <glib.h>
#include <iostream>
typedef struct _CustomData {
GstElement *source;
GstElement *rtp;
GstElement *sink;
GstElement *vpudec;
GstElement *converter, *gdkpixbufoverlay, *capsfilter ;
GstBus *bus;
GstElement *pipeline;
GMainLoop *loop;
} CustomData;
static gboolean bus_call (GstBus *bus,
GstMessage *msg,
gpointer data)
{
GMainLoop *loop = (GMainLoop *) data;
switch (GST_MESSAGE_TYPE (msg)) {
case GST_MESSAGE_EOS:{
g_print ("End of stream\n");
g_main_loop_quit (loop);
break;
}
case GST_MESSAGE_ERROR: {
gchar *debug;
GError *error;
gst_message_parse_error (msg, &error, &debug);
g_free (debug);
g_printerr ("Error: %s\n", error->message);
g_error_free (error);
g_main_loop_quit (loop);
break;
}
default:
break;
}
return TRUE;
}
static void pad_added_handler (GstElement *src, GstPad *new_pad, CustomData *data) {
GstPad *sink_pad = gst_element_get_static_pad (data->rtp, "sink");
GstPadLinkReturn ret;
GstCaps *new_pad_caps = NULL;
GstStructure *new_pad_struct = NULL;
const gchar *new_pad_type = NULL;
if (gst_pad_is_linked (sink_pad)) {
goto exit;
}
new_pad_caps = gst_pad_query_caps (new_pad, NULL);
new_pad_struct = gst_caps_get_structure (new_pad_caps, 0);
new_pad_type = gst_structure_get_name (new_pad_struct);
if (!g_str_has_prefix (new_pad_type, "application/x-rtp")) {
g_print (" It has type '%s' which is not x-rtp . Ignoring.\n",
new_pad_type);
goto exit;
}
ret = gst_pad_link (new_pad, sink_pad);
if (GST_PAD_LINK_FAILED (ret)) {
g_print(" Type is '%s' but link failed.\n", new_pad_type);
} else {
g_print (" Link succeeded (type '%s').\n", new_pad_type);
}
exit:
if (new_pad_caps != NULL)
gst_caps_unref (new_pad_caps);
gst_object_unref (sink_pad);
}
int main (int argc, char *argv[]){
CustomData data;
gst_init (NULL, NULL);
data.loop = g_main_loop_new (NULL, FALSE);
// Create gstreamer elements
data.pipeline = gst_pipeline_new ("player");
data.source = gst_element_factory_make ("rtspsrc", "source");
data.rtp = gst_element_factory_make ("rtph264depay","rtp");
data.vpudec = gst_element_factory_make ("vpudec","vpudec");
data.converter = gst_element_factory_make
("imxcompositor_ipu","converter");
data.capsfilter = gst_element_factory_make ("capsfilter", "video-
rate");
data.gdkpixbufoverlay = gst_element_factory_make
("gdkpixbufoverlay","overlaytool");
data.sink = gst_element_factory_make ("overlaysink",
"videoSink");
if (!data.pipeline || !data.source || !data.rtp || !data.vpudec ||
!data.converter || !data.capsfilter || !data.gdkpixbufoverlay || !data.sink)
{
g_printerr ("One element could not be created. Exiting.\n");
return -1;
}
g_object_set (data.source, "location","rtsp://user:pass#IP:port/channel",
NULL);
g_object_set (data.source,"latency", 400 , NULL);
g_object_set (data.vpudec, "use-vpu-memory", false, NULL);
g_object_set (data.gdkpixbufoverlay,
"location","/home/user/folder/image.png", NULL);
g_object_set (data.gdkpixbufoverlay, "offset-x", 100 , NULL);
g_object_set (data.gdkpixbufoverlay, "offset-y", 100 , NULL);
GstCaps *capsFormat = gst_caps_from_string ("video/x-raw,format=I420");
g_object_set ( data.capsfilter, "caps", capsFormat, NULL);
gst_caps_unref(capsFormat);
//add all elements into the pipeline
gst_bin_add_many (GST_BIN (data.pipeline),
data.source,
data.rtp,
data.vpudec,
data.converter,
data.capsfilter,
data.gdkpixbufoverlay,
data.sink,
NULL);
// link all elements
gst_element_link_many ( data.rtp, data.vpudec , data.converter ,
data.capsfilter, data.gdkpixbufoverlay, data.sink, NULL);
g_signal_connect (data.source, "pad-added", G_CALLBACK (pad_added_handler),
&data);
// Set the pipeline to "playing" state
GstStateChangeReturn ret;
ret = gst_element_set_state (data.pipeline, GST_STATE_PLAYING);
if (ret == GST_STATE_CHANGE_FAILURE) {
g_printerr("Unable to set the pipeline to the playing state.\n");
gst_object_unref (data.pipeline);
return -1;
}
// Iterate
g_main_loop_run (data.loop);
// Out of the main loop, clean
g_print ("Returned, stopping playback\n");
gst_element_set_state (data.pipeline, GST_STATE_NULL);
g_print ("Deleting pipeline\n");
gst_object_unref (GST_OBJECT (data.pipeline));
return 0;
}
Does anyone see the problem?
Thank you

After many tries, I did figure out that in the C code I posted I have selected the wrong element, therefore the data.converter element is:
data.converter = gst_element_factory_make("imxvideoconvert_ipu ","converter");
and not imxcompositor_ipu .

Related

WL_SHM_FORMAT_ARGB8888 not fully transparent if color bit was set

I am learning Wayland client programming and now I'm trying to make transparent surface.
I created a buffer and paint each pixels to shared memory. I am using WL_SHM_FORMAT_ARGB8888 format but it is not working as I expected.
As I understand, 0x00ff0000 means 255 red, 0 green, 0 blue and 0 alpha so the pixel should not shown. But it shows semi-transparent red surface to me.
Below is entire source code working on Weston compositor.
// main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wayland-client.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>
#include <unistd.h>
#include "xdg-shell.h"
struct wl_display *display = NULL;
struct wl_compositor *compositor = NULL;
struct wl_surface *surface;
struct zxdg_shell_v6 *xdg_shell = NULL;
struct zxdg_surface_v6 *xdg_surface;
struct zxdg_toplevel_v6 *xdg_toplevel;
struct wl_shm *shm;
struct wl_buffer *buffer;
void *shm_data;
int WIDTH = 480;
int HEIGHT = 360;
//===============
// Xdg
//===============
static void xdg_shell_ping_handler(void *data, struct zxdg_shell_v6 *xdg_shell,
uint32_t serial)
{
zxdg_shell_v6_pong(xdg_shell, serial);
printf("ping pong!\n");
}
static const struct zxdg_shell_v6_listener xdg_shell_listener = {
.ping = xdg_shell_ping_handler,
};
static void xdg_toplevel_configure_handler(void *data,
struct zxdg_toplevel_v6 *xdg_toplevel, int32_t width, int32_t height,
struct wl_array *states)
{
printf("Configure: %dx%d\n", width, height);
}
static void xdg_toplevel_close_handler(void *data,
struct zxdg_toplevel_v6 *xdg_toplevel)
{
printf("Close\n");
}
static const struct zxdg_toplevel_v6_listener xdg_toplevel_listener = {
.configure = xdg_toplevel_configure_handler,
.close = xdg_toplevel_close_handler,
};
static void xdg_surface_configure_handler(void *data,
struct zxdg_surface_v6 *xdg_surface, uint32_t serial)
{
fprintf(stderr, "xdg_surface_configure_handler().\n");
zxdg_surface_v6_ack_configure(xdg_surface, serial);
}
static const struct zxdg_surface_v6_listener xdg_surface_listener = {
.configure = xdg_surface_configure_handler,
};
//=================
// File system
//=================
static int set_cloexec_or_close(int fd)
{
long flags;
if (fd == -1) {
return -1;
}
flags = fcntl(fd, F_GETFD);
if (flags == -1)
goto err;
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
goto err;
return fd;
err:
close(fd);
return -1;
}
static int create_tmpfile_cloexec(char *tmpname)
{
int fd;
#ifdef HAVE_MKOSTEMP
fd= mkostemp(tmpname, O_CLOEXEC);
if (fd >= 0) {
unlink(tmpname);
}
#else
fd = mkstemp(tmpname);
if (fd >= 0) {
fd = set_cloexec_or_close(fd);
unlink(tmpname);
}
#endif
return fd;
}
int os_create_anonymous_file(off_t size)
{
static const char template[] = "/blusher-shared-XXXXXX";
const char *path;
char *name;
int fd;
path = getenv("XDG_RUNTIME_DIR");
if (!path) {
errno = ENOENT;
return -1;
}
name = malloc(strlen(path) + sizeof(template));
if (!name) {
return -1;
}
strcpy(name, path);
strcat(name, template);
fd = create_tmpfile_cloexec(name);
free(name);
if (fd < 0) {
return -1;
}
if (ftruncate(fd, size) < 0) {
close(fd);
return -1;
}
return fd;
}
//==============
// Painting
//==============
static void paint_pixels()
{
uint32_t *pixel = shm_data;
fprintf(stderr, "Painting pixels.\n");
for (int n = 0; n < WIDTH * HEIGHT; ++n) {
if (n > 1100 && n < 1200) {
pixel[n] = 0xffff0000; // please ignore this
} else {
pixel[n] = 0x00ff0000;
}
}
}
static struct wl_buffer* create_buffer()
{
struct wl_shm_pool *pool;
int stride = WIDTH * 4; // 4 bytes per pixel
int size = stride * HEIGHT;
int fd;
struct wl_buffer *buff;
fd = os_create_anonymous_file(size);
if (fd < 0) {
fprintf(stderr, "Creating a buffer file for %d B filed: %m\n",
size);
exit(1);
}
shm_data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (shm_data == MAP_FAILED) {
fprintf(stderr, "mmap filed: %m\n");
close(fd);
exit(1);
}
pool = wl_shm_create_pool(shm, fd, size);
buff = wl_shm_pool_create_buffer(
pool,
0,
WIDTH,
HEIGHT,
stride,
WL_SHM_FORMAT_ARGB8888
);
wl_shm_pool_destroy(pool);
return buff;
}
static void create_window()
{
buffer = create_buffer();
wl_surface_attach(surface, buffer, 0, 0);
// wl_surface_damage(surface, 0, 0, WIDTH, HEIGHT);
wl_surface_commit(surface);
}
static void shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
{
// struct display *d = data;
// d->formats |= (1 << format);
fprintf(stderr, "Format %d\n", format);
}
struct wl_shm_listener shm_listener = {
shm_format,
};
//==============
// Global
//==============
static void global_registry_handler(void *data, struct wl_registry *registry,
uint32_t id, const char *interface, uint32_t version)
{
if (strcmp(interface, "wl_compositor") == 0) {
fprintf(stderr, "Interface is <wl_compositor>.\n");
compositor = wl_registry_bind(
registry,
id,
&wl_compositor_interface,
version
);
} else if (strcmp(interface, "zxdg_shell_v6") == 0) {
fprintf(stderr, "Interface is <zxdg_shell_v6>.\n");
xdg_shell = wl_registry_bind(registry, id, &zxdg_shell_v6_interface, 1);
} else if (strcmp(interface, "wl_shm") == 0) {
fprintf(stderr, "Interface is <wl_shm>.\n");
shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
wl_shm_add_listener(shm, &shm_listener, NULL);
} else {
// printf("(%d) Got a registry event for <%s> id <%d>\n",
// version, interface, id);
}
}
static void global_registry_remover(void *data, struct wl_registry *registry,
uint32_t id)
{
printf("Got a registry losing event for <%d>\n", id);
}
static const struct wl_registry_listener registry_listener = {
global_registry_handler,
global_registry_remover
};
//==============
// Main
//==============
int main(int argc, char *argv[])
{
(void)argc;
(void)argv;
display = wl_display_connect(NULL);
if (display == NULL) {
fprintf(stderr, "Can't connect to display.\n");
exit(1);
}
printf("Connected to display.\n");
struct wl_registry *registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, NULL);
wl_display_dispatch(display);
// wl_display_roundtrip(display);
// Check compositor.
fprintf(stderr, " - Checking compositor...\n");
if (compositor == NULL) {
fprintf(stderr, "Can't find compositor.\n");
exit(1);
}
// Check surface.
fprintf(stderr, " - Checking surface...\n");
surface = wl_compositor_create_surface(compositor);
if (surface == NULL) {
fprintf(stderr, "Can't create surface.\n");
exit(1);
}
if (xdg_shell == NULL) {
fprintf(stderr, "Haven't got a Xdg shell.\n");
exit(1);
}
zxdg_shell_v6_add_listener(xdg_shell, &xdg_shell_listener, NULL);
// Check shell surface.
xdg_surface =
zxdg_shell_v6_get_xdg_surface(xdg_shell, surface);
zxdg_surface_v6_add_listener(xdg_surface, &xdg_surface_listener, NULL);
xdg_toplevel = zxdg_surface_v6_get_toplevel(xdg_surface);
zxdg_toplevel_v6_add_listener(xdg_toplevel, &xdg_toplevel_listener, NULL);
// Signal that the surface is ready to be configured.
wl_surface_commit(surface);
// Wait for the surface to be configured.
wl_display_roundtrip(display);
create_window();
paint_pixels();
// wl_surface_attach(surface, buffer, 0, 0);
// wl_surface_commit(surface);
while (wl_display_dispatch(display) != -1) {
;
}
wl_display_disconnect(display);
printf("Disconnected from display.\n");
return 0;
}
# Makefile
default:
wayland-scanner client-header /usr/share/wayland-protocols/unstable/xdg-shell/xdg-shell-unstable-v6.xml xdg-shell.h
wayland-scanner public-code /usr/share/wayland-protocols/unstable/xdg-shell/xdg-shell-unstable-v6.xml xdg-shell.c
gcc -lwayland-client -lwayland-egl -lEGL -lGLESv2 main.c xdg-shell.c
But when I set pixel to 0x00000000, then it is fully transparent.
And in some tests, subsurfaces are completely transparent even there are color bits set. I want to know what is prevent the transparent toplevel surface with color bits.
If your wayland compositor supports alpha-compositing-v1 protocol you can use it do what you want.
In short; get a reference to zwp_alpha_compositing_v1 struct in you registry handler then after creating your surface you set it like this:
struct zwp_blending_v1* blending = zwp_alpha_compositing_v1_get_blending(<YOUR_ZWP_ALPHA_COMPOSITING>, <YOUR_WL_SURFACE>);
zwp_blending_v1_set_blending(blending, ZWP_BLENDING_V1_BLENDING_EQUATION_STRAIGHT);
This is an equivalent to (src_alpha, one_minus_src_alpha) blending.

How to implement a tcp server in GTK based application using GIOChannel

I have got below sample from stackoverflow itself.
#include <glib.h>
#include <gio/gio.h>
gchar *buffer;
gboolean
network_write(GIOChannel *source,
GIOCondition cond,
gpointer data)
{
return TRUE;
}
gboolean
network_read(GIOChannel *source,
GIOCondition cond,
gpointer data)
{
GString *s = g_string_new(NULL);
GError *error;
g_print("Inside network_read function\n");
GIOStatus ret = g_io_channel_read_line_string(source, s, NULL, &error);
if (ret == G_IO_STATUS_ERROR)
g_error ("Error reading: %s\n", error->message);
else
g_print("Got: %s\n", s->str);
return TRUE;
}
gboolean
new_connection(GSocketService *service,
GSocketConnection *connection,
GObject *source_object,
gpointer user_data)
{
GSocketAddress *sockaddr = g_socket_connection_get_remote_address(connection, NULL);
GInetAddress *addr = g_inet_socket_address_get_address(G_INET_SOCKET_ADDRESS(sockaddr));
guint16 port = g_inet_socket_address_get_port(G_INET_SOCKET_ADDRESS(sockaddr));
g_print("New Connection from %s:%d\n", g_inet_address_to_string(addr), port);
GSocket *socket = g_socket_connection_get_socket(connection);
gint fd = g_socket_get_fd(socket);
g_print("Naseeb fd: %d\n", fd);
GIOChannel *channel = g_io_channel_unix_new(fd);
if(!g_io_add_watch(channel, G_IO_IN, (GIOFunc) network_read, NULL))
{
g_print("Got Error while adding network_read\n");
}
// g_io_add_watch(channel, G_IO_OUT, (GIOFunc) network_write, NULL);
return TRUE;
}
int main(int argc, char **argv) {
g_type_init();
GSocketService *service = g_socket_service_new();
GInetAddress *address = g_inet_address_new_from_string("0.0.0.0");
GSocketAddress *socket_address = g_inet_socket_address_new(address, 3001);
g_socket_listener_add_address(G_SOCKET_LISTENER(service), socket_address, G_SOCKET_TYPE_STREAM,
G_SOCKET_PROTOCOL_TCP, NULL, NULL, NULL);
g_object_unref(socket_address);
g_object_unref(address);
g_socket_service_start(service);
g_signal_connect(service, "incoming", G_CALLBACK(new_connection), NULL);
g_socket_service_start(service);
GMainLoop *loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(loop);
return 0;
}
Using this code, i am able to get the client connected to server. I confirm the same using message printed in the function new_connection
But when i send data from client, callback network_read never gets called at server. Although client side, send() API return value shows total bytes sent.
1) Is there any api missing at server side.
2) What is proper way to invoke network_write ?
You shouldn't be using GIOChannel, new_connection() already has a connection and you can just use stream = g_io_stream_get_input_stream (G_IO_STREAM (connection)); to get a GInputStream to read from.

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);
...

Gtk, runtime menu

I have runtime-created menu based on words in selected gtkTreeView row.
gboolean
menu_RELEASE(GtkObject *object, GdkEvent *event, gpointer user_data)
{
if (strlen(user_data) > 0)
{
gtk_entry_set_text(GTK_ENTRY(entry1), user_data);
gtk_widget_grab_focus(entry1);
}
else
main_art(get_sifra());
return TRUE;
}
gboolean
treeview1_BUTTONRELEASE(GtkWidget *widget, GdkEventButton *event, gpointer *user_data)
{
if (event->type == GDK_BUTTON_RELEASE && event->button == 3)
{
char *ntext;
treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
if (gtk_tree_selection_get_selected(treesel, &model ,&iter))
{
gtk_tree_model_get(model, &iter, cNaziv, &ntext, -1);
GtkWidget *menu, *menu_item;
menu = gtk_menu_new();
char *sresult = NULL;
sresult = strtok(ntext, " ");
while(sresult != NULL)
{
if (strlen(sresult)>1)
{
menu_item = gtk_menu_item_new_with_label(sresult);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
g_signal_connect(G_OBJECT(menu_item), "button-release-event", G_CALLBACK(menu_RELEASE), (gpointer)sresult);
}
sresult = strtok(NULL, " ");
}
menu_item = gtk_separator_menu_item_new();
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
//
menu_item = gtk_image_menu_item_new_with_label("Uredi...");
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), GTK_WIDGET(gtk_image_new_from_stock(GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU)));
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
g_signal_connect(G_OBJECT(menu_item), "button-release-event", G_CALLBACK(menu_RELEASE), (gpointer)"");
//
gtk_widget_show_all(menu);
gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
return TRUE;
}
}
return FALSE;
}
When menu item was released action from "menu_RELEASE" should appear.
But what happened?
Menu don't dissappear, stay's visible and active.
What is wrong with my code?
You're not supposed to connect to mouse-button signals of the items, that's being too low-level. Your handler is "swallowing" the mouse button signal, preventing GTK+ from handling it.
Use the activate signal.

How to access (copy/modify) particular appfiledirectory from the name of its background process in iPhone?

I have list of background processes and their pid running in background in iphone got from following code. My projects requirement is-
(its like an antivirus)
Get information on each process
a. Name
b. Size
c. Last Modified Date/Time
d. Associated Files
e. What the process is accessing from all interfaces (storage, USB, Bluetooth, Wi-Fi etc)
f. Any other information available
Thanks in advance.
#import <mach/mach_host.h>
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "sys/sysctl.h"
#include <CoreFoundation/CoreFoundation.h>
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
- (void)viewDidLoad
{
[super viewDidLoad];
[self printProcessInfo];
}
-(int) printProcessInfo
{
int mib[5];
struct kinfo_proc *procs = NULL, *newprocs;
int i, st, nprocs;
size_t miblen, size;
/* Set up sysctl MIB */
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_ALL;
mib[3] = 0;
miblen = 4;
/* Get initial sizing */
st = sysctl(mib, miblen, NULL, &size, NULL, 0);
/* Repeat until we get them all ... */
do {
/* Room to grow */
size += size / 10;
newprocs = realloc(procs, size);
if (!newprocs) {
if (procs) {
free(procs);
}
perror("Error: realloc failed.");
return (0);
}
procs = newprocs;
st = sysctl(mib, miblen, procs, &size, NULL, 0);
} while (st == -1 && errno == ENOMEM);
if (st != 0) {
perror("Error: sysctl(KERN_PROC) failed.");
return (0);
}
/* Do we match the kernel? */
assert(size % sizeof(struct kinfo_proc) == 0);
nprocs = size / sizeof(struct kinfo_proc);
if (!nprocs) {
perror("Error: printProcessInfo.");
return(0);
}
printf(" PID\tName\n");
printf("-----\t--------------\n");
self.lists = [[NSMutableString alloc] init];
for (i = nprocs-1; i >=0; i--) {
printf("%5d\t%s\n",(int)procs[i].kp_proc.p_pid, procs[i].kp_proc.p_comm);
}
NSLog(#"%#",lists);
listsText.text = lists;
free(procs);
return (0);
}
answer a)name of process you are getting in above code.
answer d)to get associated files,pass pid of process to this function (we have got pid in questions code)-
void print_argv_of_pid(int pid) {
printf("%d\n", pid);
int mib[3], argmax, nargs, c = 0;
size_t size;
char *procargs, *sp, *np, *cp;
extern int eflg;
int show_args = 1;
mib[0] = CTL_KERN;
mib[1] = KERN_ARGMAX;
size = sizeof(argmax);
if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1) {
goto ERROR_A;
}
/* Allocate space for the arguments. */
procargs = (char *)malloc(argmax);
if (procargs == NULL) {
goto ERROR_A;
}
mib[0] = CTL_KERN;
mib[1] = KERN_PROCARGS2;
mib[2] = pid;
size = (size_t)argmax;
if (sysctl(mib, 3, procargs, &size, NULL, 0) == -1) {
goto ERROR_B;
}
memcpy(&nargs, procargs, sizeof(nargs));
cp = procargs + sizeof(nargs);
/* Skip the saved exec_path. */
for (; cp < &procargs[size]; cp++) {
if (*cp == '\0') {
/* End of exec_path reached. */
break;
}
}
if (cp == &procargs[size]) {
goto ERROR_B;
}
/* Skip trailing '\0' characters. */
for (; cp < &procargs[size]; cp++) {
if (*cp != '\0') {
/* Beginning of first argument reached. */
break;
}
}
if (cp == &procargs[size]) {
goto ERROR_B;
}
/* Save where the argv[0] string starts. */
sp = cp;
for (np = NULL; c < nargs && cp < &procargs[size]; cp++) {
if (*cp == '\0') {
c++;
if (np != NULL) {
/* Convert previous '\0'. */
*np = ' ';
} else {
/* *argv0len = cp - sp; */
}
/* Note location of current '\0'. */
np = cp;
if (!show_args) {
/*
* Don't convert '\0' characters to ' '.
* However, we needed to know that the
* command name was terminated, which we
* now know.
*/
break;
}
}
}
if (np == NULL || np == sp) {
/* Empty or unterminated string. */
goto ERROR_B;
}
/* Make a copy of the string. */
printf("%s\n", sp);
/* Clean up. */
free(procargs);
return;
ERROR_B:
free(procargs);
ERROR_A:
printf("error");
}
answer b),c)-size and access times-
struct stat st;
//pass filepath upto /.app/ to stat function (use 'componentsseparatedby' of nsstring apply on full path which we got in answer d's code above)
if (stat(filename, &st)) {
perror(filename);
} else {
printf("%s: mtime = %lld.%.9ld\n", filename, (long long)st.st_mtimespec.tv_sec, st.st_mtimespec.tv_nsec);
printf("File size: %lld bytes\n",
(long long) st.st_size);
printf("Last status change: %s", ctime(&st.st_ctime));
printf("Last file access: %s", ctime(&st.st_atime));
printf("Last file modification: %s", ctime(&st.st_mtime));
}
other information-
TO KILL THE PROCESS-
just pass pid of process to be killed-
int pid_exists(long pid)
{
int kill_ret;
// save some time if it's an invalid PID
if (pid < 0) {
return 0;
}
// if kill returns success of permission denied we know it's a valid PID
kill_ret = kill(pid , 0);
if ( (0 == kill_ret) || (EPERM == errno) ) {
return 1;
}
// otherwise return 0 for PID not found
return 0;
}