Windows service shut down - winapi

I use VS6 and ATL with CServiceModule to implement a custom windows service. In case of a fatal error service should shut itself down. Since CServiceModule is available via _Module variable in all files I thought of something like this to cause CServiceModule::Run to stop pumping messages and shut itself down
PostThreadMessage(_Module.dwThreadID, WM_QUIT, 0, 0);
Is this correct or you have better idea ?

For self shutdown you send command to Service Manager. Try this sample :
BOOL StopServiceCmd ( const char * szServiceName )
{
SC_HANDLE schService;
SC_HANDLE schSCManager;
SERVICE_STATUS ssStatus; // current status of the service
BOOL bRet;
int iCont=0;
schSCManager = OpenSCManager(
NULL, // machine (NULL == local)
NULL, // database (NULL == default)
SC_MANAGER_ALL_ACCESS // access required
);
if ( schSCManager )
{
schService = OpenService(schSCManager, szServiceName, SERVICE_ALL_ACCESS);
if (schService)
{
// try to stop the service
if ( ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus ) )
{
Sleep( 1000 );
while( QueryServiceStatus( schService, &ssStatus ) )
{
iCont++;
if ( ssStatus.dwCurrentState == SERVICE_STOP_PENDING )
{
Sleep( 1000 );
if ( iCont > 4 ) break;
}
else
break;
}
if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
bRet = TRUE;
else
bRet = FALSE;
}
CloseServiceHandle(schService);
}
else
bRet = FALSE;
CloseServiceHandle(schSCManager);
}
else
bRet = FALSE;
return bRet;
}

I believe that if you do this, then the service manager will think that your service has crashed and if the user ever sets it up to auto-restart, it will.
In .NET, you use the ServiceController to signal your service to shut down. I expect it is similar in Win32 since most of this stuff in .NET is just wrappers. Sorry, I don't have C++ code handy to shut down the service, but here is the .NET code. This will hopefully help you Google the info you need, or find the docs in MSDN.
This is from some test suite code, thus the style of error checking ;) You will need to put this code in a thread so that the shutdown message gets handled.
private void stopPLService( bool close )
{
if ( m_serviceController == null )
{
m_serviceController = new ServiceController( "PLService" );
}
WriteLine( "StopPLService" );
if ( m_serviceController != null )
{
try
{
m_serviceController.Stop();
}
catch
{
// Probably just means that it wasn't running or installed, ignore
}
// Wait up to 30 seconds for the service to stop
try
{
m_serviceController.WaitForStatus( ServiceControllerStatus.Stopped, new TimeSpan( 0, 0, 30 ) );
}
catch ( System.ServiceProcess.TimeoutException )
{
Assert.Fail( "Timeout waiting for PLService to stop" );
}
catch
{
// Not installed, we only care in the start
}
if ( close )
{
m_serviceController.Close();
m_serviceController = null;
}
}
}

You probably want to use the ControlService or ControlServiceEx methods to shutdown your service. You should be able to get the required handle from the CServiceModule.

Related

what APIs are available to connect to IBM websphere MQ

