How to obtain Provider name of a CSP from PCCERT_CONTEXT? - c++

I have been try to get a provider name from PCCERT_CONTEXT because in my current project i must have load all certificate from smart card into my program. And in the future I have to deal with those certificate with some task like renewal certificate, delete certificate. But I have problem, I must to map CSP name and provider name with CryptAcquireContext to executive. And I currently confused how to archive this, can anyone have some guide to help me resolve this problem.
I have try CertGetCertificateContextProperty with dwPropId is CERT_KEY_PROV_INFO_PROP_ID but i can not get CRYPT_KEY_PROV_INFO.

If I have understood you correctly, the following snippet shows how to extract the key provider information from a certificate.
void trace(char* message, DWORD errorCode)
{
cout << message << errorCode;
}
std::wstring Test_CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext)
{
DWORD dwSize = 0;
BOOL bIsSuccess = CertGetCertificateContextProperty(pCertContext,
CERT_KEY_PROV_INFO_PROP_ID,
NULL,
&dwSize);
if (!bIsSuccess)
{
trace("CertGetCertificateContextProperty failed with error: ", GetLastError());
return L"";
}
PCRYPT_KEY_PROV_INFO pKeyProvInfo = (PCRYPT_KEY_PROV_INFO)LocalAlloc(LMEM_ZEROINIT, dwSize);
if (pKeyProvInfo == NULL)
{
trace("LocalAlloc failed with error:", GetLastError());
return L"";
}
bIsSuccess = CertGetCertificateContextProperty(pCertContext,
CERT_KEY_PROV_INFO_PROP_ID,
pKeyProvInfo,
&dwSize);
std::wstring provName;
if (bIsSuccess)
{
provName = pKeyProvInfo->pwszProvName;
}
LocalFree(pKeyProvInfo);
return provName;
}

Related

How to check the revocation status of a x509 certificate in c++ with wincrypt.h?

