|
Christian,
I don't have a Menu Group which contains only two items:
1- Visual Studio Tools
2- Microsoft Visual C++ 2005 Express Edition
Khoramdin
|
|
|
|
|
Oh, you have the express edition. That's probably the problem
Christian Graus - C++ MVP
'Why don't we jump on a fad that hasn't already been widely discredited ?' - Dilbert
|
|
|
|
|
Hello,
What edition do I have to have in order to get the Spy++?
Khoramdin
|
|
|
|
|
Khoramdin wrote: What edition do I have to have in order to get the Spy++?
Any of the non-Express editions.
"Approved Workmen Are Not Ashamed" - 2 Timothy 2:15
"Judge not by the eye but by the heart." - Native American Proverb
|
|
|
|
|
The app is called spyxx.exe
You may be right I may be crazy -- Billy Joel --
Within you lies the power for good, use it!!!
|
|
|
|
|
Howdy y'all,
I am using Visual C++ 6.0 MFC. I am writing my first multi-threaded application. The worker thread calls a function in another class that uses automation to create an excel spreadsheet. If I call this function from my primary thread everything works okay, but if I call it from my secondary thread the creation of the spreadsheet fails. Any information on what is happening here would be much appreciated.
Buck
|
|
|
|
|
BuckBrown wrote: the spreadsheet fails
Please provide detailed error information
led mike
|
|
|
|
|
If I call the function from the primary thread -
void CTests::OpenWorksheet()
{
COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
// Start Excel and get the application object
if(!m_App.CreateDispatch("Excel.Application"))
{
AfxMessageBox("Couldn't start Excel and get application object.");
}
}
The call to m_App.CreateDispatch("Excel.Application")) begins to execute the following code -
BOOL COleDispatchDriver::CreateDispatch(LPCTSTR lpszProgID, COleException* pError)
{
ASSERT(m_lpDispatch == NULL);
// map prog id to CLSID
CLSID clsid;
SCODE sc = AfxGetClassIDFromString(lpszProgID, &clsid);
if (FAILED(sc))
{
if (pError != NULL)
pError->m_sc = sc;
return FALSE;
}
// create with CLSID
return CreateDispatch(clsid, pError);
}
As the function executes the values in my debug window are lpszProgID = 0x005902cc "Excel.Application", m_lpDispatch = 0x00000000, pError = 0x00000000 {COleException}, this = 0x00aa0158, &clsid = 0x0012ec4c {CLSID_Microsoft Office Excel Application}, sc = 0, and the CreateDispatch(clsid, pError) function returns a value of 1.
If I call m_App.CreateDispatch("Excel.Application") from the worker thread, the values are all the same but the call to CreateDispatch(clsid, pError) returns a value of 0.
If you want more detail, from the worker thread, the CreateDispatch(clsid, pError) function calls SCODE sc = CoCreateInstance(clsid, NULL, CLSCTX_ALL | CLSCTX_REMOTE_SERVER, IID_IUnknown, (LPLP)&lpUnknown); with values of CLSCTX_REMOTE_SERVER = 16, IID_IUnknown = {IID_IUnknown}, lpUnknown = 0x00000000, &lpUnknown = 0132fbbc. This call returns a value of -2147221008 into sc and then fails.
From the primary thread the value of lpUnknown is 0x0012ec28
From the secondary thread the value of lpUnknown is 0x0132fbbc
Other than this value everthing else is the same.
Thanks
|
|
|
|
|
BuckBrown wrote: This call returns a value of -2147221008 into sc and then fails.
Do you know that HRESULTS can be tested and represent specific errors?
Visual Studio 6 comes with a tool called "Error Lookup". Plug that number into it.
Here is a hint for you, COM must be initialized for each thread it is used in.
led mike
|
|
|
|
|
Thanks Mike,
No I didn't. First and foremost I am NOT a Windows programmer. I come from the UNIX world and everthing Microsoft seems back asswords to me. I have taught myself (with help from people like yourself) just enough MFC programming in the last couple of years to be dangerous, but it has been a real challenge because what experienced Windows programmers take for granted as kindergarten stuff is not really documented very well. I'll play with this angle for a while (it will probably take me a week) and let you know how it went.
Thanks again for getting me off the snide.
Buck
p.s. If you're wondering why a Windows hater is programming in it, it is because that was the compiler on my machine at work and it's the only one I have to develop applications with. I don't want to, I have to.
|
|
|
|
|
|
BuckBrown wrote: I am NOT a Windows programmer. I come from the UNIX world and everthing Microsoft seems back asswords to me. I have taught myself (with help from people like yourself) just enough MFC programming in the last couple of years to be dangerous, but it has been a real challenge because what experienced Windows programmers take for granted as kindergarten stuff is not really documented very well.
Ah, now that is useful information to aid in our communications! So the COM kernel of windows uses thread local storage for some of it's ?whatever? and therefore requires thread based intialization. Use the OleInitialize()[^] and matching uninitialize() to accomplish this in your thread callbacks when you want to use COM routines in a worker thread.
led mike
|
|
|
|
|
Hi,
Yes, not using the CoInitialize() function at the begining of the thread was the problem with not being able to create an Excel worksheet. Thank you all for your help. I didn't know anything at all about COM before, but now I guess I should bone up on it a little bit.
Buck
|
|
|
|
|
Did you initialize the apartment in the worker thread? You must ALWAYS call CoInitialize[Ex]() in a new thread before making ANY COM-calls...
Always take a look at the HRESULTs given by COM-functions. Then put the error code in the "Error Lookup"-tool that comes with Visual Studio (it's in the tools-menu). It can translate most common COM-errors.
Also, don't forget to call CoUninitialize() in your worker thread when it exits.
Good luck!
--
Verletzen zerfetzen zersetzen zerstören
Doch es darf nicht mir gehören
Ich muss zerstören
|
|
|
|
|
Hi,
Yes, not using the CoInitialize() function at the begining of the thread was the problem with not being able to create an Excel worksheet. Thank you all for your help. I didn't know anything at all about COM before, but now I gues I should bone up on it a little bit.
Buck
|
|
|
|
|
In addition to Joergen's reply, you have to marshal your interface into the new apartment.
Spawning a worker thread and not initializing COM by calling ::CoInitialize[Ex]() , is one of the top five mistakes when doing COM. Another one of the top five is using an interface gotten in the primary thread (apartment) without marshalling the interface. If you fail to do this you will get the RPC_E_WRONG_THREAD error.
Usually you marshal an interface by using ::CoMarshalThreadInterfaceInStream() and ::CoGetInterfaceAndReleaseStream() .
Have a look here[^].
I think that by about 95% certainty, the above is your problem.
"It's supposed to be hard, otherwise anybody could do it!" - selfquote
|
|
|
|
|
Hi,
Yes, not using the CoInitialize() function at the begining of the thread was the problem with not being able to create an Excel worksheet. Thank you all for your help. I didn't know anything at all about COM before, but now I gues I should bone up on it a little bit.
Buck
|
|
|
|
|
I've created 2 classes each with it's own dialog box in an MDI application
1. commanding class
2. picViewer class
the commanding class has a func load().
where i create a picViewer variable.
<br />
void commanding::load()<br />
{<br />
UpdateData (TRUE);<br />
<br />
FILE *pic, *pic1, *pic2;<br />
picViewer cam1; <br />
pic = fopen("C:\\cv\\16bit.jp2", "rb");<br />
pic1 = fopen("C:\\cv\\nature_50.jp2", "rb");<br />
pic2 = fopen("C:\\cv\\8_8.jp2", "rb");<br />
unsigned int numRead;<br />
<br />
int i = 0;<br />
while(i < 3)<br />
{<br />
if(i == 0)<br />
numRead = fread(buff, sizeof(BYTE), 100000, pic);<br />
else if(i == 1)<br />
numRead = fread(buff, sizeof(BYTE), 100000, pic1);<br />
else<br />
numRead = fread(buff, sizeof(BYTE), 100000, pic2);<br />
cam1.showPicture(buff,numRead);<br />
i++;<br />
Sleep(2000);<br />
}<br />
<br />
fclose(pic);<br />
fclose(pic1);<br />
fclose(pic2);<br />
UpdateData (FALSE);<br />
}<br />
<br /> the picViewer class has a func show().
<br />
void picViewer::show(BYTE bfr[], DWORD size)<br />
{<br />
HBITMAP m_bitmap = NULL;<br />
CImage image;<br />
CJpeg2kDecoder imDec;<br />
<br />
image = imDec.Open(bfr, size);<br />
m_bitmap = (HBITMAP)image;<br />
m_nCam1img.SetBitmap(m_bitmap); <br />
}<br />
whenever I run the application i open up both dialog boxes hit run on the commanding dialog box i get an error when i get to "m_nCam1img.SetBitmap(m_bitmap); " which points to:
<br />
_AFXWIN_INLINE HBITMAP CStatic::SetBitmap(HBITMAP hBitmap)<br />
{ ASSERT(::IsWindow(m_hWnd)); return (HBITMAP)::SendMessage(m_hWnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap); }<br />
in afxwin2.inl
what does that mean? what am i doing wrong? what would i need to do in order to show a picture in a separate dialog box?
thanks!
Kitty5
|
|
|
|
|
kitty5 wrote: picViewer cam1;
If picViewer is a window or dialog it is never being created therefore the CStatic child window is also never created so IsWindow(m_hWnd) returns false and Asserts during debugging.
led mike
|
|
|
|
|
led mike wrote: kitty5 wrote:
picViewer cam1;
If picViewer is a window or dialog it is never being created therefore the CStatic child window is also never created so IsWindow(m_hWnd) returns false and Asserts during debugging.
picViewer is the class that is related to the picViewer dialog.
I added both
<br />
cam1.Create(IDD_PICVIEWER,0); <br />
cam1.EnableWindow(TRUE);<br />
to my commanding::load() function.
this stops the crashing.
however, no picture is shown in the picViewer dialog box even though i call the show().
<br />
cam1.show(buff,numRead);<br />
Thanks!
-- modified at 14:35 Thursday 1st February, 2007
Kitty5
|
|
|
|
|
kitty5 wrote: picViewer is the class that is related to the picViewer dialog.
I don't know that that means.
In the first code you posted:
void commanding::load()
{
UpdateData (TRUE);
FILE *pic, *pic1, *pic2;
picViewer cam1;
that instance of picViewer is local to that function so it is not related to anything else.
led mike
|
|
|
|
|
led mike wrote: In the first code you posted:
void commanding::load(){UpdateData (TRUE);FILE *pic, *pic1, *pic2;picViewer cam1;
that instance of picViewer is local to that function so it is not related to anything else.
oh... really?!
hmmm. ok then ummm... how would i be able to open up an instance of the picViewer dialog box in the commanding class and be able to update the bitmaps?
i've changed my commanding to:
<br />
int commanding::loadCmdGet3CamData()<br />
{<br />
UpdateData (TRUE);<br />
<br />
FILE *pic, *pic1, *pic2;<br />
picViewer cam1;<br />
pic = fopen("C:\\cv\\16bit.jp2", "rb");<br />
pic1 = fopen("C:\\cv\\nature_50.jp2", "rb");<br />
pic2 = fopen("C:\\cv\\8_8.jp2", "rb");<br />
unsigned int numRead;<br />
cam1.Create(IDD_IMAGEVIEWER,0);<br />
cam1.EnableWindow(TRUE);<br />
int i = 0;<br />
while(i < 3)<br />
{<br />
if(i == 0)<br />
numRead = fread(buff, sizeof(BYTE), 100000, pic);<br />
else if(i == 1)<br />
numRead = fread(buff, sizeof(BYTE), 100000, pic1);<br />
else<br />
numRead = fread(buff, sizeof(BYTE), 100000, pic2);<br />
cam1.showPicture(buff,numRead);<br />
i++;<br />
Sleep(2000);<br />
}<br />
<br />
fclose(pic);<br />
fclose(pic1);<br />
fclose(pic2);<br />
}<br />
thanks,
Kitty5
|
|
|
|
|
What you have posted so far indicates that you lack the basic knowledge required to achieve your goal on purpose. So changing things and trying it might work eventually if you get lucky. There are several good books, there are also some decent sample applications and tutorials available with Visual Studio and/or on msdn.microsoft.com that might help in regards to the fundamental concepts that you are missing. I don't know that I would be capable of providing adequate coverage in a forum.
led mike
|
|
|
|
|
I agree with led mike's response.
I see a misunderstanding of variable scope in your code.
Here's my reply to your other related post:
In your picViewer::show() method:
Your CImage object goes out of scope at the end of the function so it probably destroys the
HBITMAP via its destructor.
Instead of
m_bitmap = (HBITMAP)image;
try
m_bitmap = image.Detach();
and remove this line:
if (m_bitmap) DeleteObject(m_bitmap);
Same with code above: All your variables are local so they no longer exist when the function
ends.
Mark
|
|
|
|
|
Is m_nCam1img on same dialog and when you run m_nCam1img.SetBitmap(m_bitmap); and Is m_nCam1img valid and aslo if you want to load a jpg file you can use of (CImage)
|
|
|
|