In the last post, i was talking about mixed-mode and the various scenarios that it enables. In this post, let us look at a small sample app that would make it more clear.

the goal of our sample app is to throw a win32 windows from posix code. There are two slightly different approaches that we can follow to do this.

1.      Use the win32 functions like registerclassex(), createwindow() etc in posix code

2.      Create a windows dll that exposes a function which uses registerclassex(), createwindow() etc to diplay a win32 window.

Though both these approaches are equally feasible from a technical standpoint, for the scenario at hand, I favor the second approach for more than one reason.

1.      We are going to call more than one win32 function, each of which takes and returns data whose type is alien to posix. Code would be better readable if we seperate win32 part and posix code

2. Creating windows, displaying content etc (for which we are going to use win32 functions) is logically a distinct piece. NOt lot o interecations are required by these win32 functions and posix code.  (to better understand this, cosider a database connectivity application. in such applications as database connectivity apps it makes a lot of sense to make direct win32 calls as the posix code would often process the data returned by the win32 call and make further win32 calls)

now that we have decided on the approach, we need to do two things

1.       build a dll that exports a function that would create a win32 window.

2.       link to the dll built in step 1 and call the exported function from posix code.

Step 1:

                This is ver straight forward. The only thing that one should be aware of is the datatypes that the exported function returns/accepts should be those that the posix code understands. For example if you were to export a function like the one below

                __declspec(dllexport) HANDLE drawwindow()

make sure that you define HANDLE in the posix part of the code. Alternatively, you can include the windows header file that defines the particular type in question. But this some times would result in header conflic/re declaration issues – more on this later.

    BOOL APIENTRY DllMain( HMODULE hModule,

                       DWORD  ul_reason_for_call,

                       LPVOID lpReserved

                               )

{

      switch (ul_reason_for_call)

      {

      case DLL_PROCESS_ATTACH:

      case DLL_THREAD_ATTACH:

      case DLL_THREAD_DETACH:

      case DLL_PROCESS_DETACH:

            break;

      }

     

    return TRUE;

}

 

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

      switch (message)

    {

        case WM_DESTROY:

        PostQuitMessage (0);

        break;

        default:

        return DefWindowProc (hWnd, message, wParam, lParam);

    }

 

            return 0;

}

 

__declspec(dllexport) void drawwindow()

 {

      DWORD err = 0;   

      HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);

      HWND hwnd;

      TCHAR szClassName[ ] = TEXT("WindowsApp");

    MSG messages;

    HACCEL hAccelTable;

     

      WNDCLASSEX wincl;

    /* The Window structure */

   

wincl.hInstance = hInstance;

    wincl.lpszClassName = szClassName;

    wincl.lpfnWndProc = WndProc;

      wincl.style = CS_HREDRAW | CS_VREDRAW;

    wincl.cbSize = sizeof (WNDCLASSEX);

    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);

    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);

    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);

    wincl.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);

    wincl.cbClsExtra = 0;

wincl.cbWndExtra = 0;

wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    if (!RegisterClassEx (&wincl))

            return;

      hwnd = CreateWindow(szClassName, TEXT("This is a Sample Window..."), WS_OVERLAPPEDWINDOW,

      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

 

      if (NULL == hwnd){

            err = GetLastError();

      }

      err = ShowWindow (hwnd, SW_SHOW);

      if(0 != err){

            err = GetLastError();

      }

 

      while (GetMessage (&messages, NULL, 0, 0)){

        TranslateMessage(&messages);

        DispatchMessage(&messages);

    }

 

    return;

 }

 

Build the above code as a dll

Step2:

                Now, write posix code that calls in to the dll built in step 1.

#include<pthread.h>

#include<stdio.h>

 

void* wrapper_drawwindow(void*);

extern void drawwindow(void);

 

main()

{

      pthread_t exThread = 0;

      printf("This is a POSIX Application!!!");

      fflush(stdout);

      pthread_create(

            &exThread,

            NULL,

            &(wrapper_drawwindow),

            NULL);

 

      pthread_join(exThread,NULL);

}

 

//this function calls drawwindow() which is exposed by windll.dll

void* wrapper_drawwindow(void* temp)

{

      drawwindow();

      return NULL;

}

 

Now build the above code as a mixed mode app

cc -R -o demo.exe SUA_WinUIDemo.c ./windll.lib

As I had said earlier, -R flag tells CC to build the app as a mixed-mode app. Windll.lib is the object file library of the dll that we built in step 1.

Run demo.exe and we have a posix application showing win32 gui.  I know the above sample doesn’t answer lot of questions. I’ll try to answer some questions like, how to resolve header conflicts, what form of IPC is possible in a mixed-mode app etc. If you have anything specific, do comment back.