I'm trying to check the revocation state of a X509 certificate in a c++ program with the use of wincrypt.h. Sadly I'm not able to find a comprehensive example. In c# the code would be the following:
X509Certificate2 certificate = new X509Certificate2();
//Create X509Certificate2 object from .cer file.
byte[] rawData = ReadFile(#"C:\Users\z002m76a\Desktop\cert.pem");
certificate.Import(rawData);
X509Chain ch = new X509Chain();
ch.ChainPolicy.RevocationMode = X509RevocationMode.Online;
ch.Build(certificate);
Console.WriteLine("Chain revocation flag: {0}", ch.ChainPolicy.RevocationFlag);
Based on the excellent comment by #crypt32 I created the following c++ program. Probably it is not the most beautiful c++ code in the world (mine c++ is pretty rusty) but it seems so work
// ValidationCheckCPP.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include <windows.h>
#include <wincrypt.h>
#include "ValidationCheckCPP.h"
int main()
{
char keyFile[] = "C:\\Users\\z002m76a\\Desktop\\2698514447.crt";
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = FALSE;
HANDLE hKeyFile;
hKeyFile = CreateFile(keyFile, GENERIC_READ, FILE_SHARE_READ, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hKeyFile) {
BYTE lp[65536];
DWORD flags;
DWORD bytes;
if (ReadFile(hKeyFile, lp, GetFileSize(hKeyFile, NULL), &bytes, NULL) && bytes > 0) {
BYTE* p;
p = lp + bytes;
if (CryptStringToBinary((char*)lp, p - lp, CRYPT_STRING_BASE64_ANY, p, &bytes, NULL, &flags) && bytes > 0) {
PCCERT_CONTEXT pCertContext;
pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING, p, bytes);
if (pCertContext)
{
printf("Certificate loaded");
CERT_ENHKEY_USAGE EnhkeyUsage;
EnhkeyUsage.cUsageIdentifier = 0;
EnhkeyUsage.rgpszUsageIdentifier = NULL;
CERT_USAGE_MATCH CertUsage;
CertUsage.dwType = USAGE_MATCH_TYPE_AND;
CertUsage.Usage = EnhkeyUsage;
CERT_CHAIN_PARA ChainPara;
ChainPara.cbSize = sizeof(CERT_CHAIN_PARA);
ChainPara.RequestedUsage = CertUsage;
PCCERT_CHAIN_CONTEXT pChainContext;
if (CertGetCertificateChain(
NULL, // use the default chain engine
pCertContext, // pointer to the end certificate
NULL, // use the default time
NULL, // search no additional stores
&ChainPara,
CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
NULL, // currently reserved
&pChainContext)) // return a pointer to the chain created
{
printf("Chain built with %d certificates.\n", pChainContext->rgpChain[0]->cElement);
CERT_CHAIN_POLICY_PARA ChainPolicy = { 0 };
ChainPolicy.cbSize = sizeof(ChainPolicy);
CERT_CHAIN_POLICY_STATUS PolicyStatus = { 0 };
PolicyStatus.cbSize = sizeof(PolicyStatus);
CertVerifyCertificateChainPolicy(
CERT_CHAIN_POLICY_BASE,
pChainContext, // pointer to the chain
&ChainPolicy,
&PolicyStatus);
CERT_REVOCATION_STATUS revocationStatus;
revocationStatus.cbSize = sizeof(CERT_REVOCATION_STATUS);
PCERT_CONTEXT* pCerts = new PCERT_CONTEXT[pChainContext->cChain];
for (DWORD i = 0; i < pChainContext->cChain; i++) {
pCerts[i] = (PCERT_CONTEXT)(pChainContext->rgpChain[i]->rgpElement[0]->pCertContext);
}
// CERT_VERIFY_REV_CHAIN_FLAG
// Verification of the chain of certificates is done assuming each certificate except the first certificate is the issuer of the certificate that precedes it.If dwRevType is not CERT_CONTEXT_REVOCATION_TYPE, no assumptions are made about the order of the contexts.
// CERT_VERIFY_CACHE_ONLY_BASED_REVOCATION
// Prevents the revocation handler from accessing any network - based resources for revocation checking.
// CERT_VERIFY_REV_ACCUMULATIVE_TIMEOUT_FLAG
// When set, dwUrlRetrievalTimeout is the cumulative time - out across all URL wire retrievals.
// CERT_VERIFY_REV_SERVER_OCSP_FLAG
// When set, this function only uses online certificate status protocol(OCSP) for revocation checking.If the certificate does not have any OCSP AIA URLs, the dwError member of the pRevStatus parameter is set to CRYPT_E_NOT_IN_REVOCATION_DATABASE.
DWORD revocationCheckType = CERT_VERIFY_REV_CHAIN_FLAG;
BOOL bRc = CertVerifyRevocation(
X509_ASN_ENCODING,
CERT_CONTEXT_REVOCATION_TYPE,
pChainContext->cChain,
(void**)pCerts,
revocationCheckType,
NULL,
&revocationStatus);
printf("The size of the chain context is %d. \n", pChainContext->cbSize);
printf("%d simple chains found.\n", pChainContext->cChain);
printf("\nError status for the chain:\n");
switch (pChainContext->TrustStatus.dwErrorStatus)
{
case CERT_TRUST_NO_ERROR:
printf("No error found for this certificate or chain.\n");
break;
case CERT_TRUST_IS_NOT_TIME_VALID:
printf("This certificate or one of the certificates in the certificate chain is not time-valid.\n");
break;
case CERT_TRUST_IS_REVOKED:
printf("Trust for this certificate or one of the certificates in the certificate chain has been revoked.\n");
break;
case CERT_TRUST_IS_NOT_SIGNATURE_VALID:
printf("The certificate or one of the certificates in the certificate chain does not have a valid signature.\n");
break;
case CERT_TRUST_IS_NOT_VALID_FOR_USAGE:
printf("The certificate or certificate chain is not valid in its proposed usage.\n");
break;
case CERT_TRUST_IS_UNTRUSTED_ROOT:
printf("The certificate or certificate chain is based on an untrusted root.\n");
break;
case CERT_TRUST_REVOCATION_STATUS_UNKNOWN:
printf("The revocation status of the certificate or one of the certificates in the certificate chain is unknown.\n");
break;
case CERT_TRUST_IS_CYCLIC:
printf("One of the certificates in the chain was issued by a certification authority that the original certificate had certified.\n");
break;
case CERT_TRUST_IS_PARTIAL_CHAIN:
printf("The certificate chain is not complete.\n");
break;
case CERT_TRUST_CTL_IS_NOT_TIME_VALID:
printf("A CTL used to create this chain was not time-valid.\n");
break;
case CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID:
printf("A CTL used to create this chain did not have a valid signature.\n");
break;
case CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE:
printf("A CTL used to create this chain is not valid for this usage.\n");
}
printf("Info status for the chain:\n");
switch (pChainContext->TrustStatus.dwInfoStatus)
{
case 0:
printf("No information status reported.\n");
break;
case CERT_TRUST_HAS_EXACT_MATCH_ISSUER:
printf("An exact match issuer certificate has been found for this certificate.\n");
break;
case CERT_TRUST_HAS_KEY_MATCH_ISSUER:
printf("A key match issuer certificate has been found for this certificate.\n");
break;
case CERT_TRUST_HAS_NAME_MATCH_ISSUER:
printf("A name match issuer certificate has been found for this certificate.\n");
break;
case CERT_TRUST_IS_SELF_SIGNED:
printf("This certificate is self-signed.\n");
break;
case CERT_TRUST_IS_COMPLEX_CHAIN:
printf("The certificate chain created is a complex chain.\n");
break;
} // end switch
}
CertFreeCertificateContext(pCertContext);
}
else {
printf("Could not convert certificate to internal form\n");
}
}
else {
printf("Failed to convert from PEM\n");
}
}
else {
printf("Failed to read key file: %s\n", keyFile);
}
}
else {
printf("Failed to open key file: %s\n", keyFile);
}
CloseHandle(hKeyFile);
return 0;
}
In C++, you use CertGetCertificateChain function. Along with call result, the function returns a a pointer to CERT_CHAIN_CONTEXT (via ppChainContext member). This CERT_CHAIN_CONTEXT structure stores a pointer to a CERT_SIMPLE_CHAIN structure (rgpChain member) which represents an array of chain elements (this is what X509Chain.ChainElements represents in .NET). Essentially, you need to check the very first element in rgpChain, which is a pointer to a CERT_SIMPLE_CHAIN structure. And examine TrustStatus member for revocation status flags (two flags).
The example provided by #Rufus Buschart is quite lovely. If checking OCSP in his example, simply change revocationCheckType to CERT_VERIFY_REV_SERVER_OCSP_FLAG.
Here I'd like to provide an example using another api CertOpenServerOcspResponse()
// after construct the PCCERT_CHAIN_CONTEXT ppChainContext, which can be the same as #Rufus
// If async operation is required, change second parameter 0 to 1 (available since Win8.1, but not announced on official documentations)
HCERT_SERVER_OCSP_RESPONSE hServerOcspResponse = CertOpenServerOcspResponse(ppChainContext, 0, nullptr);
PCCERT_SERVER_OCSP_RESPONSE_CONTEXT recvdResponseCtx = CertGetServerOcspResponseContext(hServerOcspResponse, 0, nullptr);
if (recvdResponseCtx == nullptr)
{
printf("Receive OCSP server response failed\n");
showStrError("CertGetServerOcspResponseContext"); // show the description about GetLastError()
return 1;
}
POCSP_RESPONSE_INFO pocspResponseInfo = nullptr;
DWORD ocspResponseSize = 0; // X509_SEQUENCE_OF_ANY
ret = CryptDecodeObjectEx(PKCS_7_ASN_ENCODING, OCSP_RESPONSE, recvdResponseCtx->pbEncodedOcspResponse, recvdResponseCtx->cbEncodedOcspResponse, CRYPT_DECODE_ALLOC_FLAG, nullptr, &pocspResponseInfo, &ocspResponseSize);
if (!ret)
{
printf("Error decode ocsp response info from CERT_SERVER_OCSP_RESPONSE_CONTEXT.\n");
showStrError("DecodeOcspServerResponse");
return 1;
}
if (pocspResponseInfo->dwStatus != OCSP_SUCCESSFUL_RESPONSE)
{
printf("Unsuccessfully ocsp response. The status value is %d, which means %s\n", pocspResponseInfo->dwStatus, "OCSP_MALFORMED_REQUEST_RESPONSE if it is 1");
return 1;
}
if (strcmp(szOID_PKIX_OCSP_BASIC_SIGNED_RESPONSE, pocspResponseInfo->pszObjId))
{
printf("Ocsp response info is %s\n, but it should be %s\n", pocspResponseInfo->pszObjId, szOID_PKIX_OCSP_BASIC_SIGNED_RESPONSE);
return 1;
}
POCSP_BASIC_SIGNED_RESPONSE_INFO pocspBasicSignedResponseInfo = nullptr;
DWORD ocspBasicSignedResponseSize = 0;
ret = CryptDecodeObjectEx(PKCS_7_ASN_ENCODING, OCSP_BASIC_SIGNED_RESPONSE, pocspResponseInfo->Value.pbData, pocspResponseInfo->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, nullptr, &pocspBasicSignedResponseInfo, &ocspBasicSignedResponseSize);
if (!ret)
{
showStrError("DecodeOCSP_BASIC_SIGNED_RESPONSE");
return 1;
}
POCSP_BASIC_RESPONSE_INFO pocspBasicResponseInfo = nullptr;
DWORD ocspBasicResponseSize = 0;
ret = CryptDecodeObjectEx(PKCS_7_ASN_ENCODING, OCSP_BASIC_RESPONSE, pocspBasicSignedResponseInfo->ToBeSigned.pbData, pocspBasicSignedResponseInfo->ToBeSigned.cbData, CRYPT_DECODE_ALLOC_FLAG, nullptr, &pocspBasicResponseInfo, &ocspBasicResponseSize);
if (!ret)
{
showStrError("DecodeOCSP_BASIC_RESPONSE");
return 1;
}
DWORD certStatus = pocspBasicResponseInfo->rgResponseEntry->dwCertStatus;
printf("cert status is %d", certStatus); // good:0, revoked:1, unknown:2
return 0;
The showStrError() is modified from WinCrypt examples as below:
void showStrError(const char* lpszFunction)
{
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf,
0, NULL);
// Display the error message and exit the process
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
printf("%s failed with error %d: %ws\n", lpszFunction, dw, (LPCTSTR)lpMsgBuf);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
}

