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 / November 2003

Tip: Looking for answers? Try searching our database.

Callbacks of unmanaged code-urgent

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
vijaya - 15 Nov 2003 08:52 GMT
I've to invoke a unmanaged dll fucntion in C# which uses
a callback fucntion.My problem is that the function is
executing finely but I'm not getting correct output

Error: The return code is 0 which means the fucntion has
executed successfully. But I'm not getting the correct
values in the structure pborcadirentry.

For detailed information, I've given bith the unmanaged
function and the managed function which I've written .Plzzz
help me out.

The unmanaged dll fucntion is as
follows

****************************************
The Original Fucntion in the dll
****************************************
int PBORCA_LibraryDirectory ( HPBORCA hORCASession, LPSTR
lpszLibName, LPSTR lpszLibComments, int iCmntsBuffSize,
PBORCA_LISTPROC pListProc, LPVOID pUserData );

hORCASession-Handle to previously established ORCA session

pListProc- Pointer to the PBORCA_LibraryDirectory callback
function.

pUserData -Pointer to user data to be passed to the
PBORCA_LibraryDirectory callback function  

Given below function is the callback function declaration
in C.

typedef void (FAR PASCAL *PBORCA_LISTPROC) (
PPBORCA_DIRENTRY, LPVOID );

PPBORCA_DIRENTRY -Pointer to the structure
PBORCA_DIRENTRY, described next
LPVOID -Long pointer to user data

The user data strcuture to the callback fucntion is as  
follows:

typedef struct ORCA_UserDataInfo
{
LPSTR lpszBuffer; // Buffer for entry info
DWORD dwCallCount; // # of entries in lib
DWORD dwBufferSize; // size of buffer
DWORD dwBufferOffset; // current offset in buffer
} ORCA_USERDATAINFO, FAR *PORCA_USERDATAINFO;

The structure passed to the callback fucntion by the
LibraryDirectory fucntion is as follows:

typedef struct pborca_direntry { CHAR szComments
[PBORCA_MAXCOMMENT + 1];
LONG lCreateTime;
LONG lEntrySize;
LPSTR lpszEntryName;
PBORCA_TYPE otEntryType;} PBORCA_DIRENTRY, FAR
*PPBORCA_DIRENTRY;

Note:PBORCA_TYPE  is an enum
PBORCA_MAXCOMMENT=255
***************************************
End of the dll fucntion
***************************************

_________________________________________
C# code which I've written
_________________________________________

[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Auto)]
    public class UserData
    {
        public string s;
        public uint callcount;
        public uint bufsize;
        public uint offset;
    }

[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Auto)]
    public  struct pborca_direntry
    {
        public const int i=255;
    [MarshalAsUnmanagedType.ByValTStr,SizeConst=i+1)]
        public string s;
        public System.Int32 time;
        public System.Int32 size;
        [MarshalAs(UnmanagedType.LPStr)]
        public string name;
        public int type;
                       }
public unsafe delegate void Callback(ref pborca_direntry
p,UserData usr);

