Welcome to MSDN Blogs Sign in | Join | Help

Debugging SUA(posix) Processes using Visual Studio

SUA processes can be debugged using Visual Studio debugger.  If you had tried debugging SFU/Interix processes using Visual Studio  debugger, you would have noticed

1.       You will not be able to launch the process using the debugger (doing so would launch posix.exe and debugger would attach to it instead of the actual posix process.)

2.       Fork() Debugging

If the process that is being debugged (usually referred to as the debugee) calls fork() the debugger will not attach to the child process. The child process behavior will be unpredictable. 

These limitations can be overcome by installing the ‘Visual Studio debugger Add-in’ component that is available with the Utilities and SDK for SUA package available for R2, Vista and Windows Server 2008(aka longhorn).

What is ‘Visual Studio debugger Add-in’?  : 

‘Visual Studio debugger Add-in’   installs a Visual Studio add-in. VS Debugger Add-in supplied for SUA enables Visual studio debugger to overcome some of the limitations with debugging posix process.

How do I debug with Visual studio debugger?

1.       Install Visual studio debugger Add-in Component. Re run the setup wizard for Utilities and SDK and select Visual studio debugger Add-in in the list of components to install.

 

2.       Verify whether the add-in has installed correctly.

Open Visual Studio IDE, navigate to Tools->Add-in Manager. In the resultant window, you should see VSAddin as one of the available Add-ins.

3.       Use CC with –g  option to build the application. –g option instructs the compiler to generate debug information(you will find a .pdb file after compilation).

 

4.        Start Visual Studio IDE. Click File ->Open-> Project/Solution.

 Browse to the POSIX executable that has to be debugged and open it. The solution explorer (if you don’t see it click View menu-> Solution explorer) will now display the application that you want to debug

 

                                You can also do this by typing in ‘<path to devenv.exe>’/devenv.exe /debugexe<application name>.  Devenv can be found at <Location at which Visual Studio is installed>\ Common7\IDE. For example, on my machine the path is ‘/dev/fs/C/Program Files/Microsoft Visual Studio 8/Common7/IDE/devenv.exe’

5.       Now, Open the source file that was used to build the debugee  application. (File->Open ->File menu and browse the desired file).  The source file will now be displayed in the main window of the Visual Studio IDE. You can set break points etc using the main window.

You can set/unset  break points by clicking on the main window frame. Refer to Visual Studio help for more information on how to set/unset break points.

6.       Now, happy debugging. The first time you do this you get a popup that reads “Debugging information for ‘posix.exe’ cannot be found or does not match. No symbols loaded. Do you want to continue debugging?”

This is an innocuous message that you can simply ignore by selecting the ‘Don’t show this dialog again’ check box. If you missed selecting this check box and simply said ‘yes’, to disable this warning,  click Tools, point to Options, click Debugging, select General, and then empty the check box Warn if No symbols on Launch (Native only).

                The steps 5 might be a bit tedious if the application you are debugging has many source files and you are going to debug the application a number of times.  In such a case, make sure you save the solution after you have opened all the source files, added break points and book marks etc. The next time around you can just open the Visual studio solution (.sln file ) to get the same set of files opened, debug points set etc. 

While debugging you would also see a window, with the title ‘PosixPID (NativePID) [EXE Path]’ that displays the posix ID (pid) of the process that you are debugging. You can also see parent child relationship in case the process forks.  By default, debugger is attached to both the parent and child after fork.

note:

1.       Binaries built with GCC cannot be debugged using Visual Studio

2.       This feature works only with Microsoft Visual Studio 2005 (Visual Studio versions 8.x and newer).

I have just mentioned things that are specific to debugging SUA processes. If you are new to Visual Studio debugging as such, then the help files with Visual Studio should be great starting point.

 

 

Posted by shankul | 5 Comments
Filed under:

Mixed-mode processes and IPC

Mixed-mode processes, because of their ability to call both Win32 subystem and subsystem libraries, can use both posix and windows InterProcessCommunication mechanisms.

 

This ability makes mixed-mode processes far more capable in terms of IPC abilities - they can communicate with

pure SUA (posix) processes,

Windows processes and

other mixed-mode processes.

 

Mixed mode processes can use any of the below posix IPC mechanisms

 