why OpenService() doesn't work when I check a window service status?

I am working on a very confused issue all this afternoon, I want to check the windows service status by QueryServiceStatusEx, but always get 0. MSDN says
"If the function fails, the return value is zero. To get extended
error information, call GetLastError."
To get more error information, I call GetLastError, the error code is 1.
ERROR_INVALID_HANDLE : The handle is invalid.
Here is my code, e.g. I check the window service :"Spooler", where is wrong in my code? Why I can't get the service SC_HANDLE by using OpenService()?
bool isServiceStart()
{
SERVICE_STATUS_PROCESS status;
SC_HANDLE schSCManager;
SC_HANDLE schService;
//get hadnle to the scm database
schSCManager = OpenSCManager(
NULL, //local machine
NULL, //services acitive database
SC_MANAGER_ALL_ACCESS
);
if(NULL == schSCManager){
qDebug() << "Open SCManager failed: " << (GetLastError() == ERROR_ACCESS_DENIED);
CloseServiceHandle(schSCManager);
return false;
}
//Get a hadle to the service
QString serviceName = "Spooler";
schService = OpenService(
schSCManager, //database
(LPCTSTR)serviceName.data(),
SERVICE_ALL_ACCESS
);
if(schService == NULL){
qDebug() << "service doesn't exist: " << GetLastError();
CloseServiceHandle(schSCManager);
return false;
}
DWORD dwBytesNeeded;
if(!QueryServiceStatusEx(
schService,
SC_STATUS_PROCESS_INFO, // information level
(LPBYTE) &status, // address of structure
sizeof(SERVICE_STATUS_PROCESS),
&dwBytesNeeded // size needed if buffer is too small
))
{
qInfo() << "service status" << status.dwCurrentState;
}else{
qInfo() << "hahaha alway is 0" <<GetLastError();
}
return false;
}
Your condition is wrong, you write "hahaha alway is 0" when QueryServiceStatusEx returns non-zero.
Either remove the ! operator in the condition, or switch places of the outputs.

