Why does my CreateThread input parameter get corrupted? - multithreading

In a namespace extension, I'm creating a thread and passing in a file path to the thread function.
The problem I'm seeing is the first character of the file path gets corrupted. D:\temp0.csv gets passed in and in the thread function it becomes Y:\temp0.csv or some other random corrupted first wchar. In Win2k8R2 and Win10 it was working fine, but sometimes it would fail in the same way. I tried disabling optimizations to no avail.
The fileName variable is populated from the IShellItem that came from the IFileOpenDialog.
What do I need to do to fix this?
Caller of thread function:
LPWSTR filePath = NULL;
IFileOpenDialog *ofd = NULL;
IShellItem *file = NULL;
hrPath = file->GetDisplayName(SIGDN_FILESYSPATH, &filePath);
CreateThread(NULL, 0, CCsv::BuildTree, static_cast<LPVOID>(filePath), 0, NULL);
static class thread function
DWORD WINAPI CCsv::BuildTree(LPVOID lpParam) {
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
LPWSTR filePath = static_cast<LPWSTR>(lpParam);
}
Here is a minimal program, but it does not repro with this code. One difference is I added a wait for the thread function. THat doesn't exist in the namespace extension.
main.cpp
// buf.cpp : Defines the entry point for the console application.
//
#pragma once
#include "stdafx.h"
using std::wstring;
static CRITICAL_SECTION g_TreeLock;
static CRITICAL_SECTION g_MountQueueLock;
class CCsv
{
public:
CCsv();
~CCsv();
static DWORD WINAPI BuildTree(LPVOID lpParam);
};
class CMountPath {
public:
CMountPath();
~CMountPath();
BOOL Mount();
BOOL PathExists(LPWSTR path);
private:
CSimpleArray<wstring> m_MountQueue;
};
extern CCsv g_Csv;
CCsv::CCsv() {
InitializeCriticalSection(&g_TreeLock);
}
CCsv::~CCsv() {
DeleteCriticalSection(&g_TreeLock);
}
DWORD WINAPI CCsv::BuildTree(LPVOID lpParam) {
LPWSTR name = static_cast<LPWSTR>(lpParam);
MessageBox(NULL, name, L"", MB_OK);
CoTaskMemFree(name);
return 0;
}
CMountPath::CMountPath() {
InitializeCriticalSection(&g_MountQueueLock);
}
CMountPath::~CMountPath() {
DeleteCriticalSection(&g_MountQueueLock);
}
BOOL CMountPath::PathExists(LPWSTR path) {
return FALSE;
}
BOOL CMountPath::Mount() {
IEnumIDList *idl = NULL;
LPITEMIDLIST pidl = NULL;
LPITEMIDLIST desktopPidl = NULL;
LPCITEMIDLIST pidlRelative = NULL;
BOOL success = FALSE;
HRESULT hr, hrPath = S_FALSE;
LPWSTR filePath = NULL;
PWSTR filePathHeap = NULL;
WCHAR msg[MAXPATH+MAXMSG] = {0};
IFileOpenDialog *ofd = NULL;
IShellItem *file = NULL;
DWORD idx = 0;
BOOL isQueued = FALSE;
const COMDLG_FILTERSPEC fileSpec[] = {
{ L"CSV Text Files", L"*.csv" },
{ L"All Files", L"*.*" },
};
hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&ofd));
if (SUCCEEDED(hr)) {
if (SUCCEEDED(hr)){
ofd->SetTitle(L"Choose file");
ofd->SetFileTypes(ARRAYSIZE(fileSpec), fileSpec);
hr = ofd->Show(NULL);
if(SUCCEEDED(hr))
hr = ofd->GetResult(&file);
if(SUCCEEDED(hr))
hrPath = file->GetDisplayName(SIGDN_FILESYSPATH, &filePath);
if(SUCCEEDED(hrPath)){
LPWSTR filePathHeap = (LPWSTR)CoTaskMemAlloc(MAXPATH * sizeof(WCHAR));
if(filePathHeap) {
StringCchCopy(filePathHeap, MAXPATH, filePath);
if(PathExists(filePathHeap)) {
StringCchPrintf(msg, MAXPATH+MAXMSG, L"The file %s is already loaded.", filePathHeap);
MessageBox(NULL, msg, L"appname", MB_OK);
}
else {
EnterCriticalSection(&g_MountQueueLock);
isQueued = !m_MountQueue.Find(wstring(filePathHeap)) ? TRUE : FALSE;
if(!isQueued)
m_MountQueue.Add(wstring(filePathHeap));
LeaveCriticalSection(&g_MountQueueLock);
if(!isQueued) {
HANDLE hThread = CreateThread(NULL, 0, CCsv::BuildTree, static_cast<LPVOID>(filePathHeap), 0, NULL);
// there is no wait in the namespace extension. the wait is just to keep the console app main thread running.
if(INVALID_HANDLE_VALUE != hThread)
WaitForSingleObject(hThread, INFINITE);
}
else {
StringCchPrintf(msg, MAXPATH+MAXMSG, L"The file %s is already being loaded.", filePathHeap);
MessageBox(NULL, msg, L"appname", MB_OK);
}
}
}
CoTaskMemFree(filePath);
file->Release();
}
}
ofd->Release();
}
return success;
}
int main() {
CoInitialize(NULL);
CMountPath m;
m.Mount();
CoUninitialize();
return 0;
}
stdafx.h
#pragma once
#define MAXPATH 32767
#define MAXMSG 128
#define WIN32_LEAN_AND_MEAN
#define WINVER 0x0600
#define _WIN32_WINNT 0x0600
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <atlbase.h>
#include <atlstr.h>
#include <atlcoll.h>
#include <shlobj.h>
#include <Shobjidl.h>
#include <ShlGuid.h>
#include <shellapi.h>
#include <OleAuto.h>
#include <shlwapi.h>
#include <strsafe.h>
#include <string>

