Solved

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

Posted on 2002-06-18
20
886 Views
Last Modified: 2013-12-23
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
0
Comment
Question by:aquila98
[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
  • 10
  • 9
20 Comments
 
LVL 63

Expert Comment

by:SysExpert
ID: 7090349
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 !
0
 
LVL 86

Expert Comment

by:jkr
ID: 7090683
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)
0
 
LVL 86

Expert Comment

by:jkr
ID: 7090707
BTW - if you still want to pursue the 'RPC_IF_CALLBACK_FN' path, see http://www.ntdev.org/archive/ntdev0001/msg0272.html
0
Efficient way to get backups off site to Azure

This user guide provides instructions on how to deploy and configure both a StoneFly Scale Out NAS Enterprise Cloud Drive virtual machine and Veeam Cloud Connect in the Microsoft Azure Cloud.

 
LVL 2

Author Comment

by:aquila98
ID: 7090839
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();
...

???
0
 
LVL 86

Expert Comment

by:jkr
ID: 7091066
In the above example:

int     ShutDownCallBack (     void)
{
     // ...

     return     (     0);
}

MIDL will generate the code that calls the callback implementation.
0
 
LVL 86

Accepted Solution

by:
jkr earned 200 total points
ID: 7091069
BTW, here is the (generated) stub code:

void __RPC_STUB
TheServer_ShutDownCallback(
    PRPC_MESSAGE _pRpcMessage )
{
    int _RetVal;
    MIDL_STUB_MESSAGE _StubMsg;
    RPC_STATUS _Status;

    ((void)(_Status));
    NdrServerInitializeNew(
                          _pRpcMessage,
                          &_StubMsg,
                          &IRLicSrv_StubDesc);

    RpcTryFinally
        {
        RpcTryExcept
            {
            if(_StubMsg.Buffer > _StubMsg.BufferEnd)
                {
                RpcRaiseException(RPC_X_BAD_STUB_DATA);
                }
            }
        RpcExcept( RPC_BAD_STUB_DATA_EXCEPTION_FILTER )
            {
            RpcRaiseException(RPC_X_BAD_STUB_DATA);
            }
        RpcEndExcept

        _RetVal = ShutDownCallback();

        _StubMsg.BufferLength = 4U;
        _pRpcMessage->BufferLength = _StubMsg.BufferLength;

        _Status = I_RpcGetBuffer( _pRpcMessage );
        if ( _Status )
            RpcRaiseException( _Status );

        _StubMsg.Buffer = (unsigned char __RPC_FAR *) _pRpcMessage->Buffer;

        *(( int __RPC_FAR * )_StubMsg.Buffer)++ = _RetVal;

        }
    RpcFinally
        {
        }
    RpcEndFinally
    _pRpcMessage->BufferLength =
        (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer);

}
0
 
LVL 2

Author Comment

by:aquila98
ID: 7092330
thanks it works ;-)
0
 
LVL 2

Author Comment

by:aquila98
ID: 7097100
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.

???
0
 
LVL 86

Expert Comment

by:jkr
ID: 7115479
Sorry, I didn't ever get a notif for your last comment (see also http://www.experts-exchange.com/jsp/qManageQuestion.jsp?qid=2030914999 - I'll check about the bindings...
0
 
LVL 2

Author Comment

by:aquila98
ID: 7124684
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!

???
0
 
LVL 86

Expert Comment

by:jkr
ID: 7145001
Iiih, yikes, sorry - just saw this one by chance by going through old Qs - do you still have that problem?
0
 
LVL 2

Author Comment

by:aquila98
ID: 7145788
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
0
 
LVL 86

Expert Comment

by:jkr
ID: 7147863
>>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...
0
 
LVL 2

Author Comment

by:aquila98
ID: 7148818
0
 
LVL 2

Author Comment

by:aquila98
ID: 7148819
0
 
LVL 2

Author Comment

by:aquila98
ID: 7148825
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
http://www.experts-exchange.com/jsp/qManageQuestion.jsp?qid=20317066
0
 
LVL 86

Expert Comment

by:jkr
ID: 7150079
>>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?
0
 
LVL 2

Author Comment

by:aquila98
ID: 7150097
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!
0
 
LVL 2

Author Comment

by:aquila98
ID: 7165118
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

!
0
 
LVL 86

Expert Comment

by:jkr
ID: 7172686
>>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...
0

Featured Post

Online Training Solution

Drastically shorten your training time with WalkMe's advanced online training solution that Guides your trainees to action. Forget about retraining and skyrocket knowledge retention rates.

Question has a verified solution.

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

Suggested Solutions

Sometimes you might need to configure routing based not only on destination IP address, but also on a combination of destination IP address (or hostname) and destination port number. I will describe a method how to accomplish this with free tools. …
Greetings, Experts! First let me state that this website is top notch. I thoroughly enjoy the community that is shared here; those seeking help and those willing to sacrifice their time to help. It is fantastic. I am writing this article at th…
How to Install VMware Tools in Red Hat Enterprise Linux 6.4 (RHEL 6.4) Step-by-Step Tutorial

738 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