WsOpenServiceHost returns WS_E_OTHER

I'm tryind to run HttpCalculatorServiceExample located in MSDN. Function WsOpenServiceHost returns error code 0x803d0021. This error means
MessageId: WS_E_OTHER
Unrecognized error occurred in the Windows Web Services framework.
Printed error:
Unable to add URL to HTTP URL group.
Unrecognized error occurred in the Windows Web Services framework.
The process cannot access the file because it is being used by another process.
How to solve this problem?
int __cdecl wmain(int argc, __in_ecount(argc) wchar_t **argv)
{
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(argv);
HRESULT hr = NOERROR;
WS_SERVICE_HOST* host = NULL;
WS_SERVICE_ENDPOINT serviceEndpoint = {};
const WS_SERVICE_ENDPOINT* serviceEndpoints[1];
serviceEndpoints[0] = &serviceEndpoint;
WS_ERROR* error = NULL;
WS_SERVICE_ENDPOINT_PROPERTY serviceEndpointProperties[1];
WS_SERVICE_PROPERTY_CLOSE_CALLBACK closeCallbackProperty = {CloseChannelCallback};
serviceEndpointProperties[0].id = WS_SERVICE_ENDPOINT_PROPERTY_CLOSE_CHANNEL_CALLBACK;
serviceEndpointProperties[0].value = &closeCallbackProperty;
serviceEndpointProperties[0].valueSize = sizeof(closeCallbackProperty);
// Initialize service endpoint
serviceEndpoint.address.url.chars = L"http://+:80/example"; // address given as uri
serviceEndpoint.address.url.length = (ULONG)wcslen(serviceEndpoint.address.url.chars);
serviceEndpoint.channelBinding = WS_HTTP_CHANNEL_BINDING; // channel binding for the endpoint
serviceEndpoint.channelType = WS_CHANNEL_TYPE_REPLY; // the channel type
serviceEndpoint.contract = &calculatorContract; // the contract
serviceEndpoint.properties = serviceEndpointProperties;
serviceEndpoint.propertyCount = WsCountOf(serviceEndpointProperties);
// Create an error object for storing rich error information
hr = WsCreateError(
NULL,
0,
&error);
if (FAILED(hr))
{
goto Exit;
}
// Create Event object for closing the server
closeServer = CreateEvent(
NULL,
TRUE,
FALSE,
NULL);
if (closeServer == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Exit;
}
// Creating a service host
hr = WsCreateServiceHost(
serviceEndpoints,
1,
NULL,
0,
&host,
error);
if (FAILED(hr))
{
goto Exit;
}
// WsOpenServiceHost to start the listeners in the service host
hr = WsOpenServiceHost(
host,
NULL,
error);
if (FAILED(hr))
{
goto Exit;
}
WaitForSingleObject(closeServer, INFINITE);
// Close the service host
hr = WsCloseServiceHost(host, NULL, error);
if (FAILED(hr))
{
goto Exit;
}
Exit:
if (FAILED(hr))
{
// Print out the error
PrintError(hr, error);
}
fflush(
stdout);
if (host != NULL)
{
WsFreeServiceHost(host);
}
if (error != NULL)
{
WsFreeError(error);
}
if (closeServer != NULL)
{
CloseHandle(closeServer);
}
fflush(stdout);
return SUCCEEDED(hr) ? 0 : -1;
}
I had the same error "Unrecognized error occurred in the Windows Web Services framework", while tried to debug remote target (C++ project).
I've tried all possible solutions, which I've found over internet: turn-off/uninstall antivirus(I use MS Essentials), turnoff firewall, reinstall VS etc.
But it didn't help.
So, I've deleted all programms (not windows updates) which I've installed last month, reboot computer, and the bug went away.
Uninstalled software:
Foxit PhantomPDF Standard. Версия: 7.0.5.1021.
widecap
CCleaner
Uninstall Tool
just in case, I've also uninstalled Microsoft Security Essentials and after the bug went away I've installed it again and had no problems.
Hope, this helps