Why are you using threads at all? When you spawn a new thread, you are blocking your code waiting for the thread to terminate before continuing, so you are serializing all of your code. You may as well not even use threads at all.
Also, you have memory leaks and various logic errors in your code.
Try this instead:
// buf.cpp : Defines the entry point for the console application.
//
#pragma once
#include "stdafx.h"
using std::wstring;
class CCsv
{
public:
CCsv();
~CCsv();
void BuildTree(LPCWSTR name);
private:
CRITICAL_SECTION m_TreeLock;
};
class CMountPath {
public:
CMountPath();
~CMountPath();
BOOL Mount();
BOOL PathExists(LPCWSTR path);
private:
CSimpleArray<wstring> m_MountQueue;
CRITICAL_SECTION m_MountQueueLock;
};
CCsv g_Csv;
CCsv::CCsv() {
InitializeCriticalSection(&m_TreeLock);
}
CCsv::~CCsv() {
DeleteCriticalSection(&m_TreeLock);
}
void CCsv::BuildTree(LPCWSTR name) {
MessageBoxW(NULL, name, L"", MB_OK);
}
CMountPath::CMountPath() {
InitializeCriticalSection(&m_MountQueueLock);
}
CMountPath::~CMountPath() {
DeleteCriticalSection(&m_MountQueueLock);
}
BOOL CMountPath::PathExists(LPCWSTR path) {
return FALSE;
}
BOOL CMountPath::Mount() {
BOOL success = FALSE;
HRESULT hr = S_FALSE;
LPWSTR filePath = NULL;
WCHAR msg[MAXPATH+MAXMSG] = {0};
IFileOpenDialog *ofd = NULL;
IShellItem *file = NULL;
BOOL isQueued = FALSE;
const COMDLG_FILTERSPEC fileSpec[] = {
{ L"CSV Text Files", L"*.csv" },
{ L"All Files", L"*.*" },
};
hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&ofd));
if (SUCCEEDED(hr)) {
ofd->SetTitle(L"Choose file");
ofd->SetFileTypes(ARRAYSIZE(fileSpec), fileSpec);
hr = ofd->Show(NULL);
if(SUCCEEDED(hr))
hr = ofd->GetResult(&file);
if(SUCCEEDED(hr)) {
hr = file->GetDisplayName(SIGDN_FILESYSPATH, &filePath);
if(SUCCEEDED(hr)){
if(PathExists(filePath)) {
StringCchPrintf(msg, ARRAYSIZE(msg), L"The file %s is already loaded.", filePath);
MessageBox(NULL, msg, L"appname", MB_OK);
}
else {
EnterCriticalSection(&m_MountQueueLock);
isQueued = !m_MountQueue.Find(filePath) ? TRUE : FALSE;
if(!isQueued)
m_MountQueue.Add(filePath);
LeaveCriticalSection(&m_MountQueueLock);
if(!isQueued) {
CCsv::BuildTree(filePath);
}
else {
StringCchPrintf(msg, ARRAYSIZE(msg), L"The file %s is already being loaded.", filePath);
MessageBox(NULL, msg, L"appname", MB_OK);
}
}
CoTaskMemFree(filePath);
}
file->Release();
}
ofd->Release();
}
return success;
}
int main() {
CoInitialize(NULL);
CMountPath m;
m.Mount();
CoUninitialize();
return 0;
}

your conceptual mistake here:
if(!isQueued)
{
m_MountQueue.Add(wstring(filePathHeap));
CreateThread(NULL, 0, CCsv::BuildTree, static_cast<LPVOID>(filePathHeap), 0, NULL);
}
so you insert filePathHeap in some database and simultaneously pass this filePathHeap to some thread. question - who is OWNER of filePathHeap ? who must free it ? if you free it from BuildTree - in m_MountQueue will be invalid pointer ? you not show code who and how handle m_MountQueue - may be this code pop and free filePathHeap before it used in BuildTree.
in general - if you push filePathHeap to m_MountQueue - you must not direct use it pointer after this, but have working thread (pool) which pop data from m_MountQueue , process and free it. or if you direct use filePathHeap you must not insert it to m_MountQueue.
in case if you need simultaneously working with filePathHeap from several threads - you need ref count have. some like this:
class CFilePath
{
PWSTR _filePath;
LONG _dwRef;
~CFilePath()
{
CoTaskMemFree(_filePath);
}
public:
PCWSTR getPath() { return _filePath; }
CFilePath(PWSTR filePath)
{
_filePath = filePath;
_dwRef = 1;
}
void AddRef()
{
InterlockedIncrement(&_dwRef);
}
void Release()
{
if (!InterlockedDecrement(&_dwRef)) delete this;
}
};
ULONG CALLBACK CCsv::BuildTree(CFilePath* p)
{
MessageBoxW(0, p->getPath(), L"use path in thread 2", MB_OK);
p->Release();
return 0;
}
BOOL CMountPath::Mount() {
...
if (CFilePath* p = new CFilePath(filePath))
{
p->AddRef();
if (HANDLE hThread = CreateThread(0, 0, reinterpret_cast<PTHREAD_START_ROUTINE>(CCsv::BuildTree), p, 0, 0))
{
CloseHandle(hThread);
}
else
{
p->Release();
}
MessageBoxW(0, p->getPath(), L"use path in thread 1", MB_OK);
p->Release();
}
else
{
CoTaskMemFree(filePath);
}
...
}
Secondly - this code
LPWSTR filePathHeap = (LPWSTR)CoTaskMemAlloc(MAXPATH * sizeof(WCHAR));
if(filePathHeap) StringCchCopy(filePathHeap, MAXPATH, filePath);
absolutely unnecessary. you can direct use filePath as is, but not reallocate it. for what ?!
thirdly - as in previous answer - almost no sense create thread and after this just wait on it exit.
HANDLE hThread = CreateThread(NULL, 0, CCsv::BuildTree, static_cast<LPVOID>(filePathHeap), 0, NULL);
// there is no wait in the namespace extension. the wait is just to keep the console app main thread running.
if(INVALID_HANDLE_VALUE != hThread)
WaitForSingleObject(hThread, INFINITE);
why in this case not direct call CCsv::BuildTree(filePathHeap); with same effect ?
also can note that INVALID_HANDLE_VALUE returned only for CreateFile or Socket - so for file handles only. all another object creating api (including CreateThread return 0 on error, but not INVALID_HANDLE_VALUE (-1) ) - so you incorrect check error condition.
and finally who will call CloseHandle(hThread) ? handle not auto closed when thread exit

Related

How to prematurely kill std::async threads before they are finished *without* using a std::atomic_bool?

I have a function that takes a callback, and used it to do work on 10 separate threads. However, it is often the case that not all of the work is needed. For example, if the desired result is obtained on the third thread, it should stop all work being done on of the remaining alive threads.
This answer here suggests that it is not possible unless you have the callback functions take an additional std::atomic_bool argument, that signals whether the function should terminate prematurely.
This solution does not work for me. The workers are spun up inside a base class, and the whole point of this base class is to abstract away details of multithreading. How can I do this? I am anticipating that I will have to ditch std::async for something more involved.
#include <iostream>
#include <future>
#include <vector>
class ABC{
public:
std::vector<std::future<int> > m_results;
ABC() {};
~ABC(){};
virtual int callback(int a) = 0;
void doStuffWithCallBack();
};
void ABC::doStuffWithCallBack(){
// start working
for(int i = 0; i < 10; ++i)
m_results.push_back(std::async(&ABC::callback, this, i));
// analyze results and cancel all threads when you get the 1
for(int j = 0; j < 10; ++j){
double foo = m_results[j].get();
if ( foo == 1){
break; // but threads continue running
}
}
std::cout << m_results[9].get() << " <- this shouldn't have ever been computed\n";
}
class Derived : public ABC {
public:
Derived() : ABC() {};
~Derived() {};
int callback(int a){
std::cout << a << "!\n";
if (a == 3)
return 1;
else
return 0;
};
};
int main(int argc, char **argv)
{
Derived myObj;
myObj.doStuffWithCallBack();
return 0;
}
I'll just say that this should probably not be a part of a 'normal' program, since it could leak resources and/or leave your program in an unstable state, but in the interest of science...
If you have control of the thread loop, and you don't mind using platform features, you could inject an exception into the thread. With posix you can use signals for this, on Windows you would have to use SetThreadContext(). Though the exception will generally unwind the stack and call destructors, your thread may be in a system call or other 'non-exception safe place' when the exception occurs.
Disclaimer: I only have Linux at the moment, so I did not test the Windows code.
#if defined(_WIN32)
# define ITS_WINDOWS
#else
# define ITS_POSIX
#endif
#if defined(ITS_POSIX)
#include <signal.h>
#endif
void throw_exception() throw(std::string())
{
throw std::string();
}
void init_exceptions()
{
volatile int i = 0;
if (i)
throw_exception();
}
bool abort_thread(std::thread &t)
{
#if defined(ITS_WINDOWS)
bool bSuccess = false;
HANDLE h = t.native_handle();
if (INVALID_HANDLE_VALUE == h)
return false;
if (INFINITE == SuspendThread(h))
return false;
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_CONTROL;
if (GetThreadContext(h, &ctx))
{
#if defined( _WIN64 )
ctx.Rip = (DWORD)(DWORD_PTR)throw_exception;
#else
ctx.Eip = (DWORD)(DWORD_PTR)throw_exception;
#endif
bSuccess = SetThreadContext(h, &ctx) ? true : false;
}
ResumeThread(h);
return bSuccess;
#elif defined(ITS_POSIX)
pthread_kill(t.native_handle(), SIGUSR2);
#endif
return false;
}
#if defined(ITS_POSIX)
void worker_thread_sig(int sig)
{
if(SIGUSR2 == sig)
throw std::string();
}
#endif
void init_threads()
{
#if defined(ITS_POSIX)
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = worker_thread_sig;
sigaction(SIGUSR2, &sa, 0);
#endif
}
class tracker
{
public:
tracker() { printf("tracker()\n"); }
~tracker() { printf("~tracker()\n"); }
};
int main(int argc, char *argv[])
{
init_threads();
printf("main: starting thread...\n");
std::thread t([]()
{
try
{
tracker a;
init_exceptions();
printf("thread: started...\n");
std::this_thread::sleep_for(std::chrono::minutes(1000));
printf("thread: stopping...\n");
}
catch(std::string s)
{
printf("thread: exception caught...\n");
}
});
printf("main: sleeping...\n");
std::this_thread::sleep_for(std::chrono::seconds(2));
printf("main: aborting...\n");
abort_thread(t);
printf("main: joining...\n");
t.join();
printf("main: exiting...\n");
return 0;
}
Output:
main: starting thread...
main: sleeping...
tracker()
thread: started...
main: aborting...
main: joining...
~tracker()
thread: exception caught...
main: exiting...

