Writing/Reading a structure in registry

Hello experts

Please help how to write and read a simple structure , structure contains one date field and one integer.

I need this structure data to access from other process.

Thanks in advance
HarishMinuAsked:
Who is Participating?
 
sarabandeConnect With a Mentor Commented:
yes, QLemo is right. shared memory is a good idea for p2p. if the processes are window-less shared memory is a fine and quick solution:

   
HANDLE hMapFile = NULL;
   MyStruct * pBuf = NULL; // pointer to structure with date and number

   hMapFile = CreateFileMapping(
                 INVALID_HANDLE_VALUE,    // use paging file
                 NULL,                    // default security
                 PAGE_READWRITE,          // read/write access
                 0,                       // maximum object size (high-order DWORD)
                 sizeof(MyStruct),                // maximum object size (low-order DWORD)
                 "SomeUniqueName");                 // name of mapping object

   if (hMapFile == NULL)
   {
      log_error("Could not create file mapping object. Error=", GetLastError());
      return 1;
   }

   pBuf = (MyStruct*) MapViewOfFile(hMapFile,   // handle to map object
                        FILE_MAP_ALL_ACCESS, // read/write permission
                        0,
                        0,
                        BUF_SIZE);

   if (pBuf == NULL)
   {
      log_error("Could not map view of file. Error=", GetLastError());
      CloseHandle(hMapFile);
      return 1;
   }

Open in new window


you can use the same code for write and read. in case of reading you might check after CreateFileMapping successfully returning a handle that GetLastError() returns ERROR_ALREADY_EXISTS cause the reading process should be second after the writing process.

alternatively the client processes may use OpenFileMapping as described in

http://msdn.microsoft.com/en-us/library/windows/desktop/aa366551(v=vs.85).aspx

Sara
0
 
jkrConnect With a Mentor Commented:
You have two options - writing each individual field as a separate value or using REG_BINARY to write the entire struct, e.g.

bool WriteMyStruct(HKEY Key, MyStruct* pBuf) 
{
    if (RegSetValueEx (Key, _T("MyStruct"), 0, REG_BINARY, (LPBYTE) pBuf,  
                      sizeof(MyStruct)) == ERROR_SUCCESS) return true; 
    else return false; 
}

Open in new window


To read that, you'd just use

bool ReadMyStruct(HKEY Key, MyStruct* pBuf) 
{
    DWORD dwType = REG_BINARY;
    DWORD dwSize = sizeof(MyStruct);
    if (RegQueryValueEx (Key, _T("MyStruct"), 0, &dwType, (LPBYTE) pBuf,  
                      &dwSize) == ERROR_SUCCESS) return true; 
    else return false; 
}

Open in new window

0
 
Subrat (C++ windows/Linux)Software EngineerCommented:
Your requirement is not fully clear. But I hope you are new to C++ struct. If so please follow the link:
http://www.cplusplus.com/doc/tutorial/structures/

PSceoudo code:
struct myStruct {
  std:;string data1;
  int data2;
};

Regarding Registry:
You can use
RegOpenKeyEx()
RegQueryValueEx()
RegCloseKey()
This will read the value from registry according to the input to the functions.
Finally set read out values to structure.

If you want to access data of one process in other process then you have to use Inter Process Communication(IPC) or Shared Memory.

If you are facing any specific issue in codeing then you can show the snap shot!
0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
QlemoDeveloperCommented:
Since those are just two values you need to manage, use the "write individual field" approach. Storing binary data should be done only for more complex scenarios.
0
 
HarishMinuAuthor Commented:
My requirement is

One process will be invoked many times by external process to create multiple tasks.
First it will check No.1 task if it is free it will assign the job to process else it will create No.2 task and goes on for N tasks.

In order to synchronize, I need to keep the data of the process ( time created and process id, etc. ) in a temporary memory and reset the data after completion. If 2nd process is invoked it will check No1 task data, it is already in processing it will go and create No2 task else it will assign to No1 task.

what will be best way to implement this ?
please let me know if it is not clear.

Apologies for not explaining in detail.
0
 
sarabandeCommented:
if the tasks are threads and not processes, they could access any shared data of the (parent) process. so writing to registry or any other shared storage would not be necessary.

struct threadinfo 
{  
    HANDLE threadhandle; 
    bool busy;
    threadinfo() :  threadhandle(NULL), busy(false) {}
};

class ThreadManager
{
    enum { max_threads = 64 };
    std::string date;
    int number;
    threadinfo ti[max_threads];

    void handleThreads(const std:.string& dat, int num);
    bool wait_for_task();

    static void thread_func(void * p);
public: 
    const std::string & get_date() { return date; }
    int  get_num() { return number; }
};