CreateEnvironmentBlock crashes service

I'm trying to start GUI application from windows service. But when I call CreateEnvironmentBlock() function, It hangs there for a while then crashes displaying dialog box "SampleService.exe stopped working and was closed. A problem caused the application to stop working correctly. windows will notify you if a solution is available." Following is my code.
DWORD dwSessionId = 0; // Session ID
HANDLE hToken = NULL; // Active session token
HANDLE hDupToken = NULL; // Duplicate session token
WCHAR szErr[1024] = {0};
STARTUPINFO* startupInfo;
PROCESS_INFORMATION processInformation;
PWTS_SESSION_INFO pSessionInfo = 0;
DWORD dwCount = 0;
LPVOID lpEnvironment = NULL; // Environtment block
OutputDebugString(_T("My Sample Service: startApplication: Entry"));
// Get the list of all terminal sessions
WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &dwCount);
int dataSize = sizeof(WTS_SESSION_INFO);
// look over obtained list in search of the active session
for (DWORD i = 0; i < dwCount; ++i)
{
WTS_SESSION_INFO si = pSessionInfo[i];
if (WTSActive == si.State)
{
// If the current session is active – store its ID
dwSessionId = si.SessionId;
break;
}
}
OutputDebugString(_T("My Sample Service: startApplication: freewtsmemory"));
WTSFreeMemory(pSessionInfo);
OutputDebugString(_T("My Sample Service: startApplication: WTSQueryUserToken"));
// Get token of the logged in user by the active session ID
BOOL bRet = WTSQueryUserToken(dwSessionId, &hToken);
if (!bRet)
{
swprintf(szErr, _T("WTSQueryUserToken Error: %d"), GetLastError());
OutputDebugString(szErr);
return false;
}
OutputDebugString(_T("My Sample Service: startApplication: duplicatetokenex"));
// Get duplicate token from the active logged in user's token
bRet = DuplicateTokenEx(hToken, // Active session token
TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, // Desired access
NULL, // Token attributes
SecurityImpersonation, // Impersonation level
TokenPrimary, // Token type
&hDupToken); // New/Duplicate token
if (!bRet)
{
swprintf(szErr, _T("DuplicateTokenEx Error: %d"), GetLastError());
OutputDebugString(szErr);
return false;
}
// Get all necessary environment variables of logged in user
// to pass them to the process
OutputDebugString(_T("My Sample Service: startApplication: createenvironmentblock"));
try{
bRet = CreateEnvironmentBlock(&lpEnvironment, hDupToken, FALSE);
}
catch( const exception &e)
{
swprintf(szErr, _T("CreateEnvironmentBlock Exception: %s"), e);
OutputDebugString(szErr);
return false;
}
if(!bRet)
{
swprintf(szErr, _T("CreateEnvironmentBlock Error: %d"), GetLastError());
OutputDebugString(szErr);
return false;
}
// Initialize Startup and Process info
startupInfo->cb = sizeof(STARTUPINFO);
OutputDebugString(_T("My Sample Service: startApplication: createprocess"));
// Start the process on behalf of the current user
BOOL returnCode = CreateProcessAsUser(hDupToken,
NULL,
L"C:\\KM\\TEST.exe",
NULL,
NULL,
FALSE,
NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT,
lpEnvironment,
NULL,
startupInfo,
&processInformation);
if( !returnCode)
{
swprintf(szErr, _T("CreateProcessAsUser Error: %d"), GetLastError());
OutputDebugString(szErr);
return false;
}
CloseHandle(hDupToken);
return true;
It shows "My Sample Service: startApplication: createenvironmentblock" in debugview and stopped service. please help me out regarding this issue. please note i m using windows vista.
Regards,
KM.
You need to initialise pointers before you can use them in a defined fashion.
STARTUPINFO* startupInfo;
...
startupInfo->cb = sizeof(STARTUPINFO);
This mistake might have been more obvious to spot if your variables were declared closer to where they are used. If you follow some rule that variables can only be declared at the start of a function, you might want to consider making more functions.
And, for what it's worth, when troubleshooting these sorts of issues you can always attach Visual Studio's debugger to the service process instead of relying on OutputDebugString. Just make sure the service process is the last thing built by Visual Studio and process, symbol files and source code should all be aligned.