-          Process pipes

-          Named pipes

-          Message queues

-          Sockets

-          Memory-mapped files

-          Shared memory

Or any of the below Win32 IPC mechanisms

 

-          Process pipes *  ( this is implemented in std c library – so cannot be used if the application is linking to libc)

-          Named pipes

-          Message queues

-          Sockets

-          Memory-mapped files

-          Shared memory

 

Though a mixed-mode process can use a mix of these mechanisms, one should be careful to make sure that both ends of the IPC are compatible with each other– for example, while one end of an IPC connection can be windows sockets and the other end can be SUA sockets, other IPC mechanisms don’t give you this liberty. For example, both ends of shared memory should either be SUA shared memory calls or windows shared memory calls.

Posted by shankul | 4 Comments
Filed under:

Debugging mixed-mode applications

32 bit Mixed mode applications can be debugged using both Gdb and Visual studio debugger. (Since there is no 64 bit gcc suite available for SUA, 64 bit mixed mode apps cant be debugged using gdb - VS  debugger is the only option.)

There is caveat that you need to be aware of when using gdb to debug mixed-mode applications - code in the windows dll that the mixed-mode application links to can’t be debugged.  On the other hand, Visual studio debugger can be used to debug both the posix part of the code and the windows part of the code.  Gdb, being a SUA utility, doesn’t have the capability to debug windows part of the code.

So how is then Visual studio able to debug both the posix part and windows part of the code? It’s because all Mixed-mode processes are essentially windows processes. The binary image of a mixed-mode process is stamped as Windows CUI.  So on pure technical grounds, a mixed-mode process is a windows process that can make calls in to the SUA subsystem.

<edit>

After I had written this post, my colleague Sanjay pointed out that file utility shows this difference as well.  

output of file utility for a pure SUA binary

Windows NT PE format (EXE), executable not stripped Intel Posix-CUI DOS executable (EXE)

 output of file utility for a mixed-mode binary

mixed.out: Windows NT PE format (EXE), executable not stripped Intel Windows-CUI DOS executable (EXE)

Thanks Sanjay.

</edit> 

This has a lot of significance with respect to the kind of tool that can be used with mixed-mode processes. Windows subsystem sees a mixed-mode process as if it were a normal win32 process. So you can use all of the windows world tools with mixed-mode processes as well. Some such tools are

-          Task manager lists mixed-mode processes

-          You can add mixed-mode processes windows fire wall

-          You can use profiling tools on mixed-mode processes.

-          Application verifier can be used on mixed-mode processes to detect heap corruptions among many other things.

 

For those that are familiar with mixed-mode, the above fact that mixed-mode processes are windows processes might appear counter intuitive. You needn’t worry much about it. It still makes lot of sense to think of a mixed more process as if it were a SUA/posix process that has the capability to call into windows dlls. This mental model will help you when thinking of how effectively you can leverage mixed-mode in your existing applications.

Posted by shankul | 3 Comments
Filed under:

Mixed-mode programming paradigms… part 2.

In part 1, I had written about how mixed-mode code can be written using the ‘inline’ approach. In this post I will write about the second approach.

SUA Application that links to a custom Win32 dll which exposes functions and data whose datatypes are consistent with that of SUA datatypes:

This paradigm, though technically not very different from the first paradigm discussed, solves one of the drawbacks of the first approach – namely ‘header conflicts’.  This paradigm segregates the scope of data types of SUA and Windows, thereby removing any possibility of conflict.  The onus is on the programmer to take care of the mapping between SUA and Windows types.

Below is the list of steps that I would follow to write code using this approach.

1.       Identify the  Win32 function that needs to used

2.       Build a custom win32 dll with a wrapper function that calls the Win32 function that was indentified in step 1.

Note: The wrapper function should not return data which is of a Windows type. It should rather return data that is of SUA datatype. ( or make sure the SUA part of the code can understand the Windows type)

For example, consider CloseWIndow() win32 function. The syntax of this function as defined by msdn is BOOL CloseWindow(HWND hWnd).

 

To use this in the SUA/POSIX Code, build a custom win 32 dll that exports a wrapper function as below

 

__declspec(dllexport) char myCloseWindow(int hWnd) {

       return CloseWindow(hWnd);

}

 

