Solved

BCB2006 TOpenDialog (and TSaveDialog) problem and missing option

Posted on 2006-07-12
21
897 Views
Last Modified: 2013-11-17
I just got a call from a site where I have an app installed, and a problem was reported to me which I can verify, and cannot find a quick fix.

The problem is using a TOpenDialog (using BCB 2006).  The problem is that drives are not shown - folders, and everything else are shown, but going to "My Computer" gives an empty selection screen.  I couldn't find a flag in Options or OptionsEx which would fix this, either.  I threw a TSaveDialog on the form to test with, it has the same problem.

0
Comment
Question by:sburck
  • 9
  • 8
  • 3
21 Comments
 
LVL 16

Expert Comment

by:George Tokas
ID: 17090821
I made an application in BCB2006 and dropped a TOpenDialog and a TButton.
At Button click I called OpenDialog1->Execute() and run it.
After click at the button the dialog displayed with all drives visible when clicked "My Computer"...
Did you installed the updates??
I had installed them...

George Tokas.
0
 
LVL 3

Author Comment

by:sburck
ID: 17090889
No, I found the solution now at Borland -         

"TOpenDialog doesn't show MyComputer items when CoInitFlags := COINIT_MULTITHREADED"

and, because I require CoInitFlags to be COINIT_MULTITHREADED I will have to replace the dialog boxes with API calls.
0
 
LVL 16

Expert Comment

by:George Tokas
ID: 17103718
Agree since I was of no help....
George Tokas.
0
 
LVL 3

Author Comment

by:sburck
ID: 17120347
First, I will remove my request to close this question - however, I'm going to change it, and increase it's points, because it has now become considerably more difficult.

After a lot of research, I've found the following:  Although the bug is listed on Borland as I reported above, the 'bug' is in Windows.  See http://support.microsoft.com/kb/287087 (INFO: Calling Shell Functions and Interfaces from a Multithreaded Apartment).  This is not a Borland-specific problem, but in general, a lot of the shell interface will fail from a multithreaded apartment.

Now, this problem cannot be fixed by using API calls, because the API calls fail in the identical manner.  I have to, I believe, make a multithreaded application, where the calls to the DLL I'm using which requires me to use COINIT_MULTITHREADED in one thread, and the other thread is COINIT_APARTMENTTHREADED.  This I don't know how to do.  To make my original application multithreaded I had to add the call to CoInitializeEx(NULL, COINIT_MULTITHREADED); before the Application->Initialize() and then the calls to the DLL worked.  However, I don't know where to go about changing the concurrency model for a TThread.

What I'd like to do, actually, is make the main thread the APARTMENTTHREADED one, and create a MULTITHREADED thread where the DLL calls could go, that would mean the least changes to my code, I think.

Another option is if anyone knows of Open/Save Dialog components which don't care about the concurrency model; I could use these without mucking about with making a rather simple application multithreaded in order to view these two dialogs correctly.

0
 
LVL 3

Author Comment

by:sburck
ID: 17120359
Someone has suggested to me to make two applications, one which gets the filenames (normal app), and then runs the second (MULTITHREADED), which display the filenames gotten.  I'm not thrilled with this, but it's my last resort.
0
 
LVL 16

Expert Comment

by:George Tokas
ID: 17120779
The description I'm about to give you assumes that the multithreaded app is running...
Create a new standard app...
Drop a TClientSocket...
At your main application drop a TServerSocket...
Those will be needed for communication the FAST way...
The standard application when starts connecting to the TServerSocket...
The Server sends the data the other app have to find...
The Client sends report...
Precautions:
Because the standard app may called many times from the multithreaded app you have to use a mutex, or simply if you choose TServer/TClient sockets limit the TServer connections by using at OnConnect: if(Socket->ActiveConnections > 1){Socket->Close();}
If something isn't clear on the strategy I'm proposing feel free to ask...

George Tokas.
0
 
LVL 3

Author Comment

by:sburck
ID: 17120828
I'll look into this - let me just clarify.  For my user interface, I make a standard application with a clientsocket.  The (main) application which uses the DLL will be formless (or at least invisible), and have a ServerSocket.  The two applications communicate via the sockets.

I'll give this a try and let you know.
0
 
LVL 16

Expert Comment

by:George Tokas
ID: 17120977
Just create a Dialog application with the client socket...
BEFORE the dialog appears HAS TO connect to the server socket...
If not terminating...
If connection closed terminating...
If error terminating...
Choose the file using the dialog and press ok...
At the button's handler communicate with the server and if all are OK terminate the dialog application...

George Tokas.
0
 
LVL 16

Expert Comment

by:George Tokas
ID: 17120992
For saving:
Create a temporary file and send the path and filename to the dialog application...
At the dialog application load the temporary file to a TMemoryStream and save it as you like....
Report to master application for deletion...

George Tokas.
0
 
LVL 3

Author Comment

by:sburck
ID: 17122207
It seems that in BDS, the tclientsocket and tserversocket have been deprecated, there are the newer, more complicated INDY 10 components.  I'm looking at how to make a simple client/server connection without any underlying protocol (the old "chat" example from BCB6).
0
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 
LVL 16

Expert Comment

by:George Tokas
ID: 17128845
There are there just not added to the pallete...
Check out the bpl TClient/TServer Sockets are included...
Add the same in BDS....
I am on the move and the machines I have the details are not here yet....

George Tokas.
0
 
LVL 3

Author Comment

by:sburck
ID: 17129139
After trying to use them (I created them dynamically), they gave strange linker errors.  So, late yesterday I decided to try to use Windows Messaging (PostMessage, with a Message handler on the form of both master and slave to handle a WM_USER message) instead.  I'll keep you updated.
0
 