void ThreadManager::handleThreads(const std:.string& dat, int num)
{
    date = dat;
    number = num;

    while (true)
    {
         if (wait_for_task() == false) break;
         
         for (int n = 0; n <  max_threads; ++n)
         {
              if (ti[n].busy == false)
              {
                    ti[n].busy = true;
                    ti[n].thread_handle = _begin_thread(thread_func, 0, this);
                    break;
             } 
        }
} 

Open in new window


with the above all threads could access the date and number by means of the ThreadManager.

void ThreadManager::thread_func(void * p)
{
    ThreadManager * pthis = (ThreadManager *)p;
    ...
    std::string date = pthis->get_date();
    ...

Open in new window


if the tasks are different processes i nevertheless would use a similar concept. you either pass the information when the processes were created - for example by commandline arguments- or if the client processes can be used for different tasks - you do some program-to-program communication (see also comment of Subrat), where windows messages probably are the easiest way though they require at least a pseudo window and message loop for each participant.

Sara
0
 
QlemoDeveloperCommented:
Maybe using a Shared Memory segment is a better idea for interprocess communication ...
0
 
jkrCommented:
One good start certainly would be to post the exact declaration of your structure.
0
 
HarishMinuAuthor Commented:
Thanks Sara

CopyMemory method is missing in above code, Is it is not necessary ?

I am unable to set the first PVOID parameter to struct in CopyMemory method.

Thank you .
0
 
jkrCommented:
That basically works the same way as I showed you how to do that with the registry, which was your original question. Why do you want to abandon your own approach now?
0
 
sarabandeCommented:
CopyMemory method is missing in above code, Is it is not necessary

it depends. if you return the pbuf pointer as const and the caller would assign it to its own struct variable it is safe enough:

mystruct * ps = get_mystruct_from_shared_memory();

if (ps == NULL)
    return;

mystruct ms;
ms = *ps;   // copies the shared memory to a local

Open in new window


registry entries rarely are used for p2p (too slow). it is recommendable for properties or settings, though. so shared memory is fine for client-server on one machine. you could have a big structure which has a separate section for each participant. that way each side could write to its exclusive space in memory. you only would need to lock read and write operations by a named mutex if the information was updated periodically. if the data is more a constant which is not a matter of change the registry approach jkr has shown is more simple and allows you an easy external update by using regedit.

Sara
0
 
HarishMinuAuthor Commented:
here is my entire code
main

#include "stdafx.h"

#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>

struct MyStruct
{
      int ID;
      LPWSTR text;
};

#define BUF_SIZE 256


int _tmain(int argc, _TCHAR* argv[])
{



      HANDLE hMapFile = NULL;
    MyStruct * pBuf = new MyStruct; // pointer to structure with date and number
      pBuf->ID = GetCurrentProcessId ();
      pBuf->text = L"Test1";

   hMapFile = CreateFileMapping(
                 INVALID_HANDLE_VALUE,    // use paging file
                 NULL,                    // default security
                 PAGE_READWRITE,          // read/write access
                 0,                       // maximum object size (high-order DWORD)
                 sizeof(MyStruct),                // maximum object size (low-order DWORD)
                 L"SomeUniqueName");                 // name of mapping object

   if (hMapFile == NULL)
   {
      _tprintf(TEXT("Could not create file mapping object (%d).\n"),
             GetLastError());      return 1;
   }

   pBuf = (MyStruct*) MapViewOfFile(hMapFile,   // handle to map object
                        FILE_MAP_ALL_ACCESS, // read/write permission
                        0,
                        0,
                        BUF_SIZE);

   if (pBuf == NULL)
   {
    _tprintf(TEXT("Could not create file mapping object (%d).\n"),
             GetLastError());
      CloseHandle(hMapFile);
      return 1;
   }


   UnmapViewOfFile(pBuf);

   CloseHandle(hMapFile);
 

      return 0;
}




Client

// ShareMem.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>

struct MyStruct
{
      int ID;
      LPWSTR text;
};

#define BUF_SIZE 256


int _tmain(int argc, _TCHAR* argv[])
{

      HANDLE hMapFile = NULL;
      MyStruct * pBuf = new MyStruct; // pointer to structure with date and number
      pBuf->ID = GetCurrentProcessId ();
      pBuf->text = L"Test1";

      hMapFile = CreateFileMapping(
            INVALID_HANDLE_VALUE,    // use paging file
            NULL,                    // default security
            PAGE_READWRITE,          // read/write access
            0,                       // maximum object size (high-order DWORD)
            sizeof(MyStruct),                // maximum object size (low-order DWORD)
            L"SomeUniqueName");                 // name of mapping object

      if (hMapFile == NULL)
      {
            _tprintf(TEXT("Could not create file mapping object (%d).\n"),
                  GetLastError());      return 1;
      }

      DWORD error = GetLastError ();

      if(error == ERROR_ALREADY_EXISTS)
      {


            pBuf = (MyStruct*) MapViewOfFile(hMapFile,   // handle to map object
                  FILE_MAP_ALL_ACCESS, // read/write permission
                  0,
                  0,
                  BUF_SIZE);

            if (pBuf == NULL)
            {
                  _tprintf(TEXT("Could not create file mapping object (%d).\n"),
                        GetLastError());
                  CloseHandle(hMapFile);
                  return 1;
            }

            printf("ID - %d, Name - %ls", pBuf->ID , pBuf->text );

      }

      UnmapViewOfFile(pBuf);

   CloseHandle(hMapFile);
 
      return 0;
}

I cannot able to get the struct data in the client. pls help
0
 
jkrCommented:
For either approach, you need to use

struct MyStruct
{
      int ID;
      wchar_t text[BUF_SIZE];
};

Open in new window

since a LPWSTR is a pointer and does not make sense in another process' context.


I can''t help, but

#include "stdafx.h"

#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <string.h>



#define BUF_SIZE 256

struct MyStruct
{
      int ID;
      wchar_t text[BUF_SIZE9;
};

bool WriteMyStruct(MyStruct* pBuf) 
{
    HKEY hKey;
    bool bResult = false;

    RegOpenKeyEx(HKEY_CURRENT_USER,L"MyApp",0, KEY_WRITE, '&hKey);

    if (RegSetValueEx (Key, _T("MyStruct"), 0, REG_BINARY, (LPBYTE) pBuf,  
                      sizeof(MyStruct)) == ERROR_SUCCESS) bResult = true; 
    
    RegCloseKey(hKey);

    return bResult;
}
                                            


int _tmain(int argc, _TCHAR* argv[])
{

      MyStruct * pBuf = new MyStruct; // pointer to structure with date and number
      pBuf->ID = GetCurrentProcessId ();
      wcscpy(pBuf->tex,L"Test1");

      WriteMyStruct(pBuf);

      return 0;
}

Open in new window


and

#include "stdafx.h"

#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <string.h>



#define BUF_SIZE 256

struct MyStruct
{
      int ID;
      wchar_t text[BUF_SIZE9;
};


bool ReadMyStruct(MyStruct* pBuf) 
{
    DWORD dwType = REG_BINARY;
    DWORD dwSize = sizeof(MyStruct);
    HKEY hKey;
    bool bResult = false;

    RegOpenKeyEx(HKEY_CURRENT_USER,L"MyApp",0, KEY_WRITE, '&hKey);


    if (RegQueryValueEx (Key, _T("MyStruct"), 0, &dwType, (LPBYTE) pBuf,  
                      &dwSize) == ERROR_SUCCESS) bResult = true; 


    RegCloseKey(hKey);

    return bResult;
}
                                            
                                            


int _tmain(int argc, _TCHAR* argv[])
{

      MyStruct * pBuf = new MyStruct; // pointer to structure with date and number

      ReadMyStruct(pBuf);

      return 0;
}

Open in new window


looks a little less complicated. Plus it is/was your very own approach.
0
 
jkrCommented:
One caveat - make sure that "HKEY_CURRENT_USER\MyApp" does actually exist.
0
 
sarabandeCommented:
I cannot able to get the struct data in the client. pls help

in both programs you need to add a wait such that the "server" and "client" both can keep up holding a handle on the shared memory. when there is no program which has an open handle to the shared memory, windows will free the space.

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <string.h>
you should turn both the projects from 'using precompiled headers' to 'not using precompiled headers' both for debug and release configuration. for that you would remove stdafx.cpp from project tree (you can only remove or delete it that makes no difference) and then go to configuration properties - c/c++- precompiled headers and change the 'precompiled header' option. precompiled headers is a compiler speed optimization which don't make so much sense for non-mfc projects and even for those it could make more problems as it helps. also I would recommend to change the character set from UNICODE to 'Multibyte' in the configuration properties - general (again both for debug and release). if you do so you could forget all the TCHAR/wchar_t, _T/L"", LPCTSTR, LPTSTR, _tmain, -tprintf stuff and use char, "", const char*, char *, main and std::cout instead:

#include <windows.h>
#include <string>
#include <iostream>

struct MyStruct
{
      int    i;
      char text[64];  // don't pass pointers but characters (see comment of jkr)
};
 
int main(int narg, char * szargs[])
{
       MyStruct ms = { 0, "Hello Client" };  // init structure or use strcpy(ms.text, "some text");
       // put here your code for writing to shared memory
       // you also can do the UnmapViewOfFile 
       // but don't close the handle to the memory mapped file
       ...
       std::cout << "server: successfully written a message to client into shared memory" << std::endl;
       std::cout << "server: waiting for client to read from shared memory: ";
       int r;
       std::cin >> r;         // here the program waits until you enter a number.
       
       // after input from console you can free the shared memory from your side
       CloseHandle(hMapFile);
       return r;
}

Open in new window


the client would be made similar. you would start the server first and then the client. both programs would print the success message on the screen and wait for input. you can stop the scenario by inputting a number to either program.

Sara
0
All Courses

From novice to tech pro — start learning today.