The wrapper function, myCloseWindow, takes int (which is of size same as HWND) as argument and returns char (which is of same size as BOOL). HWND and BOOL are windows types and are not defined by SUA headers.

 

 

3.       Call the exported wrapped function from SUA/POSIX code. The SUA/POSIX code will have to link the custom Win32 dll in order to call the exported function.

Ok. So, when should one favor this approach over the first one.

1.       When there are header conflicts

2.       When there is clear separation between functionality the SUA/POSIX code and functionality of win32 call.  Example: SUA/POSIX code that calls Win32 API’s to display Graphical user interface (GUI).

The post about win32 gui and posix code is a good example of code written using this approach.

Posted by shankul | 1 Comments
Filed under:

Mixed-mode programming paradigms… part 1.

Like I alluded to in the post Using win32 GUI from posix code using mixedmode. , there are more than one way to write mixed mode programs.

There are atleast two distinct approaches that we can take when we write code that transgresses both posix and win32 worlds.

1.       SUA code with inline calls to win32 functions

2.       SUA Application that links to a custom Win32 dll which exposes functions and data whose datatypes are consistent with that of SUA datatypes.

From a technical standpoint, both these approaches are the same.  Even in the second approach we still make calls to win32 functions within posix code; but the difference lies in the fact that in the second approach we make calls to custom written functions that act as wrappers to the win32 function/ code that we want to access from posix code. 

I’ll discuss the first approach in detail in this post. The second approach will have to wait for the next post J.

SUA Code with inline calls to win32 functions:

‘inline’ here doesn’t refer to inline functions , rather it refers to the practice of calling win32 functions from within  posix/sua code. In this paradigm, calls to Win32 functions are interspersed in the SUA Applications code. In other words calls to Win32 functions will be in the same source file as that of SUA code. This is an intuitive and straight forward approach and increases readability and enables easier debugging as developers need not develop additional libraries as is the case with the other approach.  Also not e that, this is the only approach possible when only static libraries of the Win32 library is available.

                If I were to break down this approach into simple steps, this is how it will look.

1.       Identify the function in the Win32 library that you want to call in SUA/POSIX code.

2.       Identify headers that need to be included to call the win32 call identified in step 1.

3.       Include the header in the SUA/POSIX code and make calls to the WIN32 function .

Note:  When some Windows hearders are included in a SUA/POSIX application, the application may not compile because of conflict in data type definitions. This happens because particular datatype/function prototypes/macros  may be defined in different fashion in the Windows header from that of SUA headers.  I’ll discuss at the end of this post how to identify and resolve header conflicts.

4.       If you have to use the data that is returned by the Win32 call in SUA/POSIX, make sure care is taken to covert data from the type that the Win32 call returned to the type that SUA application is expecting.

 

Lest look a sample code that was written following the above approach.  Below is a small SUA application that connects to SQL server, creates a table and fills the table with data.  

Function calls that start with SQL* are win32 calls that reside in the odbc32.dll which is a win32 dll.

#include <stdio.h>

#include "CommonHeader.h"

 

#define ROWS 3

#define NEWBALANCEVALUE 2000

#define TIMESTOSQLFETCHSCROLL 5

#define SQLTEXTLEN 1024

 

/* buffers for inserting values into the table */

#define INPUTCOUNT 9

int accno_array[]={1,2,3,4,5,6,7,8,9};

float bal_array[]={1000,2000,3000,4000,5000,6001,7000,800,9000};

 

 

SQLRETURN  CreateAndFillTables(SQLHENV henv,SQLHDBC hdbc)

