Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / Interop / July 2006

Tip: Looking for answers? Try searching our database.

C# Client and Unmanaged C++ DLL Threading

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Paul - 05 Jun 2006 16:45 GMT
Hi,
I wonder if you can help....
I have a C# client that calls into an unmanaged C++ DLL. The call never
returns due to what appears to be a multi-threading issue.....

To complete the API request, the unmanaged DLL requires to create a second
thread (windows message loop). Whislt the 2nd thread is busy, the main thread
is blocked (and therefore the C# client). Unfortunately the 2nd thread does
not run. (Calling the unmanaged DLL from a C++ console app works as desired).

I noticed that the main C# thread is a STA; I tried creating a 2nd thread in
the C# client, setting the AttributeState in the 2nd client to MTA, and
calling the C++ unmanaged DLL from the 2nd C# thread... with the same
blocking failue.

Any ideas on calling a multi-threaded unmanaged DLL from a C# app?

   cheers,

       Paul
"Peter Huang" [MSFT] - 06 Jun 2006 04:34 GMT
Hi Paul,

Thanks for your posting!

Based on my understanding, you have an unmanaged DLL, which exports a
function.
Is the DLL a COM DLL  or just a legacy DLL?

Also if you create another thread in C# to do the API call, so only the
second thread will be blocked due to the P/Invoke call is blocked. Is that
correct?
But if you call the DLL function in C++ all is OK.

From the description, to complete the API call, we need to create another
thread. So how C++ did that?
Can you describe the detailed steps about how the API call works one by
one? so that we will know what the concrete scenario.

If I misunderstood, please feel free to post here.

Best regards,

Peter Huang

Microsoft Online Community Support
==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
Paul - 06 Jun 2006 09:53 GMT
Hi Peter,
Thanks for your interest. Your interpretation is correct. I will add more
details for clarification:

The C++ unmanaged DLL is a legacy DLL, not a COM DLL.
Yes, the 2nd C# thread is blocked due to PInvoke blocking in the unmanaged
C++ DLL.

/* C++ unmanaged DLL */
The C++ unmanaged DLL exports the following function:
UINT __declspec(dllexport) GetServiceNames(char * aszServiceNames[], UINT *
puiNoOfServiceNames);

When called, the C++ unmanaged DLL creates a 2nd thread in which some
initialisation is performed. The thread is created using the Win32 API:
   CreateThread();

Whilst initialisation is being performed, the main thread is blocked using
the Win32 API:
   WaitForSingleObject();

Once initialisation is complete, the main thread is released when the 2nd
thread calls the Win32 API:
   SetEvent();    

The C++ unmanaged DLL functions as required when called from a C++ console
app. When called from the C# application, the call is blocked due to the main
thread being blocked at WaitForSingleObject(), due to the 2nd thread failing
to execute.

Modification for debug of the C++ unmanaged DLL to omit the
WaitForSingleObject() call, prevents the API GetServiceNames() call from
blocking and returns sucesfully marshaled test data.

Any thoughts on how to get the 2nd thread to run when called from the C#
client?

   thanks again,

       Paul

> Hi Paul,
>
[quoted text clipped - 26 lines]
> ==================================================
> This posting is provided "AS IS" with no warranties, and confers no rights.
"Peter Huang" [MSFT] - 07 Jun 2006 03:54 GMT
Hi Paul,

Based on my test with a simple reproduce sample following your instruction,
I can not reproduce the problem
You may have a test and change the code below to reproduce the problem.

Also you may try to debug into your code to check which steps cause the
problem.
e.g. If CreateThread called succeed with GetLastError();
And if the code in the 2nd thread is running and if the SetEvent is called,
did that succeed?

[C++]
VOID ThreadFunction(LPVOID lpParam)
{
    HANDLE hEvent = *(HANDLE*)lpParam;
    for(int i = 0;i<10;i++)
    {
        cout<<i<<": Running"<<endl;
        Sleep(1000);
    }
    if(SetEvent(hEvent))
        cout<<"Event Signal succeeded"<<endl;
    else
        cout<<"Event signal failed"<<endl;
}

CPPDLL_API int fnCPPDLL(void)
{
    DWORD IDThread;
    HANDLE hEvent;
    HANDLE hThread;
    hEvent = CreateEvent(
        NULL,         // default security attributes
        TRUE,         // manual-reset event
        FALSE,         // initial state is signaled
        _T("MyEvent")  // object name
        );
    hThread =
CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadFunction,&hEvent,0,&IDThre
ad);
    if (WAIT_TIMEOUT == WaitForSingleObject(hEvent,10000))
        cout<<"Time Out"<<endl;
               WaitForSingleObject(hThread,INFINITE);//This line is used
to ensure the cout routine after SetEvent will complete.
    return 42;
}