Is it possble to check from the code of ActiveX, if the current page(site) is in Trusted Sites zone?

Hi
I have legacy ActiveX (ATL), that works properly if loaded from the Trusted Sites security zone.
I want to add verification in code, the be sure that customer added the host of activeX to the trusted sites and if not just give a warning.
What API should I use ? (browser is IE7 and UP).
Thank you
You can map an url to a zone in native code using IInternetSecurityManager::MapUrlToZone.
The sample code from MSDN:
const char* rgZoneNames[] = { "Local", "Intranet", "Trusted", "Internet", "Restricted" };
IInternetSecurityManager* pInetSecMgr;
HRESULT hr = CoCreateInstance(CLSID_InternetSecurityManager, NULL, CLSCTX_ALL,
IID_IInternetSecurityManager, (void **)&pInetSecMgr);
if (SUCCEEDED(hr))
{
DWORD dwZone;
hr = spInetSecMgr->MapUrlToZone(szUrl, &dwZone, 0);
if (hr == S_OK) {
if (dwZone < 5) {
printf("ZONE: %s (%d)\n", rgZoneNames[dwZone], dwZone);
} else {
printf("ZONE: Unknown (%d)\n", dwZone);
}
} else {
printf("ZONE: Error %08x\n", hr);
}
pInetSecMgr->Release();
}