Subject | Re: C Language ServiceManager Interface DLL? |
---|---|
Author | Dan Cooperstock |
Post date | 2007-12-19T20:58:24Z |
--- In firebird-support@yahoogroups.com, "Dan Cooperstock" <dcoops@...>
wrote:
Here is the code, that you can compile into a Windows DLL (or
presumably anything else, with appropriate changes). I compiled it as
non-UNICODE (not defining _MBCS or _UNICODE), because that works best
with PB (PowerBuilder). I also needed a DEF file to give it a good
callable name from PB.
Here is the code:
#include <stdio.h>
#include <string.h>
#include "ibase.h"
// Local prototypes
void interpret_messages(ISC_STATUS *status_vector, char *messages, int
messagesLen);
/* Use the Firebird ServiceManager funtions to do a backup.
* Parameters:
* server: Hostname of the server to run this on, or the empty
string for local
* user: User name to log in as
* pwd: Password for that user
* dbFile: The full pathname of the database file to back up
(will be on the server, if server is not empty)
* backupFile: The full pathname of the file to back up to (will be
on the server, if server is not empty)
* messages: Write any messages from the backup (probably error
messages) into here
* messagesLen: Amount of space in the messages string (don't write
more than this)
*
* Returns 0 for success, 1 (plus a message in messages) for failure.
*/
int __declspec(dllexport) doBackup(char *server, char *user, char *pwd,
char *dbFile, char *backupFile,
char
*messages, int messagesLen)
{
char spb_buffer[200], *spb = spb_buffer, service_name[100];
isc_svc_handle service_handle = NULL;
unsigned short spb_length;
ISC_STATUS status[20];
char request[500], *p = request;
int retval = 0;
char request_buffer[] = { isc_info_svc_to_eof };
char result_buffer[2048];
// Attach to the Services Manager
*spb++ = isc_spb_version;
*spb++ = isc_spb_current_version;
*spb++ = isc_spb_user_name;
*spb++ = strlen(user);
strcpy(spb, user);
spb += strlen(user);
*spb++ = isc_spb_password;
*spb++ = strlen(pwd);
strcpy(spb, pwd);
spb += strlen(pwd);
spb_length = spb - spb_buffer;
if (!server || !*server)
strcpy(service_name, "service_mgr");
else
sprintf(service_name, "%s:service_mgr", server);
if (isc_service_attach(status, 0, service_name,
&service_handle, spb_length, spb_buffer))
{
interpret_messages(status, messages, messagesLen);
return 1;
}
// do the backup
// Identify action
*p++ = isc_action_svc_backup;
// Argument for database filename
*p++ = isc_spb_dbname;
ADD_SPB_LENGTH(p, strlen(dbFile));
strcpy(p, dbFile);
p += strlen(dbFile);
// Argument for backup output filename
*p++ = isc_spb_bkp_file;
ADD_SPB_LENGTH(p, strlen(backupFile));
strcpy(p, backupFile);
p += strlen(backupFile);
// Start the service (asynchronously)
if (isc_service_start(status, &service_handle, NULL, (unsigned
short)(p - request), request))
{
interpret_messages(status, messages, messagesLen);
retval = 1;
goto DETACH;
}
// Get the results
spb = spb_buffer;
p = result_buffer;
*spb++ = isc_info_svc_timeout;
ADD_SPB_NUMERIC(spb, 30); /* 30 second timeout */
if (isc_service_query (status, &service_handle, NULL,
(unsigned short)
(spb - spb_buffer), spb_buffer,
sizeof
(request_buffer), request_buffer,
sizeof
(result_buffer), result_buffer))
{
interpret_messages(status, messages, messagesLen);
retval = 1;
goto DETACH;
}
if (*p == isc_info_svc_to_eof)
{
spb_length = (unsigned short)isc_vax_integer(p + 1,
sizeof(unsigned short));
if (spb_length < (unsigned)messagesLen)
{
strncpy(messages, p + 3, spb_length);
messages[spb_length] = '\0';
}
else
{
strncpy(messages, p + 3, messagesLen - 34);
strcpy(messages + messagesLen - 34, "\r\n-
Firebird messages too long");
}
}
else
{
strcpy(messages, "Could not determine results of
backup, due to 30-second timeout waiting for results.");
retval = 1;
}
DETACH:
// must detach when we are done!
isc_service_detach(status, &service_handle);
//MessageBox(NULL, "Test message", "FirebirdServer", 0);
//strcpy(messages, "DLL successfully attached and detached");
return retval;
}
/* Expand status messages from status_vector into messages, filling at
most messagesLen bytes. */
void interpret_messages(ISC_STATUS *status_vector, char *messages, int
messagesLen)
{
char msg[512];
long *pvector = status_vector; /* Pointer to pointer to status
vector. */
isc_interprete(msg, &pvector); /* Retrieve first message. */
if (strlen(msg) < (unsigned)messagesLen)
strcpy(messages, msg);
else if (messagesLen > 30)
strcpy(messages, "Firebird messages too long");
while(isc_interprete(msg, &pvector)) /* More messages? */
{
if (strlen(msg) + 4 + strlen(messages) < (unsigned)
messagesLen)
{
strcat(messages, "\r\n- ");
strcat(messages, msg);
}
else if (strlen(msg) + 34 < (unsigned)messagesLen)
{
strcat(messages, "\r\n- Firebird messages too
long");
break;
}
}
}
If you are calling this from PowerBuilder, the following External
Function definition is required (assuming the DLL is called
FirebirdService.dll):
Function long FBdoBackup(string server, string user, string pwd, string
dbFile, string backupFile, REF string messages, long messagesLen) &
LIBRARY "FirebirdService.DLL" alias for "doBackup;Ansi"
Also, when calling it from PB, you have to initialize a string variable
for the messages argument to have room in it for writing, with code
like:
string messages
messages = Space(1000)
and then pass 1000 as messageLen.
Finally, in PB, when you call this, you have to remember to precede the
messages argument with "REF", or the value copied into it by the C code
won't come through.
wrote:
>need
> I need to call the ServiceManager from PowerBuilder, which means I
> to build a C-language DLL - I can't call the C++ classes in IBPP.OK, so I gave in and did the part of this that I need (backups) myself.
>
> Has anyone done this, who would be willing to supply the code? All I
> really need is to be able to do a backup using ServiceManager,
> supplying an optional server, username, password, database to backup,
> and single backup filename, and somehow get back any results.
>
> I need this because of the bug in GBAK, where it doesn't handle
> filenames containing spaces if you are using the ServiceManager.
>
> Thanks.
Here is the code, that you can compile into a Windows DLL (or
presumably anything else, with appropriate changes). I compiled it as
non-UNICODE (not defining _MBCS or _UNICODE), because that works best
with PB (PowerBuilder). I also needed a DEF file to give it a good
callable name from PB.
Here is the code:
#include <stdio.h>
#include <string.h>
#include "ibase.h"
// Local prototypes
void interpret_messages(ISC_STATUS *status_vector, char *messages, int
messagesLen);
/* Use the Firebird ServiceManager funtions to do a backup.
* Parameters:
* server: Hostname of the server to run this on, or the empty
string for local
* user: User name to log in as
* pwd: Password for that user
* dbFile: The full pathname of the database file to back up
(will be on the server, if server is not empty)
* backupFile: The full pathname of the file to back up to (will be
on the server, if server is not empty)
* messages: Write any messages from the backup (probably error
messages) into here
* messagesLen: Amount of space in the messages string (don't write
more than this)
*
* Returns 0 for success, 1 (plus a message in messages) for failure.
*/
int __declspec(dllexport) doBackup(char *server, char *user, char *pwd,
char *dbFile, char *backupFile,
char
*messages, int messagesLen)
{
char spb_buffer[200], *spb = spb_buffer, service_name[100];
isc_svc_handle service_handle = NULL;
unsigned short spb_length;
ISC_STATUS status[20];
char request[500], *p = request;
int retval = 0;
char request_buffer[] = { isc_info_svc_to_eof };
char result_buffer[2048];
// Attach to the Services Manager
*spb++ = isc_spb_version;
*spb++ = isc_spb_current_version;
*spb++ = isc_spb_user_name;
*spb++ = strlen(user);
strcpy(spb, user);
spb += strlen(user);
*spb++ = isc_spb_password;
*spb++ = strlen(pwd);
strcpy(spb, pwd);
spb += strlen(pwd);
spb_length = spb - spb_buffer;
if (!server || !*server)
strcpy(service_name, "service_mgr");
else
sprintf(service_name, "%s:service_mgr", server);
if (isc_service_attach(status, 0, service_name,
&service_handle, spb_length, spb_buffer))
{
interpret_messages(status, messages, messagesLen);
return 1;
}
// do the backup
// Identify action
*p++ = isc_action_svc_backup;
// Argument for database filename
*p++ = isc_spb_dbname;
ADD_SPB_LENGTH(p, strlen(dbFile));
strcpy(p, dbFile);
p += strlen(dbFile);
// Argument for backup output filename
*p++ = isc_spb_bkp_file;
ADD_SPB_LENGTH(p, strlen(backupFile));
strcpy(p, backupFile);
p += strlen(backupFile);
// Start the service (asynchronously)
if (isc_service_start(status, &service_handle, NULL, (unsigned
short)(p - request), request))
{
interpret_messages(status, messages, messagesLen);
retval = 1;
goto DETACH;
}
// Get the results
spb = spb_buffer;
p = result_buffer;
*spb++ = isc_info_svc_timeout;
ADD_SPB_NUMERIC(spb, 30); /* 30 second timeout */
if (isc_service_query (status, &service_handle, NULL,
(unsigned short)
(spb - spb_buffer), spb_buffer,
sizeof
(request_buffer), request_buffer,
sizeof
(result_buffer), result_buffer))
{
interpret_messages(status, messages, messagesLen);
retval = 1;
goto DETACH;
}
if (*p == isc_info_svc_to_eof)
{
spb_length = (unsigned short)isc_vax_integer(p + 1,
sizeof(unsigned short));
if (spb_length < (unsigned)messagesLen)
{
strncpy(messages, p + 3, spb_length);
messages[spb_length] = '\0';
}
else
{
strncpy(messages, p + 3, messagesLen - 34);
strcpy(messages + messagesLen - 34, "\r\n-
Firebird messages too long");
}
}
else
{
strcpy(messages, "Could not determine results of
backup, due to 30-second timeout waiting for results.");
retval = 1;
}
DETACH:
// must detach when we are done!
isc_service_detach(status, &service_handle);
//MessageBox(NULL, "Test message", "FirebirdServer", 0);
//strcpy(messages, "DLL successfully attached and detached");
return retval;
}
/* Expand status messages from status_vector into messages, filling at
most messagesLen bytes. */
void interpret_messages(ISC_STATUS *status_vector, char *messages, int
messagesLen)
{
char msg[512];
long *pvector = status_vector; /* Pointer to pointer to status
vector. */
isc_interprete(msg, &pvector); /* Retrieve first message. */
if (strlen(msg) < (unsigned)messagesLen)
strcpy(messages, msg);
else if (messagesLen > 30)
strcpy(messages, "Firebird messages too long");
while(isc_interprete(msg, &pvector)) /* More messages? */
{
if (strlen(msg) + 4 + strlen(messages) < (unsigned)
messagesLen)
{
strcat(messages, "\r\n- ");
strcat(messages, msg);
}
else if (strlen(msg) + 34 < (unsigned)messagesLen)
{
strcat(messages, "\r\n- Firebird messages too
long");
break;
}
}
}
If you are calling this from PowerBuilder, the following External
Function definition is required (assuming the DLL is called
FirebirdService.dll):
Function long FBdoBackup(string server, string user, string pwd, string
dbFile, string backupFile, REF string messages, long messagesLen) &
LIBRARY "FirebirdService.DLL" alias for "doBackup;Ansi"
Also, when calling it from PB, you have to initialize a string variable
for the messages argument to have room in it for writing, with code
like:
string messages
messages = Space(1000)
and then pass 1000 as messageLen.
Finally, in PB, when you call this, you have to remember to precede the
messages argument with "REF", or the value copied into it by the C code
won't come through.