This whole thing started after I read the article:
http://www.codeproject.com/KB/system/TSAddinInCS.aspx?msg=3401010#xx3401010xx
I have since implemented this concept into my application. We currently
have a hosted VB6 application that rests on a Citrix server that speaks to a
VB6 applicationi on the the local machine using the Citrix Virtual channels.
Granted the virtual channel component was written in C. None the less, our
clients are asking for an RDP option as well.
Upon reading that article, we set out to prototype this solution and asked
MS to assist use with the the finer points 2 years ago. At the time, no one
said hey this is a very bad idea. The prototype is fairly simple but it
works none the less.
Now that we have the pieces in place for the testing stage, I encountered an
odd behavior. The first time the hosted application requests the local
machine to perform a task the local machine does so and then sends a result
back to the hosted app. The workflow is that the local machine then closes
the UI. Any subsequent call from the hosted app still invokes the local
machine's UI, however, the result information is never recieved by the
hosted application.
I have verified that the message is generated and sent to the channel. I
have verified that the channel receives the message and calls the send
message api. The server side of the channel never recieves the data. No
errors are generated and I am dumbfounded as to what my problem is. I have
proven (at least I think) that the channel is still open - any attempt to
close it on the server side cause an application crash.
So when I went to MS with this problem, they never even looked at the code.
They simply said that it was a bad idea and that I should abort, citing that
KB article.
Assuming that the message is being sent up the channel here is the failing
code on the server side:
void workerThread_DoWork(object sender, DoWorkEventArgs e)
{
//Variable Declaration Section.
bool success = false;
IntPtr intHandlePtr;
byte[] bytes = new byte[2048];
uint bytesread = 0;
int bytesRead = 0;
bool bContinue = true;
BackgroundWorker bgw = (BackgroundWorker)sender;
if (!bgw.CancellationPending)
{
//Query the Virtual Channel and get the underlying File Handle.
success = WtsApi32.WTSVirtualChannelQuery(
mHandle,
(int)WtsApi32.WTS_VIRTUAL_CLASS.WTSVirtualFileHandle,
out intHandlePtr,
ref bytesRead
);
//intHandlePtr is a double pointer buffer in the unmanaged world.
Retrieve the File Handle Pointer
//correctly by marshalling it.
IntPtr pFileHandle = Marshal.ReadIntPtr(intHandlePtr);
// Create an manual-reset event, which is initially set to Non
Signalled.
IntPtr myEventHandle = Kernel32.CreateEvent(IntPtr.Zero, false,
false, "MyEvent");
//Declare and initialize the OVERLAPPED structure and initialize it
correctly.
System.Threading.NativeOverlapped ovr = new
System.Threading.NativeOverlapped();
ovr.InternalHigh = IntPtr.Zero;
ovr.InternalLow = IntPtr.Zero;
ovr.OffsetHigh = 0;
ovr.OffsetLow = 0;
ovr.EventHandle = IntPtr.Zero;
//Assign the Created Event handle in the Overlapped structure.
ovr.EventHandle = myEventHandle;
while (bContinue == true)
{
//Reset the event.Still the client is in progress.
Kernel32.ResetEvent(ovr.EventHandle);
//Read any Progress data from the channel if any.
bool b = Kernel32.ReadFile(pFileHandle, bytes, (uint)bytes.Length,
out bytesread, ref ovr);
if (this.OnMessageReceived != null)
{
try
{
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
System.IO.MemoryStream ms = new System.IO.MemoryStream(bytes);
SimpleMessage sr = (SimpleMessage)bf.Deserialize(ms);
//Notify the calling app that we have new data
this.OnMessageReceived(bytes);
bContinue = false;
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.ToString());
}
if (bgw.CancellationPending) break;
}
//If not wait till the data arrives.Once the data arrives , the
event handle in the overlapped
//structure will get signaled and the WaitforSingleObject will
continue going for the next data.
int i = Kernel32.WaitForSingleObject(ovr.EventHandle,
(int)Kernel32.INFINITE);
}
//Thread is going to exit.Release the Pointer obtained.
WtsApi32.WTSFreeMemory(intHandlePtr);
//Close the channel here depending upon your requirement.
WtsApi32.WTSVirtualChannelClose(intHandlePtr);
}
}
Mike Lovell said:
What was the problem?
I think it's likely we'd need more details on what you're exactly trying
to do (if you can disclose this information).
Perhaps the lines of source relevant to the problem.
.