Link to home
Start Free TrialLog in
Avatar of aquila98
aquila98

asked on

RPC server in NT... How to pass callback from client????

Hello,

I'd like to know how to code a function in my IDL so that
a client can pass a callback function pointer to the server?
Is there an example of this kind of stuff available???

All I have so far is RPC_IF_CALLBACK_FN but I have yet to
find any example of how to use it? I don't know if this
is the kind of stuff I should use?

I need something like:
error_status_t ShutDown(
              [size_is(PwdLength), in ] byte Password[],
              [in] unsigned long PwdLength,
---------->>>    [in] RPC_IF_CALLBACK_FN aClientFunctionPtr
             );

Any hints will be appreciated ;-)

thanks
Avatar of SysExpert
SysExpert
Flag of Israel image

I would post this is the programming section of EE, rather than here.

You can post just a link back to here so that you get twice the bang for your points.

I hope this helps !
I did something similar a while ago, but I defined the function in the interface itself (which is IMHO better, as you are free to provide whatever function signature you want):

[ uuid (<removed>),
  version(1.0),
  pointer_default(unique)
]
interface TheServer
{

error_status_t ShutDown(
             [size_is(PwdLength), in ] byte Password[],
             [in] unsigned long PwdLength
            );

[ callback]
unsigned int    ShutDownCallBack  ( );
};

Anyway, you will have to declare the callback in the interface also, as MIDL needs to generate stubs for that function - or you are willing to use 'RpcServerRegisterIfEx()' (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/rpc/pr-func2_9prs.asp)
BTW - if you still want to pursue the 'RPC_IF_CALLBACK_FN' path, see http://www.ntdev.org/archive/ntdev0001/msg0272.html
Avatar of aquila98
aquila98

ASKER

And just how is the client suposed to implement ShutDownCallBack???

The server will do something like this:
error_status_t ShutDown(
            [size_is(PwdLength), in ] byte Password[],
            [in] unsigned long PwdLength
           )
{ ...
    ShutDownCallBack();
}

while the client is expected to do this:
 myserver->ShutDown();
...

???
In the above example:

int     ShutDownCallBack (     void)
{
     // ...

     return     (     0);
}

MIDL will generate the code that calls the callback implementation.
ASKER CERTIFIED SOLUTION
Avatar of jkr
jkr
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
thanks it works ;-)
I should say It compiled :)

Now I have it running and the client does NOT receive any
thing when the server executes a callback function. There
is NO error on the server side, just that the client's side
callback function never gets executed...

Should I do anything special during client binding to
say that I can get a rpc from the server? My protocol is
tcp_ip by the way.

???
Sorry, I didn't ever get a notif for your last comment (see also https://www.experts-exchange.com/jsp/qManageQuestion.jsp?qid=2030914999 - I'll check about the bindings...
Thanks,

I posted an another question in case you wish to get 100 points more ;-)

Strange, I get no compilation error, no runtime errors
and yet the client's function never gets executed, but the
server does call them!

???
Iiih, yikes, sorry - just saw this one by chance by going through old Qs - do you still have that problem?
yes, for some reason there are no errors during compile or run time but whenever the server calls a callback function the client's code never gets executed!

Should I put the callback function in the acf like the other "regular" rpc call? How can I trace within the stub to see where the error occurs? Any other way to do this? I am not familar with RPC_IF_CALLBACK_FN's way. Do you have a working example by chance???

thanks
>>Do you have a working example by chance???

I have a "production" license server that I wrote which uses the same way to detect whether the clients are "alive" by implementing a "ping" RPC callback, but I cannot post code - but, you could. There might be just a detail missing...
Here is the server's idl:
interface SOPFEUMETEORpcService
{
    const unsigned long BUFFER_SIZE = 100;
    typedef struct {
        unsigned long BufferLength;
        [unique, size_is(BufferLength)] byte *Buffer;
        } BUFFER;
error_status_t Ping();
error_status_t ReloadURL([size_is(BufferLength), in ] byte Key[],
                       [in] unsigned long BufferLength);
error_status_t ShutDown([size_is(PwdLength), in ] byte Password[],
                      [in] unsigned long PwdLength);
error_status_t GetRootDirectory([out] BUFFER *pBuffer);
[callback] error_status_t ReLoadCallback([in, string] char* key);
[callback] error_status_t UrlLoadedCallback([in, string] char* url, [in, string] char* dir);
[callback] error_status_t ErrUrlLoadedCallback([in, string] char* url, [in, string] char* dir, [in, string] char* err);
}