Mfc application crash in CWnd::DefWindowProc while creating Progress Control from within Worker Thread after 34 repetitive cycles on 64 bit windows

I am trying to figure out the exact reason for the crash happening in my 32 bit MFC application which is running on 64 bit system.
Actually this is a multithreaded MFC SDI application and can do cyclic execution which includes Inspection and outputting inspection results as reports.
After an inspection finishes it show a Custom Alert Window with a progress control until the reports are generated.The Alert Window is created from a Worker Thread and the Main Thread waits until the window is created.
Below is the coded representation of one cycle of Displaying the Alert Window With Progress Bar:
static const __int64 POPUPWND_POLLPERIOD = 10 * 10000LL;
static const __int64 POPUPWND_POLLTIMEOUT = 1000 * POPUPWND_POLLPERIOD;
class CCallFunc
{
public:
class Queue;
public:
typedef int(*Call)(const CCallFunc &cf);
public:
CCallFunc(Call call, LPVOID lpData) :
m_call(call),
m_lpData(lpData)
{}
int Run() { m_call(*this); }
LPVOID GetData() const { return m_lpData; }
private:
Call m_call;
LPVOID m_lpData;
};
class CCallFunc::Queue
{
public:
int SetQueue(const CCallFunc &cf, const __int64 &timeout = INFINITE)
{
m_pcf = &cf;
m_timeout = timeout;
}
public:
int Run(const __int64 &timeout = 0)
{
CCallFunc cf(*m_pcf);
cf.Run();
}
private:
const CCallFunc* m_pcf;
__int64 m_timeout;
};
class CWorkThread
{
private:
static DWORD WINAPI SystemThread(LPVOID lpData)
{
CWorkThread* pThread = (CWorkThread*)lpData;
__int64 timeout = pThread->m_timeout;
try {
pThread->m_queue.Run(timeout);
}
catch (const CCallFunc &cf) {
pThread->m_queue.SetQueue(cf, timeout);
}
}
public:
static int Aquire(CWorkThread *pThread)
{
pThread = &thisThread;
return S_OK;
}
static void Sleep(const __int64 &period)
{
__int64 current;
__int64 final = period;
switch (final) {
case INFINITE:
while (true)
::SleepEx(INFINITE, TRUE);
throw;
case 0:
::SleepEx(DWORD(0), TRUE);
return;
default:
::GetSystemTimeAsFileTime(reinterpret_cast<FILETIME*>(&current));
if ((final += current) < 0)
final = current;
while (current < final) {
if (::SleepEx(DWORD((final - current) / __int64(10000)), TRUE) == 0)
return;
::GetSystemTimeAsFileTime((FILETIME*)&current);
}
}
}
int Start(CCallFunc::Call call, LPVOID lpData)
{
return Start(CCallFunc(call, lpData));
}
int Start(const CCallFunc &fc)
{
DWORD dwID = 0;
::CreateThread(0, 0, &SystemThread, this, 0, &dwID);
}
public:
CCallFunc::Queue m_queue;
private:
__int64 m_timeout;
static CWorkThread thisThread;
};
class CPopupWindow;
struct PopupWndCreateContext : public CCreateContext {
CPopupWindow* popup;
CString clsname;
CString wndname;
DWORD style;
DWORD exstyle;
CRect rc;
HWND parent;
UINT id;
};
class CPopupWindow : public CWnd
{
public:
int Show()
{
HWND hParent = 0;
CWinApp* pApp = NULL;
CWnd* pMain;
if ((pApp = ::AfxGetApp()) != 0 && (pMain = pApp->GetMainWnd()) != 0) {
hParent = pMain->m_hWnd;
}
Create(800, 600, hParent);
}
private:
int Create(int iWidth, int iHeight, HWND parent)
{
PopupWndCreateContext ctxt;
ctxt.popup = this;
ctxt.clsname = "AlertCtrl";
ctxt.wndname = "Alert Control";
ctxt.style = WS_VISIBLE | WS_POPUP;
ctxt.exstyle = 0;
ctxt.rc = CRect(0, 0, iWidth, iHeight);
ctxt.parent = parent;
ctxt.id = 10000;
CWorkThread* pThread;
int e;
if (SUCCEEDED(e = CWorkThread::Aquire(pThread)) && SUCCEEDED(e = pThread->Start(&Run, &ctxt))) {
for (__int64 t = 0; t < POPUPWND_POLLTIMEOUT; t += POPUPWND_POLLPERIOD) {
if (::IsWindow(*this))
return 0;
CWorkThread::Sleep(POPUPWND_POLLPERIOD);
}
}
}
static int Run(const CCallFunc &cf)
{
int e = 0;
PopupWndCreateContext& ctxt = *(static_cast<PopupWndCreateContext*>(cf.GetData()));
ASSERT(&ctxt != 0);
CPopupWindow &wnd = *ctxt.popup;
static const DWORD clsstyle = CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW;
static const HCURSOR clscursor = ::LoadCursor(0, IDC_WAIT);
static const HICON clsicon = 0;
static LPCTSTR clsname = ::AfxRegisterWndClass(clsstyle, clscursor, NULL, clsicon);
if (wnd.CreateEx(DWORD(ctxt.exstyle), ctxt.clsname, ctxt.wndname, DWORD(ctxt.style), ctxt.rc.left, ctxt.rc.top, ctxt.rc.Width(), ctxt.rc.Height(), ctxt.parent, HMENU(ctxt.id), 0) != 0) {
HWND hwnd = wnd.GetSafeHwnd();
::UpdateWindow(hwnd);
MSG msg;
while ((::GetMessage(&msg, 0, 0, 0))) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
wnd.DestroyWindow();
}
return e;
}
};
class CAlertCtrl : CPopupWindow
{
CProgressCtrl m_progctrl;
DECLARE_MESSAGE_MAP();
int OnCreate(LPCREATESTRUCT cs)
{
int e = 0; //< error code / return value
if ((e = __super::OnCreate(cs)) != 0)
return e;
if (!::IsWindow(m_progctrl))
{
CRect rc;
GetClientRect(rc);
if (m_progctrl.Create(WS_CHILD | WS_VISIBLE | PBS_SMOOTH, rc, this, 100000))
m_progctrl.SetRange(0, 10000);
}
return e;
}
};
BEGIN_MESSAGE_MAP(CAlertCtrl, CPopupWindow)
ON_WM_CREATE()
END_MESSAGE_MAP()
So while executing m_progctrl.Create it crashes in the Wincore.cpp
at the method CWnd::DefWindowProc trying to execute callWindowProc after calling the method CPopupWindow::Show for the 35th Cycle.
/////////////////////////////////////////////////////////////////////////////
// Default CWnd implementation
LRESULT CWnd::DefWindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
{
if (m_pfnSuper != NULL)
return ::CallWindowProc(m_pfnSuper, m_hWnd, nMsg, wParam, lParam);

Using callback function in a directshow filter cause memory leaks

I am using third party API which I get streams from a callback function
int OnNewImage(BYTE *pData, int nLen)
When I run a simple C++ sample program from console
int continue = 1;
int OnNewImage(BYTE *pData, int nLen)
{
std::cout << "On new image is called" << std::endl;
return continue;
}
int main()
{
// This will block
int result = DownloadStream(/*params*/...,OnNewImage /*callbackfunction*/);
return 0;
}
I get no memory leaks.[ memory does not increase ]
But When I use this callback function in a directshow filter, it
produce memory leaks.[ memory increase regularly]
What may cause this? And how can I fix it? Any ideas?
UPDATE: My DirectShow Filter structure
What I do:
Basically
I get streams at "unsigned __stdcall DVRStreamThread(LPVOID
pvParam)" function which call back OnNewImage
Then i insert frames into my queue inside that callback[OnNewImage]
Finally At FillBuffer I consume frames from queue.
It is am h264 stream. I can able to set simple graph like this
MySourceFilter ---> H264 Decoder ---> Video Renderer
Here is my FilterSourceCode:
Well I have a simple queue which i insert incoming frames then consume:
SynchronisedQueue
template <typename T>
class SynchronisedQueue
{
public:
void Enqueue(const T& data)
{
boost::unique_lock<boost::mutex> lock(queueMutex);
dataQueue.push(data);
conditionVariable.notify_one();
}
T Dequeue()
{
boost::unique_lock<boost::mutex> lock(queueMutex);
while (dataQueue.size()==0)
{
conditionVariable.wait(lock);
}
T result=dataQueue.front(); dataQueue.pop();
return result;
}
int Size()
{
boost::unique_lock<boost::mutex> lock(queueMutex);
int size = dataQueue.size();
return size;
}
private:
std::queue<T> dataQueue;
boost::mutex queueMutex;
boost::condition_variable conditionVariable;
};
Then My Filter:
DvrSourceFilter [ header]
#define DVRSourceFilterName L"DVRDirectShowFilter"
#include <streams.h>
#include <process.h>
#include <MyDvrApi.h>
#include "SynchronisedQueue.h"
// {F89A85DA-F77C-4d44-893B-CCA43A49E7EF}
DEFINE_GUID(CLSID_DVRSourceFilter,
0xf89a85da, 0xf77c, 0x4d44, 0x89, 0x3b, 0xcc, 0xa4, 0x3a, 0x49, 0xe7, 0xef);
class DECLSPEC_UUID("34363248-0000-0010-8000-00AA00389B71") Subtype_H264;
class DVRSourceFilter;
using namespace std;
/*
* **********************
* DVRPin
* **********************
*/
class DVRPin : public CSourceStream
{
public:
DVRPin(HRESULT *phr, DVRSourceFilter *pFilter);
~DVRPin();
// Override the version that offers exactly one media type
HRESULT GetMediaType(CMediaType *pMediaType);
HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pRequest);
HRESULT FillBuffer(IMediaSample *pSample);
static int OnNewImage(void *pUser, BYTE *pData, int nLen, int nCh, int tMts, int nType, void *returnHandle);
// Setters
void SetDvrIp(char* dvrIp);
void SetDvrPort( int dvrPort);
void SetDvrUserName( char * userName);
void SetDvrPassword(char* password);
void SetStartTime(int startTime);
void SetMilliSecond(int milliSecond);
void SetChannelNumber(int channelNumber);
void SetSize(int width, int height);
// Getters
char* GetDvrIp();
int GetDvrPort();
char* GetDvrUserName();
char* GetDvrPassword();
int GetStartTime();
int GetMilliSecond();
int GetChannelNumber();
int GetMode();
public:
char* dvrIp;
int dvrPort;
char* userName;
char* password;
int startTime;
int milliSecond;
int channelNumber;
BITMAPINFOHEADER m_bmpInfo;
BYTE* m_RGB24Buffer;
DWORD m_RGB24BufferSize;
bool streamCompleted;
int hDecHandle;
HANDLE m_hDVRStreamThreadHandle;
unsigned int m_dwThreadID;
SynchronisedQueue<std::vector<BYTE>> IncomingFramesQueue;
protected:
virtual HRESULT OnThreadCreate();
virtual HRESULT OnThreadDestroy();
virtual HRESULT DoBufferProcessingLoop();
};
/*
* **********************
* DVRSourceFilter
* *********************
*
*/
class DVRSourceFilter : public CSource
{
public:
DECLARE_IUNKNOWN;
static CUnknown * WINAPI CreateInstance(IUnknown *pUnk, HRESULT *phr);
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv);
void SetDVRLiveParameters(char* dvrIP, int dvrPort, char* userName, char* password, int channelNumber, int width, int height);
private:
DVRSourceFilter(IUnknown *pUnk, HRESULT *phr);
~DVRSourceFilter();
private:
DVRPin *m_pPin;
};
DvrSourceFilter [implementation]
#include "DvrSourceFilter.h"
unsigned __stdcall DVRStreamThread(LPVOID pvParam)
{
DVRPin* streamReader = (DVRPin*)pvParam;
int channelBits = 1 << (streamReader->channelNumber - 1);
streamReader->m_RGB24BufferSize = streamReader->m_bmpInfo.biWidth * streamReader->m_bmpInfo.biHeight * 3;
streamReader->m_RGB24Buffer = (BYTE*)malloc(streamReader->m_RGB24BufferSize);
DownloadStream((LPCTSTR)streamReader->dvrIp,
streamReader->dvrPort , (LPCTSTR)streamReader->userName ,
(LPCTSTR)streamReader->password , channelBits, channelBits,
streamReader->startTime, streamReader->milliSecond,
streamReader->OnNewImage, (void*)streamReader);
streamReader->startTime = -2; // End Of Stream
return 0;
}
/*
* ******************
* DVRPin Class
* ******************
*/
DVRPin::DVRPin(HRESULT *phr, DVRSourceFilter *pFilter)
: CSourceStream(NAME("DVR Source Bitmap"), phr, pFilter, L"Out")
{
m_bmpInfo.biSize = sizeof(BITMAPINFOHEADER);
m_bmpInfo.biCompression = BI_RGB;
m_bmpInfo.biBitCount = 24;
m_bmpInfo.biPlanes = 1;
m_bmpInfo.biClrImportant = 0;
m_bmpInfo.biClrUsed = 0;
m_bmpInfo.biXPelsPerMeter = 0;
m_bmpInfo.biYPelsPerMeter = 0;
hDecHandle = 0;
m_RGB24Buffer = NULL;
m_RGB24BufferSize = 0;
streamCompleted = false;
startTime = -1; // Live Stream
*phr = S_OK;
}
DVRPin::~DVRPin()
{
}
int DVRPin::OnNewImage(void *pUser, BYTE *pData, int nLen, int nCh, int tMts, int nType, void *returnHandle)
{
DVRPin* reader = (DVRPin*)pUser;
if(reader->streamCompleted)
{
return false;
}
if(pData)
{
std::vector<BYTE> vecFrame(pData, pData + nLen/sizeof(pData[0]));
reader->IncomingFramesQueue.Enqueue(vecFrame);
}
return !reader->streamCompleted;
}
HRESULT DVRPin::OnThreadCreate()
{
m_hDVRStreamThreadHandle =
(HANDLE)_beginthreadex(NULL, 0, &DVRStreamThread, (void*)this, 0, &m_dwThreadID);
return S_OK;
}
HRESULT DVRPin::OnThreadDestroy() {
streamCompleted = true;
_endthreadex(0);
CloseHandle(m_hDVRStreamThreadHandle);
return S_OK;
}
HRESULT DVRPin::GetMediaType(CMediaType *pMediaType)
{
CAutoLock cAutoLock(m_pFilter->pStateLock());
CheckPointer(pMediaType, E_POINTER);
VIDEOINFOHEADER* pvi = (VIDEOINFOHEADER*)pMediaType->AllocFormatBuffer(sizeof(VIDEOINFOHEADER));
if (pvi == 0)
return(E_OUTOFMEMORY);
ZeroMemory(pvi, pMediaType->cbFormat);
pvi->bmiHeader = m_bmpInfo;
pvi->bmiHeader.biSizeImage = GetBitmapSize(&pvi->bmiHeader);
SetRectEmpty(&(pvi->rcSource));
SetRectEmpty(&(pvi->rcTarget));
pMediaType->SetType(&MEDIATYPE_Video);
pMediaType->SetFormatType(&FORMAT_VideoInfo);
pMediaType->SetTemporalCompression(FALSE);
// Work out the GUID for the subtype from the header info.
const GUID SubTypeGUID = __uuidof(Subtype_H264);//GetBitmapSubtype(&pvi->bmiHeader);
pMediaType->SetSubtype(&SubTypeGUID);
pMediaType->SetSampleSize(pvi->bmiHeader.biSizeImage);
return S_OK;
}
HRESULT DVRPin::DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pRequest)
{
HRESULT hr;
CAutoLock cAutoLock(m_pFilter->pStateLock());
CheckPointer(pAlloc, E_POINTER);
CheckPointer(pRequest, E_POINTER);
VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER*) m_mt.Format();
if (pRequest->cBuffers == 0)
{
pRequest->cBuffers = 2;
}
pRequest->cbBuffer = pvi->bmiHeader.biSizeImage;
ALLOCATOR_PROPERTIES Actual;
hr = pAlloc->SetProperties(pRequest, &Actual);
if (FAILED(hr))
{
return hr;
}
if (Actual.cbBuffer < pRequest->cbBuffer)
{
return E_FAIL;
}
return S_OK;
}
HRESULT DVRPin::FillBuffer(IMediaSample *pSample)
{
if(!streamCompleted)
{
CAutoLock cAutoLock(m_pLock);
HRESULT hr;
BYTE* pData = NULL;
hr = pSample->GetPointer(&pData);
if(FAILED(hr))
{
pSample->Release();
return hr;
}
if(IncomingFramesQueue.Size() <= 0) {
return S_OK;
}
vector<BYTE> data = IncomingFramesQueue.Dequeue();
int dataSize = (int)data.size();
if(dataSize <= 0 || dataSize > 1000000)
{
return S_OK;
}
memcpy(pData, &data[0], dataSize);
hr = pSample->SetActualDataLength(dataSize);
if(FAILED(hr))
{
pSample->Release();
return hr;
}
hr = pSample->SetSyncPoint(TRUE);
if(FAILED(hr))
{
pSample->Release();
return hr;
}
pSample->Release();
}
return S_OK;
}
HRESULT DVRPin::DoBufferProcessingLoop() {
Command com;
REFERENCE_TIME rtNow = 0L;
REFERENCE_TIME rtAdvise = 0L;
OnThreadStartPlay();
do {
while (!streamCompleted && !CheckRequest(&com)) {
IncomingFramesQueue.WaitUntilHaveElements();
IMediaSample *pSample;
HRESULT hr = GetDeliveryBuffer(&pSample,NULL,NULL,FALSE);
if (FAILED(hr)) {
continue; // go round again. Perhaps the error will go away
// or the allocator is decommited & we will be asked to
// exit soon.
}
hr = FillBuffer(pSample);
if (hr == S_OK) {
Deliver(pSample);
} else if (hr == S_FALSE) {
pSample->Release();
DeliverEndOfStream();
return S_FALSE;
} else {
// Log Error
}
pSample->Release();
}
if (com == CMD_RUN || com == CMD_PAUSE)
com = GetRequest(); // throw command away
else if (com != CMD_STOP)
{
// Log Error
}
} while (!streamCompleted && com != CMD_STOP);
return S_OK;
}
void DVRPin::SetDvrIp( char* dvrIp )
{
this->dvrIp = dvrIp;
}
void DVRPin::SetDvrPort( int dvrPort )
{
this->dvrPort = dvrPort;
}
void DVRPin::SetDvrUserName( char * userName )
{
this->userName = userName;
}
void DVRPin::SetDvrPassword( char* password )
{
this->password = password;
}
void DVRPin::SetStartTime( int startTime )
{
this->startTime = startTime;
}
void DVRPin::SetMilliSecond( int milliSecond )
{
this->milliSecond = milliSecond;
}
void DVRPin::SetSize(int width, int height) {
m_bmpInfo.biWidth = width;
m_bmpInfo.biHeight = height;
m_bmpInfo.biSizeImage = GetBitmapSize(&m_bmpInfo);
}
char* DVRPin::GetDvrIp()
{
return dvrIp;
}
int DVRPin::GetDvrPort()
{
return dvrPort;
}
char* DVRPin::GetDvrUserName()
{
return userName;
}
char* DVRPin::GetDvrPassword()
{
return password;
}
int DVRPin::GetStartTime()
{
return startTime;
}
int DVRPin::GetMilliSecond()
{
return milliSecond;
}
void DVRPin::SetChannelNumber( int channelNumber )
{
this->channelNumber = channelNumber;
}
int DVRPin::GetChannelNumber()
{
return channelNumber;
}
/*
* ****************************
* DVRSourceFilter Class
* ***************************
*/
DVRSourceFilter::DVRSourceFilter(IUnknown *pUnk, HRESULT *phr)
: CSource(NAME("DVRSourceBitmap"), pUnk, CLSID_DVRSourceFilter)
{
// The pin magically adds itself to our pin array.
m_pPin = new DVRPin(phr, this);
// Just for test at graph studio
SetDVRLiveParameters("192.168.3.151", 7000, "admin", "000000", 3, 352, 288);
if (phr)
{
if (m_pPin == NULL)
*phr = E_OUTOFMEMORY;
else
*phr = S_OK;
}
}
DVRSourceFilter::~DVRSourceFilter()
{
delete m_pPin;
}
CUnknown * WINAPI DVRSourceFilter::CreateInstance(IUnknown *pUnk, HRESULT *phr)
{
DVRSourceFilter *pNewFilter = new DVRSourceFilter(pUnk, phr);
if (phr)
{
if (pNewFilter == NULL)
*phr = E_OUTOFMEMORY;
else
*phr = S_OK;
}
return pNewFilter;
}
STDMETHODIMP DVRSourceFilter::NonDelegatingQueryInterface( REFIID riid, void **ppv )
{
return CSource::NonDelegatingQueryInterface(riid, ppv);
}
void DVRSourceFilter::SetDVRLiveParameters( char* dvrIP, int dvrPort, char* userName, char* password, int channelNumber, int width, int height )
{
m_pPin->SetDvrIp(dvrIP);
m_pPin->SetDvrPort(dvrPort);
m_pPin->SetDvrUserName(userName);
m_pPin->SetDvrPassword(password);
m_pPin->SetChannelNumber(channelNumber);
m_pPin->SetStartTime(-1);// Live Stream
m_pPin->SetMilliSecond(0);
m_pPin->SetSize(width, height);
}
...
To make directshow Filter simple [ to understand memory leak source], just implement OnNewImage function and FillBufferFunction as "dummy", but still has memory leak:
int DVRPin::OnNewImage(void *pUser, BYTE *pData, int nLen, int nCh, int tMts, int nType, void *returnHandle)
{
return 1; // for not to end call back
}
HRESULT DVRPin::FillBuffer(IMediaSample *pSample)
{
pSample->Release();
return S_OK;
}
In DVRStreamThread, you have:
streamReader->m_RGB24Buffer = (BYTE*)malloc(streamReader->m_RGB24BufferSize);
But I don't see a matching call to free() anywhere. When your DVRPin object is deleted, you will have to explicitly free the data pointed to by its m_RGB24Buffer member.
First thing I see, is that your destructors are not virtual. This might be a cause of leaks when release is not taking place when inheritance is used. See related article about the necessity of virtual destructors.

