Howto open ("/dev/urandom") on Windows0 Reacties

Just copy-paste2 might save you some time. rand_s is pretty safe on Windows since it uses RtlGenRandom(), but you’ll have to define _CRT_RAND_S first before

Assuming that the cpp somewhere in the class has: m_fd = open("/dev/urandom", O_RDONLY);

Original code: (thanks jacketzhong)

sds CRedLock::GetUniqueLockId()

{

unsigned char buffer[20];

if (_read(m_fd, buffer, sizeof(buffer)) == sizeof(buffer)) {

//获取20byte的随机数据

sds s; s = sdsempty();

for (int i = 0; i < 20; i++)

{

s = sdscatprintf(s, "%02X", bufferIdea); } return s;

}

else

{

//读取失败 printf("Error: GetUniqueLockId %d\n", __LINE__); }

return NULL;

}

Windows CPP compatible:

note: rand_s is not an ANSI standard.

sds CRedLock::GetUniqueLockId()
{
    //获取20byte的随机数据
    auto retVal = sdsempty();
    auto max = 20 / sizeof(unsigned int);
    for (int i = 0; i < max; i++)
    {
        unsigned int number;
        if (rand_s(&number) == 0)
        {           
            retVal = sdscatprintf(retVal, "%08X", number);           
        }
    }
    return retVal;
}

How to parse and read web.Config or app.Config in C++/on Windows0 Reacties

Just a tiny gem, which not often would be required but it can save you some time. It also demonstrates the power of the IXmlReader in unmanaged code. Because, as far I am aware of, the processing time a .config file measuring it with TickCount always is 0 ms (too small to measure). Microsoft has optimized the XML Reader implementation for fast forward reading, and it also does not allocate strings in memory, it just passes the pointer to the unicode strings (either key or value). In line with that, you might appreciate :) why I attach to the BSTR key to find as well.

What this class does, it reads the   section and puts the key value pairs in a ‘named value collection’ item.

Note 1: I am a big fan of CComBSTR when the final client still understands COM/automation. That is the reason I did not use CString in this class. In addition, the CComBSTR class has been boosted by me, to optimize reallocation of existing memory. But you can use the default MS implementation as well. So, you can change CSimpleMap to CSimpleMap if you wish.

Note 2: The .config file is cached but it is parsed again if the filewritetime of the .config file was changed.

config.h header.

#include
#include
#pragma once


using namespace ATL;

class ConfigurationManager
{
private:
    static const int DELAYTICKS = 1000;
    std::map _map;
    time_t _ftLastCheck;
    CComPtr _xmlReader;
    CComPtr _malloc;
    HRESULT CheckTimeOut();
    //ansi version!
    CComBSTR _szFilePath;
   
    void Init();

public:
    ConfigurationManager();
    ConfigurationManager(const BSTR configFile);
    std::wstring& AppSettings(const std::wstring key, PCWSTR defaultValue = NULL);
    BSTR AppSettings(const BSTR key, PCWSTR defaultValue = NULL);
    time_t GetFileTime();
    ~ConfigurationManager();
};

 

Implementation:


#include
#include
#include "config.h"
#pragma comment(lib, "xmllite.lib")