LVL 16

Expert Comment

by:George Tokas
ID: 17129323
dclsockets.pas have the declarations at BDS...
Try to add the bpl...
They will appeared in the pallete..
Maybe you will find difficulties with post message...
And the reason is multithreading...
In this case you have to use a mutex...

George Tokas.
0
 
LVL 14

Accepted Solution

by:
cwwkie earned 500 total points
ID: 17149532
>> First, I will remove my request to close this question - however, I'm going to change it,
>> and increase it's points, because it has now become considerably more difficult.

it would have been better not to withdrawn your request, and ask a new question, because it would get everybody's attention again. I only saw this by coincidence, and I don't think anybody else has subscribed after you have found your solution...

In case you still need help, maybe these links will help you.

http://www.codeguru.com/cpp/com-tech/activex/apts/article.php/c5529/
http://digital.ni.com/public.nsf/allkb/ad46b130ba24bb5c86256b8100689612?OpenDocument
0
 
LVL 16

Expert Comment

by:George Tokas
ID: 17149647
From my article at www.bcbjournal.com not yet published but at least I finished moving...

A note about BDS2006. If you noticed TServerSocket and TClientSocket are not present at the Internet “Tab” of components. That does not mean that we can’t use them anymore. The source code and the im-plementation remain there (ScktComp.pas + hpp). So where are they?
 With C++Builder personality open in BDS goto Pro-ject|Options|Packages choose Add and point to BDS\4.0\bin\dclsockets100.bpl. Click ok and now you will see the components at the internet “Tab”.

George Tokas.
0
 
LVL 3

Author Comment

by:sburck
ID: 17153458
A couple of comments:

I have begun to write the implementation using Windows Messaging and a mutex, but cannot do anything with it until at the customer site.  The problem DLL won't do anything unless it's hooked up to a big camera which I don't have access to - I'll be there on Monday, so until then I cannot test anything.

However, cwwkie, both of your points make sense.  First thing after posting this comment I'll post a pointer to this question, and won't handle a situation like this again.  Secondly, and more "on subject", the articles showed that it is possible to have different threads with different concurrency models.  This would be the ideal solution.  I would make my application a "Single-threaded-apartment", and create a "multi-threaded apartment" in a thread which calls the DLL.   Synchronization would be simple - all I need to do is wait for the thread to run to completion, after it had called the DLL.  However, I had to place my call to CoInitializeEx(COINIT_MULTITHREADED) before the call to Application->Initialize(), because Application->Initialize() automatically calls CoInitializeEx with COINIT_APARTMENTTHREADED.  I don't know what the case for a tthread is - but I'll wager if I dig into it, the thread will be auto-initialized to COINIT_APARTMENTTHREADED.  If not, or if I can place a call to CoInitializeEx in my constructor which will get called before the class itself calls it, then this may be the way to go.  I'll post this and hope for a definitive answer before Monday, when I will go in and solve the problem any way I can, but as cleanly as possible.
0
 
LVL 14

Expert Comment

by:cwwkie
ID: 17153659
>> I don't know what the case for a tthread is

You don't need to know. Take a look at the code in the second link. You only need to make some small changes, and can use it. It simply calls CreateThread to create a thread. The thread function only needs to contain CoInitializeEx, your own function call and CoUninitialize. Call the Wrapper function to use it.
0
 
LVL 3

Author Comment

by:sburck
ID: 17168100
cwwkie - I'm here and working on it - it works to a point.  My problem is callbacks.  The DLL has callback functions, which currently are my functions which update the UI.  This doesn't work - can't update the VCL from other threads.  if I was using TThread, I could call synchronize, but I'm not.  I'm trying to do modifications of the code which instead of calling

WaitForSingleObject (threadHndl, INFINITE)

I'm trying to do:

        while (WaitForSingleObject(threadHndl, 100) == WAIT_TIMEOUT)
        {
             ..update UI via globals set by the callback.
        }

This isn't working.

Any help would be appreciated.

0
 
LVL 14

Expert Comment

by:cwwkie
ID: 17170558
You can take a look what syncronise is doing (source\vcl\classes.pas)

Basicly it does
  SendMessage(ThreadWindow, CM_EXECPROC, 0, LongInt(Self));

In the window procedure, the LParam is typecasted back to a TThread pointer (Self=this) and the function is called.
You cannot use This if you do not use a TThread, but you can create something simular, or create a dummy TThread, just to call Synchronize.

As a simple alternative, you can also use a global variable, and poll it using a ttimer. Be sure to guard the access of the global variable using a mutex or critical section.
0
 
LVL 3

Author Comment

by:sburck
ID: 17170691
Due to time constraints, I just finished doing it the dirty way - I used two applications - one invisible and COINIT_MULTITASKING, and the other with the UI and not - and communicated between them using PostMessage between the two forms.  It's not a very clean solution but it works.  I think the way to have gone had there been time is  the way I started today - so I'm giving the points to cwwkie, (gtokas's suggestion had merit, as well, but, it, too, was a two-application solution).  The second article cwwkie gave the pointer to 90% of it, and given time, I would have solved the problem of the callbacks (possibly as you suggested).
0

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

Programmer's Notepad is, one of the best free text editing tools available, simply because the developers appear to have second-guessed every weird problem or issue a programmer is likely to run into. One of these problems is selecting and deleti…
How to install Selenium IDE and loops for quick automated testing. Get Selenium IDE from http://seleniumhq.org (http://seleniumhq.org) Go to that link and select download selenium in the right hand columnThat will then direct you to their downlo…
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.
The viewer will learn how to use and create new code templates in NetBeans IDE 8.0 for Windows.

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now