[DllImport
("pborc80.dll",CharSet=CharSet.Auto,EntryPoint="PBORCA_Libr
aryDirectory")]
public static extern int LibraryEntry(int hnd,[MarshalAs
(UnmanagedType.LPStr)]System.String s,[Out]char[] buff,int
se,[MarshalAs(UnmanagedType.FunctionPtr)]Callback
hr,UserData usr);

public class1
{
Callback c = new Callback(Class1.libdircallback);
char[] st = new char[10000];
GC.KeepAlive(code=class3.LibraryEntry
(hnd,"d:\\projects\\current\\tgt3.pbl",st,10000,c,usr));
           
public  static  void libdircallback(ref pborca_direntry  
s,UserData usr)
{
Console.WriteLine("hai,I'm in callback");
Console.WriteLine(s.type);
}

}

Note: I've tried GC method. But I'm not sure whether I've
applied it appropriately.I've also tried [MarshalAs
(UnmanagedType.Struct)] and [MarshalAs
(UnmanagedType.LPStruct)] for marshaling structure and
class.But there was no change in the o/p. I feel that
there is some problem in the memory management. But I'm
unable to detect it.

If you need any more information or you have found the
error,please mail me at viju_1181@yahoo.com.

Thanks in advance,
Vijaya
.
Bart Jacobs - 15 Nov 2003 21:39 GMT
I do not have access to the Powersoft OpenLibrary API DLL
<http://sybooks.sybase.com/onlinebooks/group-pb/adt0650e/orca/>, so I
created a fake replacement for it:

---- Begin ORCA.DLL ----------------------------------------------------

#define PBORCA_MAXCOMMENT 255

typedef int PBORCA_TYPE;

typedef void *HPBORCA;

typedef struct pborca_direntry {
    CHAR szComments[PBORCA_MAXCOMMENT + 1];
    LONG lCreateTime;
    LONG lEntrySize;
    LPSTR lpszEntryName;
    PBORCA_TYPE otEntryType;
} PBORCA_DIRENTRY, FAR *PPBORCA_DIRENTRY;

typedef void (FAR PASCAL *PBORCA_LISTPROC) ( PPBORCA_DIRENTRY, LPVOID );

extern "C" __declspec(dllexport) int PBORCA_LibraryDirectory ( HPBORCA
hORCASession, LPSTR lpszLibName, LPSTR lpszLibComments, int
iCmntsBuffSize, PBORCA_LISTPROC pListProc, LPVOID pUserData );

int PBORCA_LibraryDirectory ( HPBORCA hORCASession, LPSTR lpszLibName,
LPSTR lpszLibComments, int iCmntsBuffSize, PBORCA_LISTPROC pListProc,
LPVOID pUserData )
{
    strncpy(lpszLibComments, "These are the library comments.",
iCmntsBuffSize);
    pborca_direntry entry;
    entry.lCreateTime = 1;
    entry.lEntrySize = 100;
    entry.lpszEntryName = "Entry 1";
    entry.otEntryType = 3;
    strcpy(entry.szComments, "These are the comments for entry one.");
    pListProc(&entry, pUserData);
    entry.lCreateTime = 2;
    entry.lEntrySize = 200;
    entry.lpszEntryName = "Entry 2";
    entry.otEntryType = 4;
    strcpy(entry.szComments, "These are the comments for entry two.");
    pListProc(&entry, pUserData);
    return 0;
}

---- End ORCA.DLL ------------------------------------------------------

The following C# executable works perfectly with ORCA.DLL.

---- Begin ORCAClient.EXE ----------------------------------------------

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace ORCAClient
{
    [StructLayout(LayoutKind.Sequential)]
    public sealed class DirectoryEntry
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
        public string Comments;
        public int CreateTime;
        public int EntrySize;
        public string EntryName;
        public int EntryType; // int or short?

        public void WriteToConsole()
        {
            Console.WriteLine("Comments: " + Comments);
            Console.WriteLine("CreateTime: " + CreateTime);
            Console.WriteLine("EntrySize: " + EntrySize);
            Console.WriteLine("EntryName: " + EntryName);
            Console.WriteLine("EntryType: " + EntryType);
        }
    }

    public delegate void DirectoryCallback(DirectoryEntry entry, IntPtr
userData);

    public sealed class ORCASession
    {
        ORCASession() {}

        [DllImport("ORCA.DLL")]
        public static extern int PBORCA_LibraryDirectory(IntPtr sessionHandle,
string libraryName, StringBuilder libraryCommentsBuffer, int
libraryCommentsBufferSize, DirectoryCallback callback, IntPtr userData);
    }

    class Test
    {
        static void TestCallback(DirectoryEntry entry, IntPtr userData)
        {
            Console.WriteLine("Callback called.");
            entry.WriteToConsole();
        }

        static void Main(string[] args)
        {
            StringBuilder comments = new StringBuilder(256);
            int result = ORCASession.PBORCA_LibraryDirectory(IntPtr.Zero,
"MyLibrary", comments, comments.Capacity, new
DirectoryCallback(TestCallback), IntPtr.Zero);
            Console.WriteLine("Result: " + result);
            Console.WriteLine("Library comments: " + comments);
            Console.ReadLine();
        }
    }
}

---- End ORCAClient.EXE ------------------------------------------------

Note that you do not need to use GC.KeepAlive to keep your delegate
object alive, since it is automatically kept alive by P/Invoke for the
duration of the PBORCA_LibraryDirectory call.

Note also that the userData value is not very useful for managed code.
It is easier and more statically typed to pass an instance method as the
callback delegate. The target object of the delegate serves as user
data. See the following example:

---- Begin ORCAClient.EXE Version 2 ------------------------------------

using System;
using System.Collections;
using System.Text;
using System.Runtime.InteropServices;

namespace ORCAClient
{
    [StructLayout(LayoutKind.Sequential)]
    sealed class DirectoryEntry
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
        public string Comments;
        public int CreateTime;
        public int EntrySize;
        public string EntryName;
        public int EntryType; // int or short?

        public void WriteToConsole()
        {
            Console.WriteLine("Comments: " + Comments);
            Console.WriteLine("CreateTime: " + CreateTime);
            Console.WriteLine("EntrySize: " + EntrySize);
            Console.WriteLine("EntryName: " + EntryName);
            Console.WriteLine("EntryType: " + EntryType);
        }
    }

    delegate void DirectoryCallback(DirectoryEntry entry, IntPtr userData);

    sealed class ORCASession
    {
        ORCASession() {}

        [DllImport("ORCA.DLL")]
        public static extern int PBORCA_LibraryDirectory(IntPtr sessionHandle,
string libraryName, StringBuilder libraryCommentsBuffer, int
libraryCommentsBufferSize, DirectoryCallback callback, IntPtr userData);
    }

    class DirectoryListing
    {
        ArrayList entries = new ArrayList();

        public void MyDirectoryCallback(DirectoryEntry entry, IntPtr userData)
        {
            entries.Add(entry);
        }

        public void WriteToConsole()
        {
            foreach(DirectoryEntry entry in entries)
            {
                entry.WriteToConsole();
            }
        }
    }

    class Test
    {
        static void Main(string[] args)
        {
            DirectoryListing listing = new DirectoryListing();
            StringBuilder comments = new StringBuilder(256);
            int result = ORCASession.PBORCA_LibraryDirectory(IntPtr.Zero,
"MyLibrary", comments, comments.Capacity, new
DirectoryCallback(listing.MyDirectoryCallback), IntPtr.Zero);
            Console.WriteLine("Result: " + result);
            Console.WriteLine("Library comments: " + comments);
            listing.WriteToConsole();
            Console.ReadLine();
        }
    }
}

---- End ORCAClient.EXE Version 2 --------------------------------------

Hope this helps...

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.