JNI: Sink Object not Firing, Releases freezing

I am trying to create a JNI wrapper for this windows application called 'Personal Communications' through a COM Object that it supplies. PCOM Help
Through lots of googling, I have managed alot on my own. I can suffessfully connect to the COM Object and run getter/setter methods to retrieve various info on the application.
My problem is now with Sink Objects (trying to get the application to send me events).
As far as I can tell, everything is returning a good return code, but the Invoke on the Sink Class is never called. Whats worse, if a Event was suppose to be called, Releasing the COM object that told it to start sending events, hangs the application. If I end the application advising it of the sink but not making it fire any events, the application doesn't hang.
I have tried various methods and compilers. They all give the same result. Whats weird though, if I use the same code in an actual application (exe) outside of Java, everything works fine and the Events are fired through the Sink Object. So I am truly at a lost for whats wrong with Java in the picture.
Here is my code I have so far:
PcommControl.h (My Wrapper for controlling the COMs)
initConnectionManagerEvents: creates a new sink object and advises the COM of it. RegisterStartEvent tells the COM to start sending messages to the sink objects.
removeConnectionManagerEvents: unadvises and removes all sink objects. UnregisterStartEvent tells the COM to stop sending messages to the sink objects.
jobject PcommControl::initConnectionManagerEvents(jobject sinkType) {
if (!initConnectionManager())
return NULL;
if (autConnectionManagerPoint == NULL) {
autConnectionManagerPoint = getConnectionPoint(autConnectionManager,
DIID_IStartEvent);
if (autConnectionManagerPoint == NULL)
return NULL;
}
ConnectionSink *conSinkC = new ConnectionSink(jvm, sinkType);
if (!conSinkC->isInitialized()) {
delete conSinkC;
return NULL;
}
if (!conSinkC->Advise(autConnectionManagerPoint)) {
#ifdef DEBUG
printf("PcommControl: failed to advise ConnectionManagerEvent\n");
#endif
delete conSinkC;
return NULL;
}
#ifdef DEBUG
printf("PcommControl: ConnectionManagerEvent> %ld\n", conSinkC->getCookie());
#endif
ConnectionSink *temp = connectionManagerEvents.put(
(long) conSinkC->getCookie(), conSinkC);
if (temp) {
temp->Release();
}
if (connectionManagerEvents.getSize() == 1) {
#ifdef DEBUG
printf("PcommControl: Registering ConnectionManagerEvent\n");
#endif
HRESULT hresult = autConnectionManager->RegisterStartEvent();
if (!SUCCEEDED(hresult)) {
#ifdef DEBUG
printf("Failed to get RegisterStartEvent\n");
#endif
// TODO
}
}
return conSinkC->getJavaObjectConnection();
}
void PcommControl::removeConnectionManagerEvents() {
ConnectionSink *connectionSink;
if ((autConnectionManager) && (!safeUnload)) {
#ifdef DEBUG
printf("PcommControl: Unregistering ConnectionManagerEvent\n");
#endif
// TODO: seems to cause hanging issues for Java
HRESULT hresult = autConnectionManager->UnregisterStartEvent();
if (!SUCCEEDED(hresult)) {
#ifdef DEBUG
printf("Failed to UnregisterStartEvent\n");
#endif
}
}
while ((connectionSink = connectionManagerEvents.removeHead()) != NULL) {
if (!safeUnload) {
#ifdef DEBUG
printf("PcommControl: releasing a connection manager event\n");
#endif
connectionSink->Unadvise();
#ifdef DEBUG
printf("PcommControl: start release\n");
#endif
connectionSink->Release();
}
}
#ifdef DEBUG
printf("PcommControl: done releasing ConnectionManager events\n");
#endif
}
JNIEventSink.h (My Sink Interface for all JNI Sinks)
#ifndef JNIEVENTSINK_H_
#define JNIEVENTSINK_H_
#include <jni.h>
#include <OCIdl.h>
#define FARFAR FAR* FAR*
class JNIEventSink: public IDispatch {
protected:
private:
bool initialized;
bool deconstructor;
DWORD referenceCount;
JavaVM *jvm;
jobject javaObjectConnection;
DWORD cookie;
IConnectionPoint *point;
static jclass javaLangClass;
static jmethodID javaLangClassNewInstance;
void init(JavaVM *javaVM, jobject sinkType) {
initialized = false;
deconstructor = false;
referenceCount = 0;
jvm = javaVM;
javaObjectConnection = NULL;
cookie = 0;
AddRef();
// create Java sink class from sinkType
// if (javaVM) {
// JNIEnv *env;
// javaVM->AttachCurrentThread((void **) &env, NULL);
// if (env == NULL) {
//#ifdef DEBUG
// printf("JNIEventSink: java environment not found!\n");
//#endif
// return;
// }
//
// if (javaLangClass == NULL) {
// javaLangClass = NULL;
// javaLangClassNewInstance = NULL;
//
// javaLangClass = env->FindClass("java/lang/Class");
// if (javaLangClass == NULL) {
//#ifdef DEBUG
// printf("JNIEventSink: javaLangClass not found!\n");
//#endif
// return;
// }
// javaLangClassNewInstance = env->GetMethodID(javaLangClass,
// "newInstance", "()Ljava/lang/Object;");
// if (javaLangClassNewInstance == NULL) {
//#ifdef DEBUG
// printf(
// "JNIEventSink: javaLangClass NewInstance not found!\n");
//#endif
// return;
// }
// }
//
// javaObjectConnection = env->CallObjectMethod(sinkType,
// javaLangClassNewInstance);
// if (javaObjectConnection == NULL) {
//#ifdef DEBUG
// printf(
// "JNIEventSink: Failed to create new Connection Object!\n");
//#endif
// return;
// }
// }
initialized = true;
}
public:
bool test;
JNIEventSink(JavaVM *javaVM, jobject sinkType) {
#ifdef DEBUG
printf("JNIEventSink: constructor\n");
#endif
init(javaVM, sinkType);
test = false;
}
virtual ~JNIEventSink() {
#ifdef DEBUG
printf("JNIEventSink: deconstructor\n");
if (test)
printf("YESYESYESYESYESYESYESYES\n");
#endif
deconstructor = true;
//
// if (point != NULL)
// Unadvise();
//
// if (referenceCount > 0)
// Release();
}
bool isInitialized() {
return initialized;
}
bool Advise(IConnectionPoint *point) {
#ifdef DEBUG
printf("JNIEventSink: Start Advise\n");
#endif
this->point = point;
this->point->AddRef();
HRESULT hresult = point->Advise(this, &cookie);
// TODO set cookie to java class
#ifdef DEBUG
printf("JNIEventSink: Advise End\n");
if (!SUCCEEDED(hresult))
printf("JNIEventSink: failed\n");
#endif
return SUCCEEDED(hresult);
}
bool Unadvise() {
#ifdef DEBUG
printf("JNIEventSink: Start Unadvise\n");
#endif
if (point == NULL)
return true;
IConnectionPoint *point = this->point;
this->point = NULL;
HRESULT hresult = point->Unadvise(cookie);
point->Release();
#ifdef DEBUG
printf("JNIEventSink: Unadvise End\n");
if (!SUCCEEDED(hresult))
printf("JNIEventSink: failed\n");
#endif
return SUCCEEDED(hresult);
}
DWORD getCookie() {
return cookie;
}
jobject getJavaObjectConnection() {
return javaObjectConnection;
}
ULONG
STDMETHODCALLTYPE AddRef() {
#ifdef DEBUG
printf("JNIEventSink: Add Ref %ld,%ld,%ld\n", (long) this, cookie,
referenceCount);
#endif
referenceCount++;
return referenceCount;
}
ULONG
STDMETHODCALLTYPE Release() {
#ifdef DEBUG
printf("JNIEventSink: Start Release %ld,%ld,%ld\n", (long) this,
cookie, referenceCount);
#endif
if (referenceCount == 0) {
#ifdef DEBUG
printf("0 ref\n");
#endif
return 0;
}
referenceCount--;
long temp = referenceCount;
if ((temp == 0) && (!deconstructor)) {
#ifdef DEBUG
printf("JNIEventSink: deleting\n");
#endif
delete this;
}
return temp;
}
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid,
void **ppvObject) {
#ifdef DEBUG
printf("JNIEventSink: QueryInterface %ld,%ld\n", (long) this, cookie);
#endif
if (iid == IID_IUnknown) {
*ppvObject = (IUnknown *) this;
} else if (iid == IID_IDispatch) {
*ppvObject = (IDispatch *) this;
} else {
*ppvObject = (void *) this;
}
((IUnknown *) (*ppvObject))->AddRef();
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT *pctinfo) {
#ifdef DEBUG
printf("JNIEventSink: GetTypeInfoCount %ld,%ld\n", (long) this, cookie);
#endif
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid,
LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) {
#ifdef DEBUG
printf("JNIEventSink: GetIDsOfNames %ld,%ld\n", (long) this, cookie);
#endif
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(unsigned int iTInfo,
LCID lcid, ITypeInfo FARFAR ppTInfo) {
#ifdef DEBUG
printf("JNIEventSink: GetTypeInfo %ld,%ld\n", (long) this, cookie);
#endif
return E_NOTIMPL;
}
// virtual HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid,
// LCID lcid, WORD wFlags, DISPPARAMS FAR* pDispParams,
// VARIANT FAR* pVarResult, EXCEPINFO FAR* pExcepInfo,
// unsigned int FAR* puArgErr) = 0;
};
jclass JNIEventSink::javaLangClass = NULL;
jmethodID JNIEventSink::javaLangClassNewInstance = NULL;
#endif /* JNIEVENTSINK_H_ */
ConnectionSink.h (My Implementation of the JNI Sink that is suppose to get all Events from autConnectionManager)
#ifndef CONNECTIONSINK_H_
#define CONNECTIONSINK_H_
#include <jni.h>
#include "PcommInterfaces.h"
#include "..\COM\JNIEventSink.h"
class ConnectionSink: public JNIEventSink {
private:
public:
ConnectionSink(JavaVM *javaVM, jobject sinkType) :
JNIEventSink(javaVM, sinkType) {
}
virtual ~ConnectionSink() {
#ifdef DEBUG
printf("ConnectionSink: deconstructor\n");
#endif
}
// IStartEvent
// future events I want to call
// 1 - void NotifyStartEvent(VARIANT ConnHandle, VARIANT_BOOL bStarted);
// 2 - void NotifyStartError(VARIANT ConnHandle);
// 3 - void NotifyStartStop(int* Reason);
virtual HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS FAR* pDispParams,
VARIANT FAR* pVarResult, EXCEPINFO FAR* pExcepInfo,
unsigned int FAR* puArgErr) {
// TODO this seems like it is never called
#ifdef DEBUG
printf("ConnectionSink: Invoke %ld,%ld,%ld\n", (long) this,
this->getCookie(), dispIdMember);
#endif
test = true;
return S_OK;
//return E_NOTIMPL;
}
};
#endif /* CONNECTIONSINK_H_ */
Example output when it hangs:
Java_gov_ssa_utils_pcomm_ConnectionManager_registerStartEvents
JNIEventSink: constructor
JNIEventSink: Add Ref 72880304,0,0
JNIEventSink: Start Advise
JNIEventSink: Add Ref 72880304,0,1
JNIEventSink: Advise End
PcommControl: ConnectionManagerEvent> 1
PcommControl: Registering ConnectionManagerEvent
Created and attached sink.
Waiting 10 seconds for user to fire event
Destroying.
Java_gov_ssa_utils_PComm_release
PcommControl: destroying
PcommControl: Unregistering ConnectionManagerEvent
Thanks for any help.
I figured out my problem.
The thread that created the sink object needs to also pump the thread's message queue using the window's function 'GetMessage'.
This is why the windows executable was working correctly, it already have a message pump for the window that was created. I figured this out when I put a breakpoint in the sink object when the invoke was being called and looked at the stack trace. 'GetMessage' was the first thing on the trace that came from my code.
In this instance, I believe why 'GetMessage' is the answer is because I believe the COM's code is calling 'PostThreadMessage' to notify me that a sink event has occurred and 'GetMessage' looks at these messages and somehow knows they are COM related and handle them on its own.
PS: Notice I said the thread that created the sink. If you create the sink in one thread and have the message pump in another, you will receive the message from the COM about the sink, but it won't know how to handle it automatically since this thread has nothing loaded about the COM in its space. So the sink object's invoke is never called.
So Java could access the same COM everywhere, I made the 2nd thread control everything about the COM, and any native methods that were called redirect the request to the that thread. So no matter what thread Java is running in, it will always have access to the same COM without having to reload everything.