ConfigurationManager::ConfigurationManager(const BSTR configFile) throw()
{
    _szFilePath = configFile;
    time(&_ftLastCheck);
    Init();
}
ConfigurationManager::ConfigurationManager() throw()
{   
    time(&_ftLastCheck);
    _szFilePath.Attach(GetModulePath());   
    if (!_szFilePath.IsEmpty())
    {       
        _szFilePath.Append(L".config");
       
        Init();
    }   
}
void ConfigurationManager::Init() throw()
{
    if (!_szFilePath.IsEmpty())
    {
        HRESULT hr = CoGetMalloc(1, &_malloc);
        hr = CreateXmlReader(IID_IXmlReader, (void**)&_xmlReader, _malloc);
        if (FAILED(hr))
        {
   
        }
    }
}
time_t ConfigurationManager::GetFileTime() throw()
{   
    struct stat stResult;
    CComBSTR ansi(_szFilePath);
    ansi.Attach(ansi.ToByteString());
    ::stat((char*)ansi.m_str, &stResult);        // get the attributes of afile.txt
   
    return stResult.st_mtime;
}
BSTR ConfigurationManager::AppSettings(const BSTR key, PCWSTR defaultValue) throw()
{
   
    HRESULT hr = CheckTimeOut();
    if (FAILED(hr))
    {
      
        return NULL;
    }
    CComBSTR find;
    find.Attach(key);
   
    auto found = _map.find(find);
    find.Detach();
       if (found != _map.end())
    {
        return found->second.Copy();
    }
    else if (defaultValue != NULL)
    {
        return ::SysAllocString(defaultValue);
    }
    return NULL;
   
}
ConfigurationManager::~ConfigurationManager() throw()
{
    _map.clear();
    _xmlReader.Release();
    _malloc.Release();
    _szFilePath.Empty();
}
HRESULT ConfigurationManager::CheckTimeOut() throw()
{
   
    auto curT = GetFileTime();
   
    PCWSTR pwzValue;
    auto memResult = ::difftime(curT, _ftLastCheck);
    if (memResult != 0.0F)
    {
        DWORD start = ::GetTickCount();
   
        HRESULT hr = S_OK;
       
        CComPtr pStream;
        CComPtr _readerInput;
       
        hr = ::SHCreateStreamOnFileEx(_szFilePath, STGM_READ | STGM_SHARE_DENY_NONE, FILE_ATTRIBUTE_NORMAL, FALSE,NULL, &pStream);

        if (SUCCEEDED(hr))
        {
            hr = ::CreateXmlReaderInputWithEncodingCodePage(pStream, _malloc, CP_UTF8, TRUE, NULL, &_readerInput);           
            hr = _xmlReader->SetProperty(XmlReaderProperty_DtdProcessing, DtdProcessing_Prohibit);   
            hr = _xmlReader->SetInput(_readerInput);
        }   
        else
        {
            return hr;
        }
       
        XmlNodeType nodeType = XmlNodeType::XmlNodeType_None;
        UINT lenValue;
        PCWSTR key;
        bool startCollecting  = false;
        while (S_OK == _xmlReader->Read(&nodeType) && hr == S_OK)
        {
            switch(nodeType) {
            case XmlNodeType::XmlNodeType_EndElement:
               
                //hr = pReader->GetDepth(&dept);
                hr = _xmlReader->GetLocalName(&pwzValue, NULL);
                if (startCollecting && lstrcmpW(pwzValue, L"appSettings") == 0)
                {
                    //break loop
                    hr = S_FALSE;
                }
                break;
            case XmlNodeType::XmlNodeType_Element:
                {
                    // get element name such as option in

                        hr = _xmlReader->MoveToAttributeByName(L"configSource", NULL);
                        if (hr == S_OK)
                        {
                            hr = _xmlReader->GetValue(&pwzValue, NULL);
                            
                                              
                            if (::PathIsRelativeW(pwzValue) == TRUE)
                            {
                                //TODO: call back to do a Server.MapPath
                                _szFilePath.Attach(FileStripFile(_szFilePath));                               
                                _szFilePath.Append(L'\\');
                                _szFilePath.Append(pwzValue);
                            }
                            else
                            {
                                _szFilePath = pwzValue;
                            }
                            _readerInput.Release();
                            pStream.Release();
                            return CheckTimeOut(); //recursion                           
                        }
                        hr = S_OK;//reset otherwise loop stops
                    }                   
                    else if (startCollecting && lstrcmpW(pwzValue, L"add") == 0)
                    {
                       
                        hr = _xmlReader->MoveToAttributeByName(L"key", NULL);
                        if (hr == S_OK)
                        {
                            hr = _xmlReader->GetValue(&pwzValue, &lenValue);
                            //key.Append( pwzValue, lenValue);
                            key = pwzValue;

                            //ATLTRACE(L"found key %s %d\r\n", pwzValue, lenValue);
                            hr = _xmlReader->MoveToAttributeByName(L"value", NULL);
                            if (hr == S_OK)
                            {
                                _xmlReader->GetValue(&pwzValue, NULL);
                                _map.insert(std::pair(key, pwzValue));
                            }
                        }
                    }                   
                }
                break;
            }
        }
        if (SUCCEEDED(hr)) _ftLastCheck = curT;
        if (_xmlReader != NULL)
        {
            _xmlReader->SetInput(NULL);
        }
    
        return S_FALSE;
       
    }

    return S_OK;
   
};