{    

      SQLRETURN      retcode;

      SQLINTEGER     ACCOUNT_IDArray[ROWS];

      SQLINTEGER     ACCOUNT_IDIndArray[ROWS];

      SQLINTEGER     BalanceArray[ROWS];

      SQLINTEGER     BalanceIndArray[ROWS];

      SQLUSMALLINT   RowStatusArray[ROWS], RowNum;

      SQLHSTMT       hstmt;

      SQLCHAR              cursorName[NAME_LEN];

      SQLINTEGER     cursorLen;

      SQLINTEGER     NewBalance=NEWBALANCEVALUE;

      SQLINTEGER     NewBalanceInd;

      char SQL_Text[SQLTEXTLEN];

      int CursorTypeValue = 0;

      int i=0,k=0;

 

      if(SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt)!=0)

      {

            printf("Error In Setting The Connection Handler\n");

            return MYFAIL;

      }

      retcode=SQLSetStmtAttr(hstmt, (SQLINTEGER)SQL_ATTR_CONCURRENCY, (SQLPOINTER)SQL_CONCUR_VALUES,0);

      if(retcode== SQL_ERROR)

      {

            return MYFAIL;

      }

      else if(retcode==SQL_SUCCESS_WITH_INFO)

      {

            printf("Required cursor not set, Cursor type set is %d, but wanted %d \n\n",CursorTypeValue,SQL_CONCUR_VALUES);

      }

      retcode=SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE,(SQLPOINTER)SQL_CURSOR_KEYSET_DRIVEN,0);// , 0);

      if(retcode== SQL_ERROR)

      {

            return MYFAIL;

      }

      else if(retcode==SQL_SUCCESS_WITH_INFO)

      {

            printf("Required cursor not set, Cursor type set is %d, but wanted %d\n\n",CursorTypeValue,SQL_CURSOR_KEYSET_DRIVEN);

      }

      if(SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_TYPE, SQL_BIND_BY_COLUMN, 0)!=0)

      {

            return MYFAIL;

      }

      if(SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)ROWS, 0)!=0)

      {

            return MYFAIL;

      }

      if(SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, RowStatusArray, 0)!=0)

      {

            return MYFAIL;

      }

 

      if(SQLSetCursorName(hstmt, "MY_CURSOR", SQL_NTS))

      {

            return MYFAIL;

      }

 

      // Bind arrays to the ACCOUNT_IDArray

      if(SQLBindCol(hstmt, 1, SQL_C_SLONG, ACCOUNT_IDArray, 0, ACCOUNT_IDIndArray)!=0)

      {

            return MYFAIL;

      }

 

     

      if(SQLBindCol(hstmt, 2, SQL_C_SLONG, BalanceArray, 0, BalanceIndArray)!=0)

      {

            return MYFAIL;

      }

 

      // delete the existing table

      SQLExecDirect(hstmt, "drop table accounts", SQL_NTS);// ignore errors if any

 

      /* create the table accounts */

      if(SQLExecDirect(hstmt, "create table accounts(account_id  int not null unique,bal decimal(11,2))", SQL_NTS)!=0)

      {

            return MYFAIL;

      }

 

      /* insert the values in the table*/

      for(i=0;i<INPUTCOUNT;i++)

      {

            sprintf(SQL_Text,"insert into accounts values (%d,%f)",accno_array[i],bal_array[i]);

            if(SQLExecDirect(hstmt, SQL_Text, SQL_NTS)!=0)

            {

                  return MYFAIL;

            }

      }

 

 

      // Execute a statement to retrieve rows from the Customers table.

      if(SQLExecDirect(hstmt, "select * from ACCOUNTS", SQL_NTS)!=0)

      {

            return MYFAIL;

      }

 

 

      // Fetch and display the rows, from the table

      while(1)

      {

            if(SQLFetchScroll(hstmt, SQL_FETCH_NEXT, 0))

                  break;

            for(k=0;k<ROWS;k++)

            {

                  printf("ACCOUNT_ID: %d Balance: %d \n",ACCOUNT_IDArray[k],BalanceArray[k]);

            }

      }

 

      SQLCloseCursor(hstmt);

      return MYPASS;

FAILED:

      SQLCloseCursor(hstmt);

      return MYFAIL;

}

 

 

int main(int argc, char **argv)

{

      char dsn[256]      = "ODBC-TEST";

      char user[256]     = "sa";

      char passwd[256] = "111_aaa";

      SQLHENV henv;

      SQLHDBC hdbc;

 

      if (argc > 1)

      {

            strcpy(dsn, argv[1]);

      }

      if(argc > 2)

      {

            strcpy(user, argv[2]);

      }

      if(argc > 3)

      {

            strcpy(passwd, argv[3]);

      }

 

      if(MYFAIL == ConnectToDB(dsn, user, passwd, &henv, &hdbc))

      {

            printf("Could not establish connection\n");

            return 1;

      }

 

      CreateAndFillTables(henv, hdbc);

 

      return 0;

     

}

 

 