[C#]
       [DllImport(@"CPPDLL.dll")]
       extern static int fnCPPDLL();
       static void Main(string[] args)
       {
           try
           {
               Console.WriteLine(fnCPPDLL());
           }
           catch (Exception e)
           {
               Console.WriteLine(e.ToString());
           }
       }

Best regards,

Peter Huang

Microsoft Online Community Support
==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
Paul - 07 Jun 2006 22:37 GMT
Hi Peter,
Thanks again for your help....
Your sample code is representative of my applications. I created test apps
with your code fragments (with the ThreadFunction loop reduced to 5), to
find, as you did, that the second thread runs as desired.

The only differences I can see are:
1. You pass in the event handle to the 2nd thread, whereas I create the
event (using the same literal) in both the main thread and the 2nd thread....
should be OK though, as it runs when called from a C++ console app?
2. After signalling the main thread, my 2nd thread falls into a windows
message loop without terminating. Can't see why this would have any impact?

You have given me some lines of investigation. I will post any progress.
Thanks again for your help.

   cheers,
       Paul

> Hi Paul,
>
[quoted text clipped - 69 lines]
> ==================================================
> This posting is provided "AS IS" with no warranties, and confers no rights.
"Peter Huang" [MSFT] - 08 Jun 2006 04:06 GMT
Hi

1. I understand you create a global Event but not pass it via Thread
Parameter.
Based on my test, it works too.

2. So far I understand that you problem as below.
The 2nd thread will be running and signal the event successfully and then
loop in the windows message.
Now the Main thread should not blocked.
Did I miss something?

Also since we did not do complex code review, can you modify the simple
test code to reproduce the problem based on your project.

3. I look forward to your troubleshooting steps based on my suggestion.

Best regards,

Peter Huang

Microsoft Online Community Support
==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
Paul - 11 Jun 2006 22:16 GMT
Hi Peter,
Sorry for the delay in replying, and thanks again for your suggestions.
2. Your description matches the desired functinality. Unfortunately the main
thread remains blocked as the 2nd thread does not run and therefore does not
signal the main thread.

3. I have modified the simple test code and have succeeded in recreating the
failure. I should have mentioned before that the initialisation is being
performed when the unmanaged DLL is being loaded and not during a subsequent
exported function call.... There appears to be a difference in the threding
behaviour of the unmanaged DLL when loaded by an unmanaged C++ console app
and when loaded by a C# app utilising PInvoke:

Within the unmanaged DLL, the 2nd thread is created from DllMain when the
first process attaches (as there will only be one windows message loop).

[C++ client]
This functions as desired when loaded by a C++ console app: the 2nd thread
is created, initialisation perfromed, and the main thread is released and
returns.

[C# client]
When loaded using the InteropServices PInvoke, DllMain() is called as for
the C++ console app, the differenece being that the 2nd thread does not run.

Moving the initialisation (creation of the 2nd thread) in DllMain to occur
on DLL_THREAD_ATTACH rather than DLL_PROCESS_ATTACH resolves the issue.

To get a full understanding of the root cause I will have to look into the
differences in DLL loading.

Thanks again for your help Peter....

   Paul



> Hi
>
[quoted text clipped - 23 lines]
> ==================================================
> This posting is provided "AS IS" with no warranties, and confers no rights.
"Peter Huang" [MSFT] - 13 Jun 2006 06:15 GMT
Hi Paul,

Thanks for your quickly reply!
I am glad to see that you have resolved the issue, if you still have any
concern, please feel free to post here.

Thanks!

Best regards,

Peter Huang

Microsoft Online Community Support
==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
Paul - 07 Jul 2006 09:49 GMT
Hi,
There is an MSDN article that contains an explanation for the failure
observed; follow the link and check out the description under the heading
"DllMain Restrictions".

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_vstechart/ht
ml/vcconMixedDLLLoadingProblem.asp


   thank you,

      Paul

> Hi Paul,
>
[quoted text clipped - 14 lines]
> ==================================================
> This posting is provided "AS IS" with no warranties, and confers no rights.
"Peter Huang" [MSFT] - 10 Jul 2006 06:36 GMT
Hi Paul,

Thanks very much for your knowledge sharing in the community.
I believe this will benefit the whole community.

Best regards,

Peter Huang

Microsoft Online Community Support
==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.

Rate this thread:







Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.