Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

how to call code in C++ library that needs to keep a running thread from my WPF app

Posted on 2010-09-05
9
Medium Priority
?
816 Views
Last Modified: 2013-12-17
I have an unmanaged legacy C++ app.
I gave up on trying to load a stylized WPF window from a newly-managed C++/CLR build of the app,
and instead I tried creating a new C# app using the stylized WPF windows (by stylized I mean I'm using a 3rd party dll that contains xaml/wpf window styles).
in other words, I'm trying to recreated the UI part in a new C# app using WPF, but don't want to migrate all my legacy non-UI code.

The problem is I want to load my old C++ code from this new C# app in such a way that the C++ code can kick off a thread and keep it running in order to do all sorts of fancy stuff.

if I just call my main exported function, then it won't return control to my C# app until the thread exits.
Do I need to do a LoadLibrary() to make sure the dll stays in memory?
I want the C++ dll to kick off a thread and stay in memory while my C# WPF app displays a window (and the 2 should talk to each other of course) - not be sequential!

What's the right way to accomplish what I want to do?

e.g.
    public partial class App : Application
    {
            [DllImport("Client_DLL.dll", SetLastError = false)]
            static extern int MyDllMain();

            //IntPtr hDll = LoadLibrary("Client_DLL.dll");

            int nRet = MyDllMain();
}
0
Comment
Question by:povjetset
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 2
9 Comments
 
LVL 5

Expert Comment

by:greatsubash
ID: 33609483
0
 
LVL 1

Expert Comment

by:XMarshall10
ID: 33610380
I think only explicit linking (LoadLibrary) and then after your work is done, call FreeLibrary so that windows can Unload your dll.

In between windows should not unload the dll from memory, as internally windows maintains a reference count or counter indicating how many clients are using this dll at any point of time.

-XM
0
 

Author Comment

by:povjetset
ID: 33611196
thanks, but as I mentioned, I can successfully call a function in my c++ dll
The problem is that if that function starts a thread, then the function does not return (back to the C# code that PInvoked it) until the thread exits! (which of course defeats my purpose of wanting that thread to keep running while my WPF C# app runs the uI)

I only added the LoadLibrary because I thought maybe the dll was getting unloaded after the function returned, killing the thread, but that's not the case. The LoadLibrary seems irrelevant.

Can I start a thread in my WPF app and have it call pinvoke that function (which wouldn't need a thread on its side)?
0
Microsoft Certification Exam 74-409

Veeam® is happy to provide the Microsoft community with a study guide prepared by MVP and MCT, Orin Thomas. This guide will take you through each of the exam objectives, helping you to prepare for and pass the examination.

 

Author Comment

by:povjetset
ID: 33612276
Update: ok, so I create a thread and then pinvoke my dll function from there, seems to work, i.e. my thread in the dll is running, and my main WPF thread is controlling my new UI. (not sure if a BackgroundWorker would have been better than a regular Thread due to the cross-thread dispatching issue)

So now the real issue:
- how does my C++/CLR code send commands to the C# app, i.e. to update the UI window, since it didn't create the WPF window and it's running in a different thread?
The sample code I see everywhere for hosting a WPF control inside a C++/CLR app doesn't seem to apply...
My Window class is defined in C#, so even if I passed a reference to it via a pinvoked call to the dll, and the dll stores it in a managed class, how do I call a member function of that class (or post a message to it, if that's possible)? As I mentioned, the window was defined in C#, not C++.
How do I attach an event handler to the C# class reference in my C++/CLR code?

FYI I can successfully I can handle the reverse by calling a new C++ dll entry point that takes a UINT cmd, which then posts the command to the internal hidden window, which gets handled in the message loop that is running inside the dll (just like the code used to do).
0
 

Accepted Solution

by:
povjetset earned 0 total points
ID: 33612476
I think I have a workable solution:

When the C# window is created, use a WindowInteropHelper to get the hWnd and pass that in to my dll

            WindowInteropHelper wih = new WindowInteropHelper(mywindow);
            IntPtr hWnd = wih.Handle;
            MyDllFun(hWnd);

Then my dll can simply PostMessage (with user-defined messages) to that hWnd as neeeded

Back in C#, process the messages by doing an AddHook on the HwndSource (from http://www.steverands.com/2009/03/19/custom-wndproc-wpf-apps/)

    public partial class MainWindow : Window
    {
        ...

        protected override void OnSourceInitialized(EventArgs e)
        {
            base.OnSourceInitialized(e);
            HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
            source.AddHook(WndProc);
        }

        IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            // Handle messages...
            if (msg == 666)
            {
                MessageBox.Show("Received msg 666");
            }
   
            return IntPtr.Zero;
        }
   }

amazingly, this actually worked for me!

Is there any reason to be concerned that this won't work properly?
0
 

Author Comment

by:povjetset
ID: 33612936
well, there is still one issue: how do I send a string in those messages? Can I use GlobalAddAtom/GlobalGetAtomName (in both directions, i.e. posted in a message either from C++ to C# or from C# to C++ although in the C# to C++ case, I can marshal the string and pass it in the pinvoked function, which if necessary can then create an atom to postmessage internally)

so what about sending a string from the C++ code to the C# WPF window?  (yes, I know the UI text should really reside with the UI code, but I have resource dll's and legacy code already building the required string to show in the new UI)

note that currently I didn't need to recompile my C++ dll with /clr since I'm only using PostMessage

0
 

Author Comment

by:povjetset
ID: 33614622
my other workaround for this string issue is to save the string (or regenerate it based on an id) and pass the id in the postmessage, then have C# call a MyDllGetString() api with the id
not great but works for a majority of my messages
0
 
LVL 1

Expert Comment

by:XMarshall10
ID: 33616069
Since you already have the window handle, I guess you can send your string data to that window by packing your data inside wParam or lParam parameters, and process it accordingly in the receiving window. This approach is very common and may be a bit simpler.

-XM
0
 

Author Comment

by:povjetset
ID: 33635967
you can't pass a string in a windows message, and a GlobalAtom is limited to just under 256 chars
But passing/getting a string between C# and C++ is easy.

in short, I guess my solution is like doing a COM control without using COM (and with making data exchange a a little less convenient). Given my limited interactions, that seems ok for now, but if things get hairier, I'll probably have to make the C++ code a full-fledged COM control
0

Featured Post

Veeam Disaster Recovery in Microsoft Azure

Veeam PN for Microsoft Azure is a FREE solution designed to simplify and automate the setup of a DR site in Microsoft Azure using lightweight software-defined networking. It reduces the complexity of VPN deployments and is designed for businesses of ALL sizes.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Entering time in Microsoft Access can be difficult. An input mask often bothers users more than helping them and won't catch all typing errors. This article shows how to create a textbox for 24-hour time input with full validation politely catching …
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

722 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