You would see lots of dataypes alien to posix used here. These are types that are defined in sql headers like sql.h, sqltypes.h etc. 

Below is the code in commonheader.h. I’ve included this so that if you want to try building this application, you have all the sources.

#include <interix/mixedmode.h>

 

#include <stdio.h>

#include <odbc/sql.h>

#include <odbc/sqlext.h>

#include <odbc/sqltypes.h>

#include <odbc/odbcss.h>

#include <stdlib.h>

#include <odbc/odbcinst.h>

#include <errno.h>

#define NAME_LEN 50

 

#define MYFAIL -1

#define MYPASS 0

 

/* displays the last error message */

void ShowError(SQLHSTMT hstmt,SQLSMALLINT HandleType)

{

      SQLCHAR       SqlState[6], SQLStmt[100], Msg[SQL_MAX_MESSAGE_LENGTH];

      SQLINTEGER    NativeError;

      SQLSMALLINT   i, MsgLen;

      SQLRETURN     rc1, rc2;

      i = 1;

      while ((rc2 = SQLGetDiagRec(HandleType, hstmt, i, SqlState, &NativeError,Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA)

      {

            printf("SqlState %s,NativeError %d ,Msg %s \n",SqlState,NativeError,Msg);

            i++;

      }

}

/* establishes the connection with the DB */

int ConnectToDB(char *DSN,char * UserId ,char *passwd,SQLHENV *henv,SQLHDBC *hdbc)

{

      SQLRETURN      retcode;

 

      if(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, henv))

      {

            printf("SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv) failed\n");

            return MYFAIL;

      }

      if(SQLSetEnvAttr(*henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3,0))

      {

            printf("SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3,0) failed\n");

            return MYFAIL;

      }

      if(SQLAllocHandle(SQL_HANDLE_DBC, *henv, hdbc))

      {

            printf("SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc) failed\n");

            return MYFAIL;

      }

 

 

      if((retcode =SQLSetConnectAttr(*hdbc, (SQLINTEGER)SQL_ATTR_ODBC_CURSORS,(SQLPOINTER)SQL_CUR_USE_IF_NEEDED,0))!=SQL_SUCCESS)//SQL_CUR_USE_ODBC

      {

            printf("Error In Using Cursor Library\n");

            return MYFAIL;

      }

      //Setting Connection Attribute

      if((retcode=SQLSetConnectAttr(*hdbc,(SQLINTEGER)SQL_LOGIN_TIMEOUT, (SQLPOINTER  )5, 0))!=SQL_SUCCESS)

      {

            printf( "Error In Setting The Connection Handler\n");

            return MYFAIL;

      }

      //Connecting to SQL-SERVER

      if((retcode =SQLConnect(*hdbc,(SQLCHAR *)DSN,SQL_NTS, (SQLCHAR *) UserId,SQL_NTS,(SQLCHAR *) passwd,SQL_NTS ))!=SQL_SUCCESS_WITH_INFO)

      {

            printf( "Error In Connecting To The SQLSERVER \n");

            return MYFAIL;

      }

      return MYPASS;

 

}

void CloseConnection(SQLHENV henv,SQLHDBC hdbc)

{

      //Free the Connection Handle                                                                               

      if( hdbc)

            SQLFreeHandle( SQL_HANDLE_DBC, hdbc );   

      //Free the Environment  Handle

      if( henv)

            SQLFreeHandle( SQL_HANDLE_ENV, henv );

}

 

 

The help files that come with ‘Utilities and SDK for SUA’ has detailed help on how to build applications that access SQL and Oracle databases. You can find that in the section ‘Developing database connectivity applications’.  I strongly recommend you to read this if you want to develop database applications that talk to either SQL server or Oracle.

 

Header Conflicts:

                A hurdle that one will have to overcome when following the above approach is header conflicts. ‘Header conflicts’ are a result of conflicting type definitions in SUA headers and Windows headers. For example, ULONG is defined in mixedmode.h a SUA/POSIX header. When mixedmode.h and a windows header that defines ULONG is included in a SUA/POSIX application, then a header conflict results. Header conflicts can be identified by looking at the compile error. 

Below are sample header conflict errors

With CC/C89

 

c:\winnt\sua\usr\include\odbc\sqltypes.h(122) : warning C4142: benign redefinition of type

 

With GCC

In file included from /usr/include/odbc/sql.h:25,

                 from CommonHeader.h:4,

                 from sample.c:2:

/usr/include/odbc/sqltypes.h:122: error: conflicting types for `ULONG'

/usr/include/interix/mixedmode.h:33: error: previous declaration of `ULONG'

 

 

How to resolve header conflicts?

1.       Construct a new header file with the types required by the Win32 function and include that instead of the standard windows header. Often, a type that is not used results in header conflicts.

2.        Change the Win32 header to resolve header conflicts.  While changing the header it is advisable to make a copy if the headers and change the copy.  This method of resolving header conflicts is advisable when the win32 header that resulted in type re declaration error is the first level header included in SUA/POSIX code and the number of re declaration error is limited to few type conflicts.

 

I strongly recommend this if you are developing sql applications – the help file also suggests this.

 

3.       Use a different programming approach –  by segregating the scope of data types of SUA and Windows, thereby removing any possibility of conflict.  

 

This post should have given you a brief idea of one of the approaches in mixed-mode programming, In the next post, I’ll discuss the second approach.

 

Posted by shankul | 0 Comments
Filed under:

Invoking win32 GUI from posix code using mixedmode.

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.

 

Posted by shankul | 2 Comments
Filed under:

Mixedmode - easy way to extend your applications!

Mixed-mode refers to the ability of code running on the Subsystem for UNIX Applications (SUA) to use native windows libraries.   Anyone familiar with SFU or SUA would know that one can port POSIX compliant code over to SFU/SUA. Though this enables one to move his application over to windows, it still had a huge limitation; the old apps are still just the same.   During the R2 release, we re-architectured the subsystem (aka SUA) so that any SUA application, in addition to the usual capabilities, can load a windows dll and make calls to it.   This pushes the horizon for the POSIX apps to a greater extent. A POSIX app can load any dll built for the windows platform. 

There are some significant advantages that this capability brings

Application Porting:  A native SUA application would require all the libraries to be ported over to SUA. In some cases these libraries on which the custom application depends might be an ISV library and a version of the same library that is ported over SUA may not available.  Mixed-mode removes this obstacle.   Database applications are one example of such class of applications.  Database applications usually link to a middle tier library, (OCI.dll in case or Oracle connectivity applications) and these libraries are not available on SUA. But since a windows version of OCI.dll is available and is supported by the vendor (Oracle), a mixed mode application can link to the windows version of the OCI.dll.

Extending functionality of SUA applications:  One can take advantage of mixed-mode to extend the functionality of their applications. Applications can be extended to use other Windows libraries or ISV libraries (equivalent of which are not available over SUA).

Here are some of the scenarios that are possible with mixed mode...

1.       A posix app can  link to ODBC drivers to  talk to any of the databases that supply a ODBC compliant client library. ODBC is just an example - infact a posix app can access any database if there is a windows version of the client library.

2.     A posix app that uses x11 can be modified to display gui using any of the windows mechanisms (win32, .net etc).

3.     Ported apps functionality can be increased by using technologies COM, active X, .net integration etc.

The common theme underlying all the above scenarios is that, bulk of the code remains the same – the complex business logic in the code etc remains untouched. You only change the part which you want to extend and you are able to give your legacy app more fire power. Think of your decade old console based app displaying swanky winforms UI; without rewriting the entire application.

So how does one build a mixed-mode app?

Simply compile the app with the –R flag e.g.:

gcc  -R helloworld.c <windowslibrary>  OR  c89 - R helloworld.c <windowslibrary>

the –R flag tells the compile that the binary to be generated is a mixed-mode binary.

When a app is a marked as a mixed-mode app it becomes a hybrid app. It is very different from a normal SUA app and a normal windows App. A mixed-mode app interacts with both the Windows subsystem and the SUA subsystem.  There are some limitations that this brings with. For example, the child process a mixed-mode app that called fork() will not be able to load and call windows dlls. A mixed-mode cannot be marked as a setuid binary. For a comprehensive list of all such limitations, refer to ‘releasenotes.doc” or releasenotes.htm in the docs folder (%windir%\sua\docs) of your SUA installation.

Stay tuned for more in this space. I will soon give some samples that would explain this better.

 

 

Posted by shankul | 1 Comments
Filed under:

SFU, SUA & IDMU… Fun with names!

I had mentioned few weird looking acronyms in my last post and had said those were what I worked on. To give you guys some history; SFU (Services for UNIX) is a hugely successful product and can be downloaded free of cost from Microsoft.com. SFU was not part of OS but can be installed on Windows XP, Windows 2000 and Windows Server 2003.

 

During the development of Windows Server 2003 R2(referred as R2 from here on), we took most of the components and technologies that made up SFU, enhanced those technologies in more than one ways and integrated them in to the OS. In addition to enhancing the capabilities of the components we also gave them new names. Don’t ask me why. All I can say is there were enough reasons to do soJ.

 

Lots of folks have asked me – How can I get functionality X of SFU on R2?  Below is what various technologies of SFU are reincarnated as

 

Subsystem for UNIX based Applications (SUA) - (yeah, I know it’s a bit long and wordy). Not many in my team are good with tongue twisters. We call it ‘SUA’ or simply, ‘subsystem’.  SUA is the successor to the Interix subsystem of SFU world. As the name indicates, SUA is capable of running UNIX “like” applications. It can’t run UNIX applications – you can just drop a UNIX binary and expect it to run. But what you can do is take the source code and compile it for SUA and run it on windows machine with SUA installed.  I’ll talk about architecture of SUA and in what way it is related to its cousin, windows subsystem, in a later post.

 

Utilities and SDK for SUA – This package, which can be downloaded for free, contains around 350 UNIX like utilities, libraries, compilers etc. Go here to download the package and read more about it.

 

Identity management for UNIX (IDMU) – This component enables you to ingrate management of UNIX identities with AD. It has a feature called password synchronization that one can setup to automatically sync passwords of his UNIX and windows Identity. Using Sever for NIS (SNIS) you can obviate the need for a separate UNIX identity server – you can have a windows Active Directory server manage the UNIX Identities. Read this paper to learn more.

 

Server for NFS and Client for NFS: I guess the names of these components are self explanatory, unlike the above ones :).

 

 