[C++] a Full Featured CAtlServiceModuleT implementation...0 Reacties

I had to do some maintenance on a Windows ® service and found that you can use an ATL service as a windows service very well without all the overhead.

 

There are some samples on the internet, but they stop where I wanted to continue. That is, run UI-less services for instance, a job that could be done through a task scheduled-job but better be done through a service?

 

b.t.w. for the ones interested in a minimal windows service and who feel a sick inclination J writing the smallest EXE possible, they should use  a plain C implementation provided by  Microsoft’s ® Platform SDK located at [Platform SDK folder]\Samples\WinBase\Service and they should not use MS VC 8 but 4 or so...

 

Note that the grey highlighted code, is my code, the normal colored code is left over of what the MS Visual Studio created for you through the wizard. In addition, I’ve snipped all trace & debugging code.

The Visual Studio 2005 wizard creates an EXE that is suitable both as COM service (DCOM) and as windows service. You can guess a lot of overhead and unneeded lines.

 

This service does not perform anything, keep in mind it is a template for a 'scheduled' task-service, a batch for instance. Your code comes within DoDBMSJob...

 

// Service_Template.cpp : Implementation of WinMain

 

#include "stdafx.h"

#include "resource.h"

 

#include "Service_Template.h"

#pragma warning(disable: 4482) // nonstandard extension used: 'enum CServiceStatus' used in qualified name

 

[v1_enum] //32 bit rulez

enum CServiceStatus

{

      run = 0,

      pauze=1,

      stop = 2,

      shutmedown=3

};

class CService_Module : public CAtlServiceModuleT< CService_Module, IDS_SERVICENAME >

{

private:

      // this flag in milliseconds, tells us how often

      // is checked for tasks

      DWORD m_iPollTime;

      HANDLE m_ThreadHandle; // eventually use CHandle

      HANDLE  m_hServerStopEvent;

      bool connDone;

      CServiceStatus m_ServiceStatus ;

      bool stopNow;

public :

      ~CService_Module() throw()

      {

            if (m_ThreadHandle != NULL)

                  CloseHandle(m_ThreadHandle);

            if (m_hServerStopEvent != NULL)

                  CloseHandle(m_hServerStopEvent);

      }

      CService_Module()  throw():   m_iPollTime(10), m_ThreadHandle(NULL), m_hServerStopEvent(NULL),

            stopNow(false)

      {

            m_ServiceStatus =CServiceStatus::run;

            //m_dwTimeOut = 60000; // one minute

 

           

      }

      // we can’t skip this! Leave as is created by wizard

      DECLARE_REGISTRY_APPID_RESOURCEID(IDR_GARBAGE_COLLECT, "{44DE094D-9AE1-5A56-A1A7-A20F9EAE0F21}")

 

      HRESULT InitializeSecurity() throw()

      {

// we don’t need this here

            return S_OK;

      }

 

      void OnPauze() throw()

      {

            m_ServiceStatus = CServiceStatus::pauze;

            __super::OnPause();

            if ( m_hServerStopEvent != NULL)

                  SetEvent(m_hServerStopEvent);

           

      }

      void OnStop() throw()