how to embed dll in vc++? how to extract that emeded dll to local drive? how to create tlb file based on the dll runtime?

I am working with vb.net .. I am new in vc++. I need to write some code in vc++ in some case. I need vc++ for following reason.
I created one dll in vb.net and make a tlb file based on vb.net dll. I import physical tlb file in my vc++ code with static value, as mentioned following.
#import "C:\Documents and Settings\Ankit.ass\My Documents\Visual Studio 2010\Projects\SetupValidationPro\SetupValidationPro\bin\Debug\SetupValidationPro.tlb" named_guids raw_interfaces_only
That's work fine.. My problem is that, I want to create a tlb file dynamically or runtime using vc++ and load that tlb file dynamically.
So, I need to embed a dll in vc++. How can I embed dll in vc++?
Now, I want to extract my embed dll to some physical file. so how can I extract my dll to physical location in vc++?
And, at the last step I want to create a tlb file dynamically using that extracted dll using vc++.. and load tlb file dynamically.
How can I achieve this?
Thanks
Ankit
I resolve the issue after lots of googling.. This is the code from where my issue is resolve. I don't need native code for this..
#include "stdafx.h"
#include "stdafx.h"
#include <Msi.h>
#include <WinUser.h>
#include "windows.h"
#include <afxwin.h>
#include <afx.h>
#include <WinSpool.h>
#include <assert.h>
#include <WinBase.h>
#include "resource.h"
#define IDR_DLL1 101
#define IDR_EXE1 102
bool ExtractDll(const HINSTANCE hInstance, WORD resourceID, LPCTSTR szOutputFilename);
bool ExtractExe(const HINSTANCE hInstance, WORD resourceID, LPCTSTR szOutputFilename);
bool cmd();
CString AppPath();
#define RtlCopyMemory(Destination,Source,Length) memcpy((Destination),(Source),(Length))
#import "dv.tlb" named_guids raw_interfaces_only
using namespace dv;
UINT __stdcall Validation( MSIHANDLE hModule )
{
/*BOOL qw = ExtractDll(AfxGetResourceHandle(), IDR_DLL1, _T("C:\\VBDLL.dll") );
BOOL qw1 = ExtractExe(AfxGetResourceHandle(), IDR_EXE1, _T("C:\\RegAsm.exe") );*/
BOOL qw = ExtractDll(AfxGetResourceHandle(), IDR_DLL1, (LPCTSTR)(AppPath() + _T("\\dv.dll")) );
if (qw == false)
{
return ERROR_INSTALL_USEREXIT;
}
BOOL qw1 = ExtractExe(AfxGetResourceHandle(), IDR_EXE1, (LPCTSTR)(AppPath() + _T("\\RegAsm.exe")) );
if (qw1 == false)
{
return ERROR_INSTALL_USEREXIT;
}
BOOL retCmd = cmd();
if (retCmd==false)
{
return ERROR_INSTALL_USEREXIT;
}
IkeyvalidationPtr pICalc(__uuidof(SetupClass));
long retun =0;
BSTR strVer = SysAllocString(L"4.0.1517");
pICalc->keyValidation(strVer,&retun);
if (retun==1)
{
return ERROR_INSTALL_USEREXIT;
}
return ERROR_SUCCESS;
}
CString AppPath()
{
try
{
TCHAR path [MAX_PATH];
ITEMIDLIST* pidl;
HRESULT hRes = SHGetSpecialFolderLocation( NULL, CSIDL_APPDATA|CSIDL_FLAG_CREATE , &pidl );
if (hRes==NOERROR)
{
SHGetPathFromIDList( pidl, path);
}
CString apPath;
apPath = path;
apPath = apPath + _T("\\path");
CreateDirectory((LPCWSTR) apPath,NULL);
return apPath;
}
catch(...)
{
}
}
bool cmd()
{
CString m1=_T('');
CString temp1 = _T("");
CString temp = temp1 + _T('"');
//CString s1 = temp + AppPath() + _T("\\RegAsm.exe"); // Cascading concatenation
CString s1 = temp + AppPath() + _T("\\RegAsm.exe") + _T('"'); // Cascading concatenation
CString s2 = _T(" /codebase");
CString message = s1 + _T('"')+ _T(' ')+ _T('"') + AppPath() + _T("\\dv.dll") + _T('"') +_T(' ') + _T("/tlb:")+('"') + AppPath() + _T("\\dv.tlb") + _T('"')+ s2;
CString message1 = _T('"') + AppPath() + _T("\\dv.dll") + _T('"') +_T(' ') + _T("/tlb:")+('"') + AppPath() + _T("\\dv.tlb") + _T('"')+ s2;
SHELLEXECUTEINFO ExecuteInfo;
memset(&ExecuteInfo, 0, sizeof(ExecuteInfo));
ExecuteInfo.cbSize = sizeof(ExecuteInfo);
ExecuteInfo.fMask = 0;
ExecuteInfo.hwnd = 0;
ExecuteInfo.lpVerb = L"runas"; // Operation to perform
ExecuteInfo.lpFile = s1;
ExecuteInfo.lpParameters = message1; // Additional parameters
ExecuteInfo.lpDirectory = 0; // Default directory
ExecuteInfo.nShow = SW_HIDE;
//ExecuteInfo.nShow = SW_SHOW;
ExecuteInfo.hInstApp = 0;
if(ShellExecuteEx(&ExecuteInfo) == FALSE)
{
return false;
}
return true;
}
bool ExtractDll(const HINSTANCE hInstance, WORD resourceID, LPCTSTR szOutputFilename)
{
TCHAR sResName[5] = _T("#101");
TCHAR sRestype[4] = _T("DLL");
HRSRC hres = FindResource(AfxGetResourceHandle(), sResName,sRestype);
if (hres == 0)
{
return false;
}
HGLOBAL hbytes = LoadResource(hInstance, hres);
// Lock the resource
LPVOID pdata = LockResource(hbytes);
DWORD dwSize = SizeofResource(hInstance, hres);
HANDLE hFile = CreateFile(szOutputFilename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
/// INSERT DATA IN FILE
HANDLE hFilemap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, dwSize, NULL);
LPVOID lpBaseAddress = MapViewOfFile(hFilemap, FILE_MAP_WRITE, 0, 0, 0);
try
{
RtlCopyMemory(lpBaseAddress,pdata,dwSize);
}
catch ( ... )
{
return false;
}
UnmapViewOfFile(lpBaseAddress);
CloseHandle(hFilemap);
CloseHandle(hFile);
return true ;
}
bool ExtractExe(const HINSTANCE hInstance, WORD resourceID, LPCTSTR szOutputFilename)
{
/*LPTSTR sArgv = argv[1];
LPTSTR sArgv2 = argv[2];*/
TCHAR sResName[5] = _T("#102");
TCHAR sRestype[4] = _T("EXE");
//HINSTANCE Nl=AfxGetInstanceHandle();
HRSRC hres = FindResource(AfxGetResourceHandle(), sResName, sRestype);
if (hres == 0)
{
return false;
}
HGLOBAL hbytes = LoadResource(hInstance, hres);
// Lock the resource
LPVOID pdata = LockResource(hbytes);
DWORD dwSize = SizeofResource(hInstance, hres);
HANDLE hFile = CreateFile(szOutputFilename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
/// INSERT DATA IN FILE
HANDLE hFilemap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, dwSize, NULL);
LPVOID lpBaseAddress = MapViewOfFile(hFilemap, FILE_MAP_WRITE, 0, 0, 0);
try
{
RtlCopyMemory(lpBaseAddress,pdata,dwSize);
}
catch ( ... )
{
return false;
}
UnmapViewOfFile(lpBaseAddress);
CloseHandle(hFilemap);
CloseHandle(hFile);
return true;
}
This is the MFC code from which solved my issue. This code embeds the resources, extracts the resources and registers the type library at run-time.

Resources