Its acf:
[implicit_handle (handle_t global_SOPFEUMETEO_handle)]
interface SOPFEUMETEORpcService
{
    [comm_status, fault_status] Ping();
    [comm_status, fault_status] ReloadURL();
    [comm_status, fault_status] ShutDown();
    [comm_status, fault_status] GetRootDirectory();
      [comm_status, fault_status] ReLoadCallback();
      [comm_status, fault_status] UrlLoadedCallback();
      [comm_status, fault_status] ErrUrlLoadedCallback();
      [comm_status, fault_status] GetServerInCharge();
}
I tried to put the callback within the acf... Is this ok?

Now the server code where it is usig the callback:
error_status_t ReloadURL(byte Key[], unsigned long pwdLength)
{
      static char buf[1000];

      if (!SUCCEEDED(g_LoadFunction(NULL)))
            return RPC_S_ENTRY_NOT_FOUND;

      memset(buf, 0, 999);
      strncpy(buf, Key, pwdLength);
      ReLoadCallback(buf);
    return(0);
}

within the stub ReloadCallBack is defined as:
SOPFEUMETEORpcService_ReLoadCallback(...

On the client side, the callback functions are defined thus
to ensure that there is no undefined symbol (because of
c++ mangeling I guess, that's the only way I figured to get
it to link)
extern void Callback_ReLoadCallback(const char* key);
extern void Callback_UrlLoadedCallback(const char* url, const char* dir);
extern void Callback_ErrUrlLoadedCallback(const char* url, const char* dir, const char* err);
unsigned long ReLoadCallback(char * key)
{
      Callback_ReLoadCallback(key);
      return (0);
}

unsigned long UrlLoadedCallback(char * url, char* dir)
{
      Callback_UrlLoadedCallback(url, dir);
      return (0);
}

unsigned long ErrUrlLoadedCallback(char * url, char* dir, char * err)
{
      Callback_ErrUrlLoadedCallback(url, dir, err);
      return (0);
}

These functions are in their own .c file NOT using pre-
compiled header.

Now within a singleton controller class (RPCClient) I
have these functions that are called by the callback
(declared external above)
extern "C" {

void Callback_ReLoadCallback(const char* key)
{
  Beep(300,300);
  // this the a call to my singleton class
  if (RPCClient::Instance()->GetClientWindowPtr())
            ::SendMessage(RPCClient::Instance()->GetClientWindowPtr(), RPCClient::Instance()->GetMessageReloadID(), (WPARAM) NULL, (LPARAM) key);
}

void Callback_UrlLoadedCallback(const char* url, const char* dir)
{
      Beep(300,300);
      if (RPCClient::Instance()->GetClientWindowPtr())
            ::SendMessage(RPCClient::Instance()->GetClientWindowPtr(), RPCClient::Instance()->GetMessageLoadingUrlID(), (WPARAM) url, (LPARAM) dir);
}

void Callback_ErrUrlLoadedCallback(const char* url, const char* dir, const char* err)
{
      CString tmp= url;
      tmp += " :: ";
      tmp += dir;
      Beep(300,300);
      if (RPCClient::Instance()->GetClientWindowPtr())
            ::SendMessage(RPCClient::Instance()->GetClientWindowPtr(), RPCClient::Instance()->GetMessageErrorLoadingUrlID(), (WPARAM) (LPCTSTR)tmp, (LPARAM) err);
}

}

And no beeps are heard, no messages sent and a breakpoint
anywhere within the callback functions on the client's side never gets executed :(

Anything wrong with that layout??? hints?

thanks

ps there are 100 points waiting for you in
https://www.experts-exchange.com/jsp/qManageQuestion.jsp?qid=20317066
>>I tried to put the callback within the acf... Is this ok?

Acually, your .acf file doesn't need to contain anything but

implicit_handle (handle_t global_SOPFEUMETEO_handle)]
interface SOPFEUMETEORpcService
{
}

You are linking the client with SOPFEUMETEORpcService_c.c, are you?
Yes,

I have included in my project the rpcsvc_c.c file
(first few lines:
//@@MIDL_FILE_HEADING(  )

#include <string.h>
#if defined( _ALPHA_ )
#include <stdarg.h>
#endif

#include "rpcsvc.h"
)

I liked the acf because I used to work with DCE RPC and via
the acf we could get more error info ;-) does not seems to
be of use in NT though!

have a nice week end!
Hmmm...

I moved the server from a NT machine tou our production
server which is running W2k AS and behold! It is now
working!

I did make a great amount of chance to the client and a
good cleanup and rebuild in release might have also
contributed to the success of the callback? Or is there a
problem with NT???

Thanks for all your help

!
>>Or is there a problem with NT???

Not that I would know of - at least not a general problem, maybe a configuration problem. The server I mentioned runs on both...