Those of you that are familiar with SFU might think the above said could be achieved with SFU. So why would anyone go for Windows Server 2003 R2 instead of SFU? Well, there is more than one reason why one should use R2.

 

-    Database (OCI/ODBC) library connectivity   SUA supports connectivity to Oracle and SQL Server from database applications by using the Oracle Call Interface (OCI) and the Open Database Connectivity (ODBC) standard.

 

-    Microsoft Visual Studio® Debugger Extension for debugging POSIX applications   SUA includes support for debugging your POSIX processes by using the Visual Studio integrated development environment (IDE).

 

-    Utilities based on SVR-5 and BSD UNIX environments   The SUA download package supports two different UNIX environments: SVR-5 and BSD.

 

-    Support for 64-bit applications: R2 SUA, IDMU are available for X64 platforms as well. ( SFU is available only for X86)

 

-    Integration with Windows updates: SUA subsystem components, IDMU and NFS in R2 will be serviced by windows updates. This makes keeping you installations secure easier.

 

-   Mixed-mode: SUA enables you to build an application that leverage both SUA Subsystem functionality and windows subsystem functionality. Mixed mode deserves more attention and so, more in a later blog.

 

-    The AD Schema in R2 is RFC 2307 compliant.

 

-    R2 IDMU has psadmin, a command line utility, to administer password synchronization settings.

 

-    R2 Server for NFS can do a direct “Active Directory” lookup for UID/GID – no need for a User Name Mapping server.

 

 

In the past, there have been articles claiming that Microsoft is stopping support for SFU. My opinion is that those articles are way off reflecting the reality. As I explained, most of the SFU technologies have a new home. SFU 3.5 is supported for a long time to come.

Posted by shankul | 3 Comments
Filed under:

hi there!

I’m Shanmugam Kulandaivel. I work as a Program Manager with the team that builds SFU, SUA and IDMU technologies.  I'll use this space to talk to about some of the cool things that we do and cool things that you can do with these UNIX Interop technologies.

Posted by shankul | 12 Comments
 
Page view tracker