|
Hi,
the application which I'm working on is based on
a client server architecture
|java gui| <- gsoap -> |c++ server|
where the server is a windows or unix program, which embeds the business logic.
I want to make a gui for users, who don't need to know about that
and simply start the gui as if it was the whole app.
Thus the gui is managing server instantiation -
gui started && server not running => gui starts server.
gui started && server running => gui uses server.
server has no more session within timeout => server exits gracefully.
So what I actually would need is a singleton server and this would mean
to query the OS for the existence of the server process.
Java has no method to
query process lists on a system independent level or to
check, whether there is a certain process running -
there's just rudimentary support for process control.
Java is gui standard here. So I made a little app (nmmutex) which is
supposed to control a named mutex for the server's main thread. This app
exits always and writes it's result (acquired, not acquired) to the
return code. The mutex is queried in a non-blocking manner (try_to_lock).
Java can run that process via Runtime.exec.
Using that mutex, the server itself may control, whether there is already
an instance running. It also can try_to_lock the mutex, and if it's not
available, may return. The server itself could also take the role of nmmutex,
i.e. to query the mutex.
The caveat of using the mutex is, as far as I understood, that boost
interprocess objects like mutex and shared memory due to portability have
'kernel or filesystem' persistence. On windows it's filesystem persistence.
So if the server crashes, it might not be restartable even after a reboot.
And the user can't tell why.
I tend to dislike the mutex idea meanwhile, although using it seemed logical
to me first: I wanted to restrict use of server's main block to a single thread.
I could try to get a soap session at gui startup and assume the server does not
run when it fails. Or maybe there's a library which hides querys to the os,
like process list, behind a portable interface.
Cheers
Werner
modified on Thursday, January 27, 2011 4:00 AM
|
|
|
|
|
Thanks for the details. So basically, you do not need the "synchronization" aspect of a mutex, just the "global name" aspect to check for exists / doesn't-exist check. I have used two methods for exactly this problem. Both methods "reset" when the image exits because Windows cleans up the objects.
One is to use "named pipes". This method has been suggested by other people in Code Project. You create a pipe with a known name agreed upon by the two processes. When you say "gui uses server", I assume you communicate in some way, you might even use pipes. I prefer this method when I need to also communicate between the processes as it provides for both a "single server instance" and the "interprocess communication".
Here's a routine I use to create an "inbound" pipe (the server code) in such a way as there will be only 1 instance. The error INVALID_HANDLE_VALUE indicates that you cannot create the pipe which is taken to mean that the pipe is already in use. I've "scrubbed" this a little to remove things I cannot share with you.
#ifndef FILE_FLAG_FIRST_PIPE_INSTANCE
#define FILE_FLAG_FIRST_PIPE_INSTANCE 0x00080000 // make VC 6.0 happy
#endif
#define RTLOCALIPC_WIN_SDDL \
SDDL_DACL SDDL_DELIMINATOR \
SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" SDDL_GENERIC_ALL ";;;" SDDL_NETWORK SDDL_ACE_END \
SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" SDDL_GENERIC_ALL ";;;" SDDL_EVERYONE SDDL_ACE_END \
SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" SDDL_FILE_ALL ";;;" SDDL_LOCAL_SYSTEM SDDL_ACE_END
HANDLE CreateInboundPipe(CString PName, bool first)
{
CString ts;
SECURITY_ATTRIBUTES *SecAttrs = NULL;
DWORD dwOpenMode;
DWORD dwPipeMode;
PSECURITY_DESCRIPTOR pSecDesc = NULL;
ConvertStringSecurityDescriptorToSecurityDescriptor(RTLOCALIPC_WIN_SDDL, SDDL_REVISION_1, &pSecDesc, NULL);
SecAttrs = (SECURITY_ATTRIBUTES *)malloc(sizeof(SECURITY_ATTRIBUTES));
SecAttrs->nLength = sizeof(SECURITY_ATTRIBUTES);
SecAttrs->lpSecurityDescriptor = pSecDesc;
SecAttrs->bInheritHandle = FALSE;
dwOpenMode = PIPE_ACCESS_DUPLEX | (first ? FILE_FLAG_FIRST_PIPE_INSTANCE : 0);
dwPipeMode = PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT;
ts.Format("\\\\.\\pipe\\%s", PName);
ThePipe = CreateNamedPipe(ts, dwOpenMode, dwPipeMode, PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, NMPWAIT_USE_DEFAULT_WAIT, SecAttrs);
free(SecAttrs);
LocalFree(pSecDesc);
return ThePipe;
}
The "client" can then try to connect to the same pipe name and if it discovers that the server isn't available, it could start an instance of the server. Again "scrubbed" a bit since I can't cut / paste the entire routine.
HANDLE ConnectToServer(CString PName, bool NoRetry)
{
CString ts;
int retry = 0;
ts.Format("\\\\.\\pipe\\%s", PName);
while (1)
{
ThePipe = CreateFile(ts, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if ((NoRetry) || (ThePipe != INVALID_HANDLE_VALUE))
break;
if (GetLastError() == ERROR_PIPE_BUSY)
{
WaitNamedPipe(ts, NMPWAIT_WAIT_FOREVER);
}
else
{
if (retry++ == 0)
{
}
if (retry > (GIVE_UP_TIMER / GIVE_UP_SLEEP))
break;
Sleep(GIVE_UP_SLEEP);
}
}
if (ThePipe != INVALID_HANDLE_VALUE)
{
DWORD dwMode = PIPE_READMODE_MESSAGE;
SetNamedPipeHandleState(ThePipe, &dwMode, NULL, NULL);
Connected = true;
}
return ThePipe;
}
since these are part of a larger Class, there are some Class Members I don't show, like ThePipe, the Timeouts, etc. But you should be able to figure those out.
The other method I use, especially for "short lived processes" is to simply open a known file with GENERIC_WRITE, in other words, take out an exclusive access lock on a shared file. Only 1 process can do this and the kernel manages that. The kernel will "close" the access when the image exits so cleanup is easy. If the "client" can get the exclusive access lock, then the server is not running so it can release the file and then start the server. This method does suffer from some timing issues and you'll need a retry mechanism like the one used for the pipes to avoid some startup problems.
|
|
|
|
|
Is there any way to find which interface a UDP packet was received on? I can't rely on using the IP addresses since it is possible (and fairly common for out of the box setup) that the device I'm talking to has a misconfigured IP.
In other words,
If a new device out of the box has a 10.1.0.1 address and my NIC that I am using to plug into it has a 192.x.x.x address, my program will eventually try broadcasting to it and a reply will come back with source address 10.1.0.1 on that NIC. This is why I cannot use IP addresses to try to determine which interface received the message.
Thanks,
Dave
|
|
|
|
|
You will need to capture entire packet frame with Mac address still in tact. One way is to use a packet capture library like Winpcap. But I certainly doubt that you can get it using normal socket operations; Since it strips off the packet headers before giving it to user application.
|
|
|
|
|
CRegKey regkey;
TCHAR modbuffer[MAX_PATH];
DWORD dwModPathLen = ::GetModuleFileName(NULL, modbuffer, _countof(modbuffer));
if (dwModPathLen == 0 || dwModPathLen == _countof(modbuffer))
return;
CString strCanonFileName = modbuffer;
strCanonFileName.Replace(_T("%"), _T("%%"));
CString regbuffer;
regbuffer.Format(_T("\"%s\""), strCanonFileName);
CString csKeyName = _T("MyProgram");
HKEY hkeyCR = HKEY_LOCAL_MACHINE;
if (bAutoRun)
{
if (regkey.Open(hkeyCR, _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"),
KEY_ALL_ACCESS) != ERROR_SUCCESS)
{
regkey.SetStringValue(csKeyName, regbuffer);
regkey.Close();
}
}
else
{
if (regkey.Open(hkeyCR, _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"), KEY_READ) != ERROR_SUCCESS)
{
regkey.RecurseDeleteKey(csKeyName);
regkey.Close();
}
}
}
The Exception is m_Key is NULL. My system is windows 7. Is it the Priviledge problem?
modified on Tuesday, January 25, 2011 8:54 PM
|
|
|
|
|
Check what Open returns, it should explain the problem.
> The problem with computers is that they do what you tell them to do and not what you want them to do. <
> Leela: Fry, you're wasting your life sitting in front of that TV. You need to get out and see the real world.
Fry: But this is HDTV. It's got better resolution than the real world <
>Nothing is free in the universe.<
|
|
|
|
|
yu-jian wrote: The Exception is m_Key is NULL.
There isn't an 'm_key ' in posted code.
yu-jian wrote: s it the Priviledge problem?
Probably. However, Checking API calls return values would help.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
yu-jian wrote: Is it the Priviledge problem?
If you run the program as admin and it works, then the answer is Yes.
|
|
|
|
|
yu-jian wrote: Is it the Priviledge problem?
No it's the coding problem. In both of your Open() statements you are checking if the return code is not equal to ERROR_SUCCESS , and proceeding if it is not. These tests should be reversed so you only proceed if the return is equal to ERROR_SUCCESS . Also you should capture the returned value as it will help you to diagnose what has gone wrong.
I must get a clever new signature for 2011.
|
|
|
|
|
OK. The return value was 5.
Now this problem resolved. Under win7 it needs Administrator priviledge to run. Under the xp, It can operate register directly.
|
|
|
|
|
|
what is a bitwise copy in c++ done by default constructor and what is shadow copy and deep copy ?
|
|
|
|
|
Please, Let Me Google That For You[^].
BTW It is 'shallow' copy.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
Bitwise copy (AKA shallow copy) copies the bits of the struct/class, including arrays. So the destruction of either may cause problems if they are not destroyed together.
A deep copy contains its own definition of all data including array to avoid this negative consequence.
|
|
|
|
|
aesthetic.crazy wrote: what is a bitwise copy in c++ done by default constructor
You mean by a compiler-generated copy constructor? It is not a bitwise copy of the object. It copies each member by invoking its copy constructor.
|
|
|
|
|
If your class/struct contains pointers (i.e. dynamically allocated data) a shallow/bitwise copy will copy the value of the pointer so that both classes point to the same data object.
While this is great for performance issues, it means that if 1 class modifies or deletes the data, the data will be changed or invalidated in the other copy of the class (as per T2102's answer).
A deep copy on the other hand will allocate a new chunk of memory and copy the contents from the memory pointed to by pointers so that the copy will have its own copy of the dynamic data to modify and delete.
Just to clarify on the use of a deep copy, you must provide the copy constructor yourself like
class MyClass : public BaseClass {
MyClass(const MyClass &objOther) : BaseClass(objOther) {
}
};
Note the parameter const MyClass &objOther , you must pass the other class in as a reference (preferable) or a pointer, otherwise the copy constructor would need to be called in order to call the copy constructor resulting in infinite recursion.
If the class has a base class, you also need to call its copy constructor in order to give it a chance to copy any memory that it may have dynamically allocated. Even if you know it doesn't this is still good style and will save you hassles if you add it in later on.
If your class has a statically allocated array by use of the square brackets [] in the class definition, and no dynamic pointers that need explicit copying, then you don't need a copy constructor, as the syntax char szMyString[20]; will allocate 20x char inside the class, so a bitwise copy will copy that.
If you provide a copy constructor, only what you explicitly copy will be copied, that is an int variable will not be copied unless you tell it to. Anything not copied should be initialised, usually by means of an initialiser list. The bitwise copy will only be provided if you don't provide a copy constructor.
If you don't want a class to be copied, simply declare its copy constructor under a private tag, then just provide no code for the function body (although you still need the code MyClass::MyClass(const MyClass &objOther) { } ) so that the function is defined.
|
|
|
|
|
Hi,
My application is MDI application.But im making one window as SDI.In that window i want Menu,Customized toolbar(DialogBar).
What i did.
in app class
pAlarmViewTemplate = new CSingleDocTemplate(
IDR_ALARMMENU,
RUNTIME_CLASS(CFoxboroDoc),
RUNTIME_CLASS(CFrameWnd),
RUNTIME_CLASS(CAlarmView));
AddDocTemplate(pAlarmViewTemplate);
For loading DialogBar in Oncreate function
// Create the Alarm view dialog bar
if( !m_wndAlarmDlg.Create(this, IDD_ALARM_DIALOGBAR, CBRS_BOTTOM |CBRS_FLYBY|CBRS_SIZE_DYNAMIC, IDD_ALARM_DIALOGBAR))
{
TRACE0("Failed to create the Alarm\n");
return -1;
}
where m_wndAlarmDlg is a dialogbar class object.
But when executing ,it doesnot show dialog bar.when i check this variable in Create function,it shows
this = 0x0624ca70 {CAlarmView hWnd=0x00000000}
I dont know how to do that.
--------------------------------------
I choose this only one SDI window in MDI window for getting customized menu for AlarmView .But i dont know how to get customized menu in childwindow of MDI.If i get this one,then i dont want to go for SDI.
Anu
|
|
|
|
|
i am trying to delete Cookies and History directories programmatically but not Possible because of index.dat file... How do i come out from this problem..?
|
|
|
|
|
|
This solution only works for your personal desktop... I run CCleaner from the command line (scheduled task on shutdown) to delete histories, etc.
|
|
|
|
|
Not able to debug my project it is shown as 'The breakpoint will not currently be hit.No symbols have been loaded for this document.'The break point is shown as an error symbol.Along with it showing another project's function name.I am using VC2005.How to solve this?
|
|
|
|
|
1) Are you sure the location where you are placing a breakpoint is in the relevant project and not a dll that it depends on?
2) Have you compiled your add-in(s) recently and made sure the latest version in your path match the versions that you just compiled.
3) Do you have debug information enabled?
|
|
|
|
|
|
I understand that the breakpoints are set; this is a common problem most often due to #1 - 3 I mentioned before.
Does your program rely on any dlls? Is it an exe or dll supporting excel for instance?
|
|
|
|
|
|