      {

            __super::OnStop();

            m_ServiceStatus =CServiceStatus::stop;

            if ( m_hServerStopEvent != NULL)

            {

                  stopNow= true;

                  // be sure not to kill the thread & process

                  // before it nicely ends

                  // otherwise, our pointers will ‘Release()’ while

                  // the instance has been killed already, a common bug!

                  SetEvent(m_hServerStopEvent);

                  DWORD tc = GetTickCount();

                  while(m_hServerStopEvent != NULL || GetTickCount() - tc > 20000) // max 20 seconds wait

                        Sleep(10);

            }

      }

 

      void OnContinue( ) throw( )

      {

            __super::OnContinue();

            m_ServiceStatus =CServiceStatus::run;

            if ( m_hServerStopEvent != NULL)

                  SetEvent(m_hServerStopEvent);

      }

 

      void OnShutDown() throw()

      {    

            //__super::OnShutDown();

            m_ServiceStatus =CServiceStatus::pauze;

            if ( m_hServ

HOWTO: [DotNet] marshale a managed string array for Interop0 Reacties

Normally if you have defined a struct in C# which is for a Win32 call, you might tend to copy-paste it from C++, and then modify LPWSTR to string and add attributes (etc),
like this:

struct myStruct
{
   [MarshalAs(UnmanagedType.LPWstr)}
   public string blah; //ok
   [MarshalAs(UnmanagedType.ByValArray, ArraySubType=UnmanagedType.LPWStr)]   
    public string[] stringarray;
}

Let's concentrate on the array definition. The original array was defined like LPWSTR* stringarray;  this is an array of pointers to zero-terminated strings.

Now you thought, that a few attributes, would be sufficient to support your interop?

[MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPWStr)]   
public string[] stringarray;

but the .NET framework, won't support you here. It is not able to create an unmanaged array of 'some type' on structs (this however, is working for parameter definitions) and to pass it to your unmanaged API.

And if you wonder what UnmanagedType.ByValArray, UnmanagedType.LPWStr  really does; it creates a pointer to a contigous block of zero terminated strings. It would not create an array of stringpointers. So now you know, why interop is an art, not a science :)

At last, I wrote an easy wrapper. It returns an IntPtr which is a just pointer to our first element to an array of string pointers :)

You should assign this class as a member variable on your own class. If you use this class inside a member function, your unmanaged memory might be cleaned when the function goes out of scope.
PS: Please send back the improved code, if you decide to use it (at your own risk of course). It might be improved, to pack managed structures as well, using C# generics.

Sample:

class myClass()

{   private packLPArray packit;      

      void myMemberfunction()
      {   // ... do your dangerous, endeavourish :) interop thing here
            packit = new packLPArray(new string[] {"element1", "element2", "blah"});
            mystruct.stringarray = packit.arrayPtr;
      }

}

 

///

packs an array of strings (type = string[]) to unmanaged memory
/// also works for 64-bit environments
///

public sealed class  packLPArray
{
    private IntPtr taskAlloc;

    private readonly int _length;

    private IntPtr[] _strings;

    public packLPArray(string[] theArray)

    {   int sizeIntPtr = IntPtr.Size;

        int neededSize = 0;

        if (theArray != null)

        {

            this._length = theArray.Length;

            this._strings = new IntPtr[this._length];

           // System.Diagnostics.Debugger.Break();

            neededSize = this._length * sizeIntPtr;

            this.taskAlloc = Marshal.AllocCoTaskMem(neededSize);           

            for (int cx = this._length - 1; cx >= 0; cx--)
            {   this._strings[cx] = Marshal.StringToCoTaskMemUni(theArray[cx]);
                Marshal.WriteIntPtr(this.taskAlloc, cx * sizeIntPtr, this._strings[cx]);

            }

        }

    }

    ///

    /// retrieves array length

    ///

    public int Length

    {

        get { return _length; }

    }

    public IntPtr arrayPtr

    {

        get { return this.taskAlloc; }

 

    }

    ~packLPArray() // clean up the rub

    {

        if (taskAlloc != IntPtr.Zero)

        {

            Marshal.FreeCoTaskMem(this.taskAlloc);

            int cx = this._length;

            while(cx-- != 0)

                Marshal.FreeCoTaskMem(this._strings[cx]);

        }

    } 

}