I have a requirement, where I need to use IBM websphere message queue pub sub functionality.
Basically I have to write the subscriber part.
I need to know what all programming languages I can use to write the API other than java.
Can I write it using perl/shell/python?
There is PyMQI available for Python lovers. But note this offering is NOT from IBM.
Use MQ Client API. It does include samples for C++ like this one:
int main ( int argc, char * * argv ) {
ImqQueueManager mgr; // Queue manager
ImqQueue queue; // Queue
ImqMessage msg; // Data message
ImqGetMessageOptions gmo; // Get message options
char buffer[ 101 ]; // Message buffer
ImqChannel * pchannel = 0 ; // Channel definition
printf( "Sample IMQSGET start\n" );
if ( argc < 2 ) {
printf( "Required parameter missing - queue name\n" );
exit( 99 );
}
// Create object descriptor for subject queue
queue.setName( argv[ 1 ] );
if ( argc > 2 ) {
mgr.setName( argv[ 2 ] );
}
// Define a channel for client communication.
if ( argc > 3 ) {
ImqString strParse( argv[ 3 ] );
ImqString strToken ;
pchannel = new ImqChannel ;
pchannel -> setHeartBeatInterval( 1 );
// Break down the channel definition,
// which is of the form "channel-name/transport-type/connection-name".
if ( strParse.cutOut( strToken, '/' ) ) {
pchannel -> setChannelName( strToken );
if ( strParse.cutOut( strToken, '/' ) ) {
// Interpret the transport type.
if ( strToken.upperCase( ) == (ImqString)"LU62" ) {
pchannel -> setTransportType( MQXPT_LU62 );
}
if ( strToken.upperCase( ) == (ImqString)"NETBIOS" ) {
pchannel -> setTransportType( MQXPT_NETBIOS );
}
if ( strToken.upperCase( ) == (ImqString)"SPX" ) {
pchannel -> setTransportType( MQXPT_SPX );
}
if ( strToken.upperCase( ) == (ImqString)"TCP" ) {
pchannel -> setTransportType( MQXPT_TCP );
}
// Establish the connection name.
if ( strParse.cutOut( strToken ) ) {
pchannel -> setConnectionName( strToken );
}
}
}
mgr.setChannelReference( pchannel );
}
// Connect to queue manager
if ( ! mgr.connect( ) ) {
/* stop if it failed */
printf( "ImqQueueManager::connect failed with reason code %ld\n",
(long)mgr.reasonCode( ) );
exit( (int)mgr.reasonCode( ) );
}
// Associate queue with queue manager.
queue.setConnectionReference( mgr );
// Open the named message queue for input; exclusive or shared
// use of the queue is controlled by the queue definition here
queue.setOpenOptions(
MQOO_INPUT_AS_Q_DEF /* open queue for input */
+ MQOO_FAIL_IF_QUIESCING
); /* but not if MQM stopping */
queue.open( );
/* report reason, if any; stop if failed */
if ( queue.reasonCode( ) ) {
printf( "ImqQueue::open ended with reason code %ld\n",
(long)queue.reasonCode( ) );
}
if ( queue.completionCode( ) == MQCC_FAILED ) {
printf( "unable to open queue for input\n" );
}
// Get messages from the message queue
// Loop until there is a failure
msg.useEmptyBuffer( buffer, sizeof( buffer ) - 1 );
/* buffer size available for GET */
gmo.setOptions( MQGMO_WAIT | /* wait for new messages */
MQGMO_FAIL_IF_QUIESCING );
gmo.setWaitInterval( 15000 ); /* 15 second limit for waiting */
while ( queue.completionCode( ) != MQCC_FAILED ) {
// In order to read the messages in sequence, MsgId and
// CorrelID must have the default value. MQGET sets them
// to the values in for message it returns, so re-initialise
// them before every call
msg.setMessageId( );
msg.setCorrelationId( );
if ( queue.get( msg, gmo ) ) {
// Display each message received
if ( msg.formatIs( MQFMT_STRING ) ) {
buffer[ msg.dataLength( ) ] = 0 ; /* add terminator */
printf( "message <%s>\n", msg.bufferPointer( ) );
} else {
printf( "Non-text message\n" );
}
} else {
/* report reason, if any */
if ( queue.reasonCode( ) == MQRC_NO_MSG_AVAILABLE ) {
/* special report for normal end */
printf( "no more messages\n" );
} else {
/* general report for other reasons */
printf( "ImqQueue::get ended with reason code %ld\n",
(long)queue.reasonCode( ) );
/* treat truncated message as a failure for this sample */
if ( queue.reasonCode( ) == MQRC_TRUNCATED_MSG_FAILED ) {
break ;
}
}
}
}
// Close the source queue (if it was opened)
if ( ! queue.close( ) ) {
/* report reason, if any */
printf( "ImqQueue::close failed with reason code %ld\n",
(long)queue.reasonCode( ) );
}
// Disconnect from MQM if not already connected (the
// ImqQueueManager object handles this situation automatically)
if ( ! mgr.disconnect( ) ) {
/* report reason, if any */
printf( "ImqQueueManager::disconnect failed with reason code %ld\n",
(long)mgr.reasonCode( ) );
}
// Tidy up the channel object if allocated.
if ( pchannel ) {
mgr.setChannelReference( );
delete pchannel ;
}
printf( "Sample IMQSGET end\n" );
return( 0 );
}
IBM offers MQ clients for the following languages:
C, C++, .NET, Java
WebSphere MQ provides support for the following programming procedural languages:
C
Visual Basic (Windows systems only)
COBOL
Assembler language (WebSphere MQ for z/OS® only)
RPG (WebSphere MQ for IBM® i only)
PL/I (WebSphere MQ for z/OS only)
These languages use the message queue interface (MQI) to access message queueing services.
WebSphere MQ provides support for:
.NET
ActiveX
C++
Java
JMS
These languages use the WebSphere MQ Object Model, which provides classes that provide the same functionality as WebSphere MQ calls and structure.
Fuente

How to reset WinHTTP proxy credentials after a failed request?

I need to write code to download a file and the requirements are as follows. If the application is configured to use a proxy, attempt to download via the proxy. If that fails, attempt a direct connection. If no proxy is configured, attempt a direct connection. High-level pseudo-code:
if(ProxyEnabled)
if(!DownloadWithProxy())
DownloadWithoutProxy()
else
DownloadWithoutProxy()
I'm using WinHTTP since this code will be running in a service. The actual downloading is straightforward but I'm having issues with the proxy settings. My current pseudo-code is as follows:
hSession = WinHttpOpen(..., WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, ...)
hConnect = WinHttpConnect(hSession, ...)
hRequest = WinHttpOpenRequest(hConnect, ...)
if(Proxy.Enabled)
{
// set proxy server
WinHttpSetOption(hRequest, WINHTTP_OPTION_PROXY, ServerName)
// set proxy credentials
WinHttpSetCredentials(hRequest, WINHTTP_AUTH_TARGET_PROXY, UserName, Password)
if(!DownloadFile(hRequest))
{
// reset proxy server
WinHttpSetOption(hRequest, WINHTTP_OPTION_PROXY, NULL)
// reset proxy credentials
WinHttpSetCredentials(hRequest, WINHTTP_AUTH_TARGET_PROXY, NULL, NULL)
DownloadFile(hRequest)
}
}
else
{
DownloadFile(hRequest)
}
Where DownloadFile() does the standard WinHttpSendRequest() and WinHttpReceiveResponse() sequence. Everything works fine except in the case where the download via the proxy fails. When that happens the call to WinHttpSetCredentials() to reset the credentials fails (with ERROR_INVALID_PARAMETER), and as a result the second call to DownloadFile() still tries to use the proxy (even though I reset it) and the credentials. NOTE: In this specific scenario I am using a valid proxy server but invalid proxy credentials to trigger the failure.
So I guess my question is what is the best approach? As far as I can tell it is not possible to reset the credentials set via WinHttpSetCredentials(), so I guess I should just recreate the request for each call to DownloadFile() rather than trying to be "clever" by reusing a single request object.
WinHttpSetCredentials() takes 6 parameters, one of which is the auth scheme. You have only shown 4 parameters, and do not say which auth scheme you are using. Overall, your sequence for authenticating is different than what MSDN suggests:
Authentication in WinHTTP
A typical WinHTTP application completes the following steps in order to handle authentication.
•Request a resource with WinHttpOpenRequest and WinHttpSendRequest.
•Check the response headers with WinHttpQueryHeaders.
•If a 401 or 407 status code is returned indicating that authentication is required, call WinHttpQueryAuthSchemes to find an acceptable scheme.
•Set the authentication scheme, username, and password with WinHttpSetCredentials.
•Resend the request with the same request handle by calling WinHttpSendRequest.
Also take note of this condition:
The credentials set by WinHttpSetCredentials are only used for one request. WinHTTP does not cache the credentials to use in other requests, which means that applications must be written that can respond to multiple requests. If an authenticated connection is re-used, other requests may not be challenged, but your code should be able to respond to a request at any time.
The documentation linked above includes the following code example for how to use WinHTTPSetCredentials() correctly:
#include <windows.h>
#include <winhttp.h>
#include <stdio.h>
#pragma comment(lib, "winhttp.lib")
DWORD ChooseAuthScheme( DWORD dwSupportedSchemes )
{
// It is the server's responsibility only to accept
// authentication schemes that provide a sufficient
// level of security to protect the servers resources.
//
// The client is also obligated only to use an authentication
// scheme that adequately protects its username and password.
//
// Thus, this sample code does not use Basic authentication
// becaus Basic authentication exposes the client's username
// and password to anyone monitoring the connection.
if( dwSupportedSchemes & WINHTTP_AUTH_SCHEME_NEGOTIATE )
return WINHTTP_AUTH_SCHEME_NEGOTIATE;
else if( dwSupportedSchemes & WINHTTP_AUTH_SCHEME_NTLM )
return WINHTTP_AUTH_SCHEME_NTLM;
else if( dwSupportedSchemes & WINHTTP_AUTH_SCHEME_PASSPORT )
return WINHTTP_AUTH_SCHEME_PASSPORT;
else if( dwSupportedSchemes & WINHTTP_AUTH_SCHEME_DIGEST )
return WINHTTP_AUTH_SCHEME_DIGEST;
else
return 0;
}
struct SWinHttpSampleGet
{
LPCWSTR szServer;
LPCWSTR szPath;
BOOL fUseSSL;
LPCWSTR szServerUsername;
LPCWSTR szServerPassword;
LPCWSTR szProxyUsername;
LPCWSTR szProxyPassword;
};
void WinHttpAuthSample( IN SWinHttpSampleGet *pGetRequest )
{
DWORD dwStatusCode = 0;
DWORD dwSupportedSchemes;
DWORD dwFirstScheme;
DWORD dwSelectedScheme;
DWORD dwTarget;
DWORD dwLastStatus = 0;
DWORD dwSize = sizeof(DWORD);
BOOL bResults = FALSE;
BOOL bDone = FALSE;
DWORD dwProxyAuthScheme = 0;
HINTERNET hSession = NULL,
hConnect = NULL,
hRequest = NULL;
// Use WinHttpOpen to obtain a session handle.
hSession = WinHttpOpen( L"WinHTTP Example/1.0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0 );
INTERNET_PORT nPort = ( pGetRequest->fUseSSL ) ?
INTERNET_DEFAULT_HTTPS_PORT :
INTERNET_DEFAULT_HTTP_PORT;
// Specify an HTTP server.
if( hSession )
hConnect = WinHttpConnect( hSession,
pGetRequest->szServer,
nPort, 0 );
// Create an HTTP request handle.
if( hConnect )
hRequest = WinHttpOpenRequest( hConnect,
L"GET",
pGetRequest->szPath,
NULL,
WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
( pGetRequest->fUseSSL ) ?
WINHTTP_FLAG_SECURE : 0 );
// Continue to send a request until status code
// is not 401 or 407.
if( hRequest == NULL )
bDone = TRUE;
while( !bDone )
{
// If a proxy authentication challenge was responded to, reset
// those credentials before each SendRequest, because the proxy
// may require re-authentication after responding to a 401 or
// to a redirect. If you don't, you can get into a
// 407-401-407-401- loop.
if( dwProxyAuthScheme != 0 )
bResults = WinHttpSetCredentials( hRequest,
WINHTTP_AUTH_TARGET_PROXY,
dwProxyAuthScheme,
pGetRequest->szProxyUsername,
pGetRequest->szProxyPassword,
NULL );
// Send a request.
bResults = WinHttpSendRequest( hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS,
0,
WINHTTP_NO_REQUEST_DATA,
0,
0,
0 );
// End the request.
if( bResults )
bResults = WinHttpReceiveResponse( hRequest, NULL );
// Resend the request in case of
// ERROR_WINHTTP_RESEND_REQUEST error.
if( !bResults && GetLastError( ) == ERROR_WINHTTP_RESEND_REQUEST)
continue;
// Check the status code.
if( bResults )
bResults = WinHttpQueryHeaders( hRequest,
WINHTTP_QUERY_STATUS_CODE |
WINHTTP_QUERY_FLAG_NUMBER,
NULL,
&dwStatusCode,
&dwSize,
NULL );
if( bResults )
{
switch( dwStatusCode )
{
case 200:
// The resource was successfully retrieved.
// You can use WinHttpReadData to read the
// contents of the server's response.
printf( "The resource was successfully retrieved.\n" );
bDone = TRUE;
break;
case 401:
// The server requires authentication.
printf(" The server requires authentication. Sending credentials...\n" );
// Obtain the supported and preferred schemes.
bResults = WinHttpQueryAuthSchemes( hRequest,
&dwSupportedSchemes,
&dwFirstScheme,
&dwTarget );
// Set the credentials before resending the request.
if( bResults )
{
dwSelectedScheme = ChooseAuthScheme( dwSupportedSchemes);
if( dwSelectedScheme == 0 )
bDone = TRUE;
else
bResults = WinHttpSetCredentials( hRequest,
dwTarget,
dwSelectedScheme,
pGetRequest->szServerUsername,
pGetRequest->szServerPassword,
NULL );
}
// If the same credentials are requested twice, abort the
// request. For simplicity, this sample does not check
// for a repeated sequence of status codes.
if( dwLastStatus == 401 )
bDone = TRUE;
break;
case 407:
// The proxy requires authentication.
printf( "The proxy requires authentication. Sending credentials...\n" );
// Obtain the supported and preferred schemes.
bResults = WinHttpQueryAuthSchemes( hRequest,
&dwSupportedSchemes,
&dwFirstScheme,
&dwTarget );
// Set the credentials before resending the request.
if( bResults )
dwProxyAuthScheme = ChooseAuthScheme(dwSupportedSchemes);
// If the same credentials are requested twice, abort the
// request. For simplicity, this sample does not check
// for a repeated sequence of status codes.
if( dwLastStatus == 407 )
bDone = TRUE;
break;
default:
// The status code does not indicate success.
printf("Error. Status code %d returned.\n", dwStatusCode);
bDone = TRUE;
}
}
// Keep track of the last status code.
dwLastStatus = dwStatusCode;
// If there are any errors, break out of the loop.
if( !bResults )
bDone = TRUE;
}
// Report any errors.
if( !bResults )
{
DWORD dwLastError = GetLastError( );
printf( "Error %d has occurred.\n", dwLastError );
}
// Close any open handles.
if( hRequest ) WinHttpCloseHandle( hRequest );
if( hConnect ) WinHttpCloseHandle( hConnect );
if( hSession ) WinHttpCloseHandle( hSession );
}
You just have to inject your WinHttpSetOption(WINHTTP_OPTION_PROXY) where appropriate, and be sure that you are handling authentication requests for both proxy and non-proxy connections (in case the target HTTP server requires its own authentication).

hp webos, pdk plugin defunct in hybrid app.

I have been trying to call a pdk plugin from the mojo hybrid app and have also tried the same with enyo app. In both cases my pdk plugin is shown as , Interesting thing is in case of enyo, i received the plugin_ready response which is sent after the plugin registration is complete.
in the web-os site, they mentioned that it is the issue with pdk plugin that makes it look defunct.
but i could not find a method to resolve it.
This is how my plugin looks,
PDL_bool powerCall(PDL_JSParameters *params) {
runsine();
char *reply = "Done";
PDL_JSReply(params, reply);
return PDL_TRUE;
}
int main(){
int result = SDL_Init(SDL_INIT_VIDEO);
PDL_Init(0);
PDL_RegisterJSHandler("pawar", powerCall);
PDL_JSRegistrationComplete();
PDL_CallJS("ready", NULL, 0); // this is for enyo
PDL_Quit();
SDL_Quit();
return 0;
}
please suggest me how to solve this issue. i know its a very simple task and am frustrated that its taking this long.
Thanks
Shankar
In your plugin you should enter an event loop after you call the "ready" function, and before you call the PDL_Quit() and SDL_Quit(). Not having an event loop causes the plugin process to quit right away.
Here is an example based on the "simple" app that ships with the PDK:
int main(){
int result = SDL_Init(SDL_INIT_VIDEO);
PDL_Init(0);
PDL_RegisterJSHandler("pawar", powerCall);
PDL_JSRegistrationComplete();
PDL_CallJS("ready", NULL, 0); // this is for enyo
atexit(SDL_Quit);
atexit(PDL_Quit);
SDL_Event Event;
bool paused = false;
while (1) {
bool gotEvent;
if (paused) {
SDL_WaitEvent(&Event);
gotEvent = true;
}
else {
gotEvent = SDL_PollEvent(&Event);
}
while (gotEvent) {
switch (Event.type) {
case SDL_ACTIVEEVENT:
if (Event.active.state == SDL_APPACTIVE) {
paused = !Event.active.gain;
}
break;
case SDL_QUIT:
// We exit anytime we get a request to quit the app
// all shutdown code is registered via atexit() so this is clean.
exit(0);
break;
// handle any other events interesting to your plugin here
default:
break;
}
gotEvent = SDL_PollEvent(&Event);
}
}
return 0;
}

boost deadline_timer not kicking off

We have written a single threaded client based on the boost asio. The client needs to implement a timeout, so that the connection is broken if the read or write from server was not completed in a stipulated time period. But the async_wait for the deadline_timer does not kick off untill I don't call run for the io_service. Now if I call run on the io_service then my reading and writing to the server is not possible.
Please see the excerpts from my current code:
typedef boost::scoped_ptr<boost::asio::ip::tcp::socket> SocketPtr;
typedef boost::shared_ptr<boost::asio::deadline_timer> DLTPtr;
SocketPtr m_SocketPtrClient;
DLPtr m_ClientTimeoutDLTPtr;
boost::asio::io_service ios;
m_SocketPtrClient.reset( new boost::asio::ip::tcp::socket( ios));
m_ClientTimeoutDLTPtr.reset( new deadline_timer( ios));
m_ClientTimeoutDLTPtr->expires_from_now( boost::posix_time::seconds( m_uiCommTimeout));
m_ClientTimeoutDLTPtr->async_wait( boost::bind( &MyClass::clientTimeoutHandler,
this,
boost::asio::placeholders::error
)
);
m_SocketPtrClient->connect
(
boost::asio::ip::tcp::endpoint
(
boost::asio::ip::address::from_string
(
m_sCommAddress == "localhost" ? "127.0.0.1" : m_sCommAddress
), m_usCommPort
), ec
);
if( !ec && m_SocketPtrClient->is_open())
{
m_ClientTimeoutDLTPtr->cancel();
}
else
{
m_ClientTimeoutDLTPtr->cancel();
m_SocketPtrClient->close();
return eStateError;
}
//install a timeout handler
m_ClientTimeoutDLTPtr->expires_from_now( boost::posix_time::seconds( m_uiCommTimeout));
m_ClientTimeoutDLTPtr->async_wait( boost::bind( &MyClass::clientTimeoutHandler,
this,
boost::asio::placeholders::error
)
);
ec = writeToServer( *m_SocketPtrClient);
if( ec)
{
// do error handling and throw an exception
}
m_ClientTimeoutDLTPtr->cancel();
//install a timeout handler
m_ClientTimeoutDLTPtr->expires_from_now( boost::posix_time::seconds( m_uiCommTimeout));
m_ClientTimeoutDLTPtr->async_wait( boost::bind( &MyClass::clientTimeoutHandler,
this,
boost::asio::placeholders::error
)
);
ec = readFromServer( *m_SocketPtrClient);
if( ec)
{
// do error handling and throw an exception
}
m_ClientTimeoutDLTPtr->cancel();
void MyClass::clientTimeoutHandler( const boost::system::error_code& ec)
{
if( ec)
{
m_ClientTimeoutDLTPtr->cancel();
m_SocketPtrClient->close();
m_ssMsg << std::endl << "break all handling because of timeout on io_service of Client!";
}
else
{
m_ClientTimeoutDLTPtr->expires_from_now( boost::posix_time::seconds( m_uiCommTimeout));
m_ClientTimeoutDLTPtr->async_wait( boost::bind( &MyClass::clientTimeoutHandler,
this,
boost::asio::placeholders::error
)
);
}
}
I need to connect, write to the server and then get response from the server and for each operation I need the timeout to kickoff. If I call the run from io_service then I can't make my these three calls.
I need to connect, write to the server and then get response from the
server and for each operation I need the timeout to kickoff. If I call
the run from io_service then I can't make my these three calls.
When using deadline_timer::async_wait() you will need to use the corresponding asynchronous socket methods such as socket::async_connect() instead of socket::connect().

Silently use Microsoft XPS Document Writer printer to create XPS

For some days now I've been battling with printing XPS to file without the dialog.
I've read posts on the matter in CodeGuru and by Feng Yuan (MSDN), along with many discussion topics here and I am still lost.
Specifically my scenario is that I have a 3rd party API that I must use, and it prints to the default printer (say Microsoft XPS Document Writer). I want to be able to "apply" a filename prior to the printing procedure, and of course not to have dialog.
I've tried working with WinDDK - XPSDRV and LOCALMON samples but wasn't able to figure out exactly how to manipulate the code to achieve my goals. (or even fully understand if I need a new printer driver or a new port type)
I ran into the same need. Following is some of the logic that provides the desired functionality for me:
//
// PrintDocument_inst
//
this.PrintDocument_inst.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(this.k_line_PrintPage);
private void Print( string align_file_name )
{
if ( plot_metafile == null )
{
MessageBox.Show( "you need to load offset data before printing a plot" );
return;
}
try
{
PrintDocument_inst.DefaultPageSettings = PageSettings_inst;
PrintDialog_inst = new PrintDialog( );
PrintDialog_inst.Document = PrintDocument_inst;
PrintDialog_inst.UseEXDialog = true; // this must be set true or dialog won't show on 64 bit Vista
PrintDialog_inst.PrinterSettings.PrinterName = "Microsoft XPS Document Writer";
PrintDialog_inst.PrinterSettings.PrintToFile = true;
PrintDialog_inst.PrinterSettings.PrintFileName = align_file_name;
i_page_to_print_next = 1;
n_pages_still_to_print = 1;
PrintDocument_inst.Print( );
}
catch ( Exception e )
{
MessageBox.Show( e.ToString( ) );
}
finally
{
}
} // end of function Print( string align_file_name )
//PrintPage event handler
private void k_line_PrintPage(object sender,PrintPageEventArgs ppea)
{
int leftMargin = ppea.MarginBounds.Left;
int topMargin = ppea.MarginBounds.Top ;
try
{
float _scale_f;
if ( PrintDialog_inst != null )
{
string str_printer_name = PrintDialog_inst.PrinterSettings.PrinterName.ToString ( );
if ( str_printer_name.CompareTo ( "Adobe PDF" ) == 0 )
{
_scale_f = 0.61F; // 0.85F;
}
else
{
_scale_f = 0.59F; // 0.82F;
}
}
else // case of print preview
{
_scale_f = 0.59F; // 0.82F;
}
if ( _scale_f != 1.0F ) ppea.Graphics.ScaleTransform ( _scale_f, _scale_f );
ppea.Graphics.DrawImage ( plot_metafile, leftMargin, topMargin );
ppea.HasMorePages = ( --n_pages_still_to_print > 0 ? true : false );
}
finally
{
}
} // end of private void k_line_PrintPage(object sender,PrintPageEventArgs ppea)
You will delete filters in pipeline xml and also related dll's in inf file. But yet, as I did, i guess you will face problem of printing canvas (graphics). I wasn't able to convert / transform this canvas to glyphs to get the contents of it.
If you had further issues, let me know
Kind Regards

Resources