I run the code example below with GC.KeepAlive() on and commented out, but it is the same. How to code so I can see the difference.
// A simple class that exposes two static Win32 functions.
// One is a delegate type and the other is an enumerated type.
public class MyWin32
{
// Declare the SetConsoleCtrlHandler function
// as external and receiving a delegate.
[DllImport("Kernel32")]
public static extern Boolean SetConsoleCtrlHandler(HandlerRoutine Handler,
Boolean Add);
// A delegate type to be used as the handler routine
// for SetConsoleCtrlHandler.
public delegate Boolean HandlerRoutine(CtrlTypes CtrlType);
// An enumerated type for the control messages
// sent to the handler routine.
public enum CtrlTypes
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT,
CTRL_CLOSE_EVENT,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT
}
}
public class MyApp
{
// A private static handler function in the MyApp class.
static Boolean Handler(MyWin32.CtrlTypes CtrlType)
{
String message = "This message should never be seen!";
// A switch to handle the event type.
switch(CtrlType)
{
case MyWin32.CtrlTypes.CTRL_C_EVENT:
message = "A CTRL_C_EVENT was raised by the user.";
break;
case MyWin32.CtrlTypes.CTRL_BREAK_EVENT:
message = "A CTRL_BREAK_EVENT was raised by the user.";
break;
case MyWin32.CtrlTypes.CTRL_CLOSE_EVENT:
message = "A CTRL_CLOSE_EVENT was raised by the user.";
break;
case MyWin32.CtrlTypes.CTRL_LOGOFF_EVENT:
message = "A CTRL_LOGOFF_EVENT was raised by the user.";
break;
case MyWin32.CtrlTypes.CTRL_SHUTDOWN_EVENT:
message = "A CTRL_SHUTDOWN_EVENT was raised by the user.";
break;
}
// Use interop to display a message for the type of event.
Console.WriteLine(message);
return true;
}
public static void Main()
{
// Use interop to set a console control handler.
MyWin32.HandlerRoutine hr = new MyWin32.HandlerRoutine(Handler);
MyWin32.SetConsoleCtrlHandler(hr, true);
// Give the user some time to raise a few events.
Console.WriteLine("Waiting 30 seconds for console ctrl events...");
// The object hr is not referred to again.
// The garbage collector can detect that the object has no
// more managed references and might clean it up here while
// the unmanaged SetConsoleCtrlHandler method is still using it.
// Force a garbage collection to demonstrate how the hr
// object will be handled.
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Thread.Sleep(30000);
// Display a message to the console when the unmanaged method
// has finished its work.
Console.WriteLine("Finished!");
// Call GC.KeepAlive(hr) at this point to maintain a reference to hr.
// This will prevent the garbage collector from collecting the
// object during the execution of the SetConsoleCtrlHandler method.
GC.KeepAlive(hr);
Console.Read();
}
}
http://msdn.microsoft.com/en-us/library/system.gc.keepalive.aspx
Thanks.
GC.KeepAlive(hr);
Is by itself a reference (later in the code) ...
So hr can't be collected at the point(s) where you cal GC.Collect().
What exactly did you expect to happen?
Related
I've created a simple c# COM component that is meant to be called by a C++ MFC application. It works but has an undesired side-effect.
The C++ client calls the c# component using it's main GUI thread, so I can't block it because the C# code is making Database operations that may take longer. That's why i need async or a thread for this...
This is the C# code, simplified:
public async void ShowOverviewDialogAsync()
{
var w = new Window();
var dbOperationOk = await LongDbOperaionAsync();
w.ShowDialog();
}
Well, the C++ code goes in, and returns after the call to async which is expected. Here is the C++ calling code:
HRESULT hr = cSharpCom.CoCreateInstance(__uuidof(CSharpCom));
if (SUCCEEDED(hr))
{
cSharpCom->ShowOverviewDialogAsync();
}
// continues without waiting for the dialog close...
The thing is, after this call, the C++ code continues to do its thing and the cSharpCom object goes out of scope. So the only way to call a Release is to make the c# object a member and on destructing or creating a new one, do a release call:
if (_cSharpCom != NULL) _cSharpCom->Release();
HRESULT hr = _cSharpCom.CoCreateInstance(__uuidof(CSharpCom));
if (SUCCEEDED(hr))
{
_cSharpCom->ShowOverviewDialogAsync();
}
This is the first Drawback. The second drawback is that the modal C# window is not a real Modal window as the message pooling of the MFC(C++) continues as normal, which is actually undesired (Right?)
These are the current ideas:
return a HWND to the calling code and somehow make the modal call using the C++ Cwnd:RunModalLoop.
return some kind of event to the calling code, that can be waited upon without blocking the GUI thread.
set a callback that will make sure the COM object will be released.
override the Task class so that it returns a COM aware Interface that allows the C++ code to wait on something (see 2. and 3.)
Number 4 is what I will probably try out. The COM signature would look like:
HRESULT _stdcall ShowOverviewDialogAsync([out, retval] IUnknown** pRetVal);
Just for the lack of completeness, if the method has no async, the MFC C++ GUI hread works as expected and shows the Window in a modal way:
public void ShowOverviewDialogAsync()
{
var w = new Window();
var dbOperationOk = LongDbOperaion();
w.ShowDialog(); // C++ will wait here - non-blocking
}
If you are asking why my async method is returning void. Well, it's defined in an interface and I can't use Task as a return value, unless I go for the solution 4 above.
[ComVisible(true)]
[Guid("XXXXXX-xxxx-xxx-xxx-XXXXX")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ICSharpCom
{
/// <summary>
/// Displays the dialog in async mode
/// </summary>
[DispId(0)]
void ShowOverviewDialogAsync();
}
Besides, COM interop does not accept generics like Task.
How to test it. Create a MFC application with one button that calls the c# com as defined.
Any ideas appreciated.
cheers,
Marco
I've managed to get it working, although I'm not very happy with the spaghetti code needed in c++.
This is how I've managed until now:
[ComVisible(true)]
[Guid("XXXXXX-xxxx-xxx-xxx-XXXXX")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ICSharpCom
{
/// <summary>
/// Displays the dialog in async mode
/// </summary>
[DispId(0)]
void ShowOverviewDialogAsync(IntPtr eventHandle);
}
//Implementation:
...
_resetEvent = new ManualResetEvent(false);
m.SafeWaitHandle = new Microsoft.Win32.SafeHandles.SafeWaitHandle(eventHandle, ownsHandle);
// ... at some later point in the method, when the window closes
_resetEvent .Set()
Until now, looks ok.
On the C++ side it gets complicated:
auto handle = CreateEvent(NULL, TRUE, FALSE, CString("MyEvent"));
if (handle != NULL)
{
HANDLE handles[] = { handle };
hr = prescOverview->ShowOverviewDialog((long)handle);
auto handleCount = _countof(handles);
if (SUCCEEDED(hr))
{
BOOL running = TRUE;
do {
DWORD const res = ::MsgWaitForMultipleObjectsEx(
handleCount,
handles,
INFINITE,
QS_ALLINPUT,
MWMO_INPUTAVAILABLE | MWMO_ALERTABLE);
if (res == WAIT_FAILED)
{
running = FALSE;
hr = GetLastError();
break;
}
else if (res == WAIT_OBJECT_0 + 0)
{
CComBSTR err;
prescOverview->GetError(&err);
CString errContainer(err);
if (errContainer.GetLength() > 0)
{
// log
hr = E_FAIL;
}
else {
hr = S_OK;
}
running = FALSE;
break;
}
else if (res >= WAIT_OBJECT_0 && res <= WAIT_OBJECT_0 + handleCount)
{
// process messages.
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
PostQuitMessage(static_cast<int>(msg.wParam));
hr = ERROR_CANCELLED;
running = FALSE;
break;
}
else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
} while (running);
}
CloseHandle(handle);
}
}
It's working. However The calling client must know how to do it -> read the docs and it's not intuitive.
I'm still working on it though.
Cheers,
Marco
I've just noticed i've never updated this.
Well, the easiest way to achieve this is to use events. If you are using ATL this will help you. I've managed this by first declaring the C# COM like this:
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(ICSharpCom))]
[ComSourceInterfaces(typeof(ICSharpComEventHandler))]
[Guid("XXXXXX-xxxx-xxx-xxx-XXXXX")]
public class CSharpCom : ICSharpCom
{
[ComVisible(false)]
public delegate void WorkCompleted(string result);
public event WorkCompleted OnWorkCompleted;
public int DoWork(string input)
{
Task t = ....
// do some hard work aync by usin
OnWorkCompleted?.Invoke(t.Result);
}
}
[ComVisible(true)]
[Guid("XXXXXX-xxxx-yyy-xxx-XXXXX")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface ICSharpComEventHandler
{
[DispId(1)]
void OnWorkCompleted(string result);
}
On The C++ side, it's not that easy
_ATL_FUNC_INFO OnWorkCompletedInfo = {CC_STDCALL, VT_EMPTY, 1, {VT_BSTR}};
class CEventSink : public IDispEventSimpleImpl<ONE_GOOD_ID, CEventSink, &DIID_ICSharpComEventHandler>
{
public:
BEGIN_SINK_MAP(CEventSink)
SINK_ENTRY_INFO(ONE_GOOD_ID, DIID_ICSharpComEventHandler, 1, OnWorkCompleted, &OnWorkCompletedInfo)
END_SINK_MAP()
const void __stdcall OnWorkCompleted(_bstr_t result)
{
// do something
}
CEventSink(CComPtr<ICSharpCom> psharp)
{
if (!pEps)
{
throw std::invalid_argument("psharp was null");
}
m_pSharp = psharp;
DispEventAdvise(m_pSharp);
}
void __stdcall StartListening()
{
DispEventAdvise(m_pSharp);
}
void __stdcall StopListening()
{
DispEventUnadvise(m_pSharp);
m_pSharp = nullptr;
}
private:
CComPtr<ICSharpCom> m_pSharp;
};
That's it guys.
Sorry for not posting before.
Cheers,
Marco
StackTrace: at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
Source: mscorlib
I see in the target source something about reflection. So i'll post the very small amount of code that uses reflection.
I normally am able to find NullReferenceExceptions easily. This one though does not appear to be my code, and I can not figure it out to save my life. I have this code bot in VB.net, and C#.Net Both have the same problem. I think that my problem is in how my pointer works, but I could be wrong.
The code is straight forward. I have a barcode scanner attached via usb that is in COM mode. I copied some of my code from another program that uses this same barcode that works perfectly. But to sum up what it does is that it opens, then, by use of reflection, gets the Pointer to the open com port, sets up a DataEventListener. When I scan something i wait 100ms, then spit out the data in string form. Simple as could be. The difference between my code and the other one that works flawlesly is that I have to get the pointer. To turn on my scanner i need a pointer to the comport using IntPtr. C# I use IntPtr, in VB i use SafeFileHandle. Both have the same error. The only time the error occurs is when a data event is fired. This is why I think it has to be with the handle. What is strange is that the Handle is needed to turn on and off the imager so I know i have a valid handle. (just don't know if it is held on to) So does anyone have any help or resources as to why I am having this error?
First up.. VB.NET
Public Class ImagerOposDevice
Inherits AbstractOPOSDevice
Dim PortHandle As SafeFileHandle
Dim ImagerPort As SerialPort
Public exitCode = 1
Sub New(ByVal comName As String)
ImagerPort = New SerialPort(comName)
End Sub
Protected Overrides Function Open() As Boolean
ImagerPort.Open()
PortHandle = GetHandleFromSerialPort(ImagerPort)
If Not PortHandle.IsInvalid Then
AddHandler ImagerPort.DataReceived, AddressOf DataReceivedHandler
End If
Return (Not PortHandle.IsInvalid)
End Function
Protected Overrides Sub Close()
Try
ImagerPort.Close()
ImagerPort.Dispose()
Catch ex As Exception
Console.WriteLine(ex.Message)
Console.ReadLine()
End Try
End Sub
Protected Overrides Function RunCommand(ByVal X As Integer) As Boolean
If X = 0 Then
Return TurnImagerOn()
ElseIf X = 1 Then
Return TurnImagerOff()
Else
Return False
End If
End Function
Private Shared Function GetHandleFromSerialPort(ByVal sp As SerialPort) As SafeFileHandle
Dim BaseStream As Object = sp.BaseStream
Dim BaseStreamType As Type = BaseStream.GetType
Return BaseStreamType.GetField("_handle", BindingFlags.NonPublic Or BindingFlags.Instance).GetValue(BaseStream)
End Function
Private Sub DataReceivedHandler(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs)
Try
'Dim sp As SerialPort = CType(sender, SerialPort)
System.Threading.Thread.Sleep(100)
Dim len = ImagerPort.BytesToRead
Dim buffer(len - 1) As Byte
ImagerPort.Read(buffer, 0, len)
Dim indata As String = System.Text.ASCIIEncoding.ASCII.GetString(buffer)
Console.WriteLine("Data Received:")
Console.Write(indata)
TurnImagerOff()
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
exitCode = 0
End Sub
in my main form it is straight forward
imager = New ImagerOposDevice("COM7")
imager.OpenDevice()
imager.SendCommand(0)
For index = 1 To 100 Step 1
System.Threading.Thread.Sleep(100)
If imager.exitCode = 0 Then
Exit For
End If
Next
Console.WriteLine("Press Enter to Close")
Console.ReadLine()
CloseDevices()
Now for the C# code. It is a windows form, but the concept is almost identicle.
private SerialPort devicePort;
private IntPtr deviceHandle;
public Imager(string Port) : base()
{
devicePort = new SerialPort(Port);
}
protected override bool Open()
{
try
{
devicePort.Open();
deviceHandle = GetHandleFromSerialPort(devicePort);
Console.WriteLine("Device Handle:{0}", deviceHandle);
Console.WriteLine("Device Open:{0}", devicePort.IsOpen);
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
return devicePort.IsOpen;
}
protected override bool Close()
{
devicePort.Close();
devicePort.Dispose();
return true;
}
protected override CommandReturnCodes RunCommand(int command)
{
switch (command)
{
case 0:
TurnImagerOn();
break;
case 1:
TurnImagerOff();
break;
case 2:
ReadLatch();
break;
case 3:
GetPartNumber();
break;
case 4:
GetSerialNumber();
break;
case 5:
GetProductString();
break;
default:
return CommandReturnCodes.FAIL;
}
return CommandReturnCodes.SUCCESS;
}
private static IntPtr GetHandleFromSerialPort(SerialPort sp)
{
Type t = typeof(SerialPort);
BindingFlags bf = BindingFlags.Instance | BindingFlags.NonPublic;
FieldInfo fi = t.GetField("internalSerialStream", bf);
object ss = fi.GetValue(sp);
Type t2 = fi.FieldType;
FieldInfo fi2 = t2.GetField("_handle", bf);
SafeFileHandle _handle = (SafeFileHandle)fi2.GetValue(ss);
Type t3 = typeof(SafeFileHandle);
FieldInfo fi3 = t3.GetField("handle", bf);
IntPtr handle = (IntPtr)fi3.GetValue(_handle);
return handle;
}
public void TurnOnImagerEventListener()
{
devicePort.DataReceived += new SerialDataReceivedEventHandler(devicePort_DataReceived);
}
void devicePort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
System.Threading.Thread.Sleep(100);
SerialPort imager = sender as SerialPort;
byte[] buffer = new byte[imager.BytesToRead];
imager.Read(buffer, 0, imager.BytesToRead);
var scannedText = System.Text.Encoding.ASCII.GetString(buffer).Trim();
SendBarcodeEvent(scannedText);
TurnImagerOff();
Console.WriteLine(scannedText);
}
and to call it is same thing
im = new Imager(comportBox.Text);
im.OpenDevice();
im.TurnOnImagerEventListener();
im.BarcodeScanned += new DataAvailableHandler(DeviceInformationReceived);
Well it turns out that LightStriker helped me see past this fog that was blinding me yesterday. I still don't have the vb.net version working, but what it ended up being was that the IntPtr used in my C# program was not being retained when a seperate thread (IE the dataevent) called it. When I stepped through the data event portion it didn't fail until i called the TurnImagerOff() portion. It was a easy fix in that all i had to do was change both my serial port and my IntPtr into static Members. I tried that in the VB.net code...but evidently I'm not smart enough to figure that out. Oh well today is another day, and atleast 50% of my code works.
So for those of you who have a null reference error and can't find it any where. And the Stack Trace doesn't give you a line number, check anything that is running on another thread that is making a call to any members that are pointers. (Or reflected as a pointer). Check data events, Thread Pools, Background workers, Timers, delegates, etc. I hope that my follies will help someone else.
I have a tricky bug I can't find. I'm doing late-binding on from C# to a native DLL I wrote.
The late-binding seem to work fine. The problems started after I added the callbacks.
The callbacks are defined as so (in c)(On a global scale in the DLL):
typedef void (*FinishedDelegate) (ProcessResult a_bResult);
typedef void (*DownloadStatusUpdateDelegate) (int a_iParametersDownloaded, int a_iTotalParameters);
typedef void (*DownloadFinishedDelegate) (char* a_sConfiguration_values, ProcessResult a_bResult);
DownloadStatusUpdateDelegate pfDownloadStatusUpdateDelegate = NULL;
DownloadFinishedDelegate pfDownloadFinishedDelegate = NULL;
This function is exported:
PLUGIN_API BOOL DownloadConfigration(DownloadStatusUpdateDelegate a_pfStatusDelegate, DownloadFinishedDelegate a_pfFinishedDelegate);
And this is the native function implementation:
DWORD WINAPI DownloadThreadFunc(void* a_pParam)
{
while (g_iParameterDownloaded < PARAMETER_COUNT)
{
if (IsEventSignaled(g_hAbortEvent))
{
CallDownloadFinished(PROCESS_ABORT);
return 0;
}
Sleep(STATUS_DELAY);
CallDownloadStatusUpdate();
g_iParameterDownloaded += STATUS_PARAMS_JUMP;
}
CallDownloadFinished(PROCESS_SUCCESS);
return 0;
}
PLUGIN_API BOOL DownloadConfigration(DownloadStatusUpdateDelegate a_pfStatusDelegate, DownloadFinishedDelegate a_pfFinishedDelegate)
{
if (IsEventSignaled(g_hInProcessEvent))
return false;
pfDownloadStatusUpdateDelegate = a_pfStatusDelegate;
pfDownloadFinishedDelegate = a_pfFinishedDelegate;
g_iParameterDownloaded = 0;
DWORD l_dwResult = WaitForSingleObject(g_hThreadsStructGuardian, INFINITE);
if (l_dwResult == WAIT_OBJECT_0)
{
g_ahThreads[PLUGIN_THREAD_DOWNLOAD] = CreateThread(NULL, 0, DownloadThreadFunc, 0, 0, NULL);
ReleaseMutex(g_hThreadsStructGuardian);
return true;
}
return false;
}
On the managed side, the function is called here:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void DownloadStatusUpdateDelegate(int a_iParametersDownloaded, int a_iTotalParameters);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void DownloadFinishedDelegate_Native(StringBuilder a_sConfigurationValues, EPluginProcessResult a_eResult);
private void OnDownloadStatusUpdate(int a_iParametersDownloaded, int a_iTotalParameters)
{
if (DownloadStatusUpdate != null)
{
DownloadStatusUpdate(a_iParametersDownloaded, a_iTotalParameters);
}
}
private void OnDownloadFinished(StringBuilder a_sConfigurationValues, EPluginProcessResult a_eResult)
{
if (DownloadFinished != null)
{
DownloadFinished(a_sConfigurationValues.ToString(), a_eResult);
}
}
public bool DownloadConfiguration()
{
bool l_bResult = DLLDownloadConfigration(OnDownloadStatusUpdate, OnDownloadFinished);
return l_bResult;
}
The weird thing is - It works for a while. I get a "Privileged Instruction" exception after some time, but as I lower STATUS_DELAY, it happens less. The exception shows up at the IsEventSignaled function - But there's simply nothing there.
The download thread syncs to the c# GUI thread to update the GUI.
I've been on this problem for way too much time. It looks like a classic calling conventions problem, but I verified it thoroughly!
Any ideas?
bool l_bResult = DLLDownloadConfigration(OnDownloadStatusUpdate, OnDownloadFinished);
The code isn't very clear, but this is the likely trouble spot. This creates two delegate objects, the callback bombs after the garbage collector runs and deletes the objects. It cannot track managed object references into unmanaged code. You'll need to create the delegates explicitly and store them in a class member so the garbage collector always sees at least one reference.
Have you tried using a lambda? As in:
bool l_bResult = DLLDownloadConfigration((downloaded, totalParams) => OnDownloadStatusUpdate(downloaded, totalParams), (values, result) => OnDownloadFinished(values, result));
My theory on this is that it is failing because your OnDownloadStatusUpdate and OnDownloadFinished methods aren't static. The underlying IL expects the 'this' object as the first invisible arg, but the C-method is not passing it when calling the callback.
EDIT: I think the answerer above me is correct, but can anyone shed some light on how the marshaller actually handles this?
What's a callback and how is it implemented in C#?
I just met you,
And this is crazy,
But here's my number (delegate),
So if something happens (event),
Call me, maybe (callback)?
In computer programming, a callback is executable code that is passed as an argument to other code.
—Wikipedia: Callback (computer science)
C# has delegates for that purpose. They are heavily used with events, as an event can automatically invoke a number of attached delegates (event handlers).
A callback is a function that will be called when a process is done executing a specific task.
The usage of a callback is usually in asynchronous logic.
To create a callback in C#, you need to store a function address inside a variable. This is achieved using a delegate or the new lambda semantic Func or Action.
public delegate void WorkCompletedCallBack(string result);
public void DoWork(WorkCompletedCallBack callback)
{
callback("Hello world");
}
public void Test()
{
WorkCompletedCallBack callback = TestCallBack; // Notice that I am referencing a method without its parameter
DoWork(callback);
}
public void TestCallBack(string result)
{
Console.WriteLine(result);
}
In today C#, this could be done using lambda like:
public void DoWork(Action<string> callback)
{
callback("Hello world");
}
public void Test()
{
DoWork((result) => Console.WriteLine(result));
DoWork(Console.WriteLine); // This also works
}
Definition
A callback is executable code that
is passed as an argument to other code.
Implementation
// Parent can Read
public class Parent
{
public string Read(){ /*reads here*/ };
}
// Child need Info
public class Child
{
private string information;
// declare a Delegate
delegate string GetInfo();
// use an instance of the declared Delegate
public GetInfo GetMeInformation;
public void ObtainInfo()
{
// Child will use the Parent capabilities via the Delegate
information = GetMeInformation();
}
}
Usage
Parent Peter = new Parent();
Child Johny = new Child();
// Tell Johny from where to obtain info
Johny.GetMeInformation = Peter.Read;
Johny.ObtainInfo(); // here Johny 'asks' Peter to read
Links
more details for C#.
A callback is a function pointer that you pass in to another function. The function you are calling will 'callback' (execute) the other function when it has completed.
Check out this link.
If you referring to ASP.Net callbacks:
In the default model for ASP.NET Web
pages, the user interacts with a page
and clicks a button or performs some
other action that results in a
postback. The page and its controls
are re-created, the page code runs on
the server, and a new version of the
page is rendered to the browser.
However, in some situations, it is
useful to run server code from the
client without performing a postback.
If the client script in the page is
maintaining some state information
(for example, local variable values),
posting the page and getting a new
copy of it destroys that state.
Additionally, page postbacks introduce
processing overhead that can decrease
performance and force the user to wait
for the page to be processed and
re-created.
To avoid losing client state and not
incur the processing overhead of a
server roundtrip, you can code an
ASP.NET Web page so that it can
perform client callbacks. In a client
callback, a client-script function
sends a request to an ASP.NET Web
page. The Web page runs a modified
version of its normal life cycle. The
page is initiated and its controls and
other members are created, and then a
specially marked method is invoked.
The method performs the processing
that you have coded and then returns a
value to the browser that can be read
by another client script function.
Throughout this process, the page is
live in the browser.
Source: http://msdn.microsoft.com/en-us/library/ms178208.aspx
If you are referring to callbacks in code:
Callbacks are often delegates to methods that are called when the specific operation has completed or performs a sub-action. You'll often find them in asynchronous operations. It is a programming principle that you can find in almost every coding language.
More info here: http://msdn.microsoft.com/en-us/library/ms173172.aspx
Dedication to LightStriker:
Sample Code:
class CallBackExample
{
public delegate void MyNumber();
public static void CallMeBack()
{
Console.WriteLine("He/She is calling you. Pick your phone!:)");
Console.Read();
}
public static void MetYourCrush(MyNumber number)
{
int j;
Console.WriteLine("is she/he interested 0/1?:");
var i = Console.ReadLine();
if (int.TryParse(i, out j))
{
var interested = (j == 0) ? false : true;
if (interested)//event
{
//call his/her number
number();
}
else
{
Console.WriteLine("Nothing happened! :(");
Console.Read();
}
}
}
static void Main(string[] args)
{
MyNumber number = Program.CallMeBack;
Console.WriteLine("You have just met your crush and given your number");
MetYourCrush(number);
Console.Read();
Console.Read();
}
}
Code Explanation:
I created the code to implement the funny explanation provided by LightStriker in the above one of the replies. We are passing delegate (number) to a method (MetYourCrush). If the Interested (event) occurs in the method (MetYourCrush) then it will call the delegate (number) which was holding the reference of CallMeBack method. So, the CallMeBack method will be called. Basically, we are passing delegate to call the callback method.
Please let me know if you have any questions.
Probably not the dictionary definition, but a callback usually refers to a function, which is external to a particular object, being stored and then called upon a specific event.
An example might be when a UI button is created, it stores a reference to a function which performs an action. The action is handled by a different part of the code but when the button is pressed, the callback is called and this invokes the action to perform.
C#, rather than use the term 'callback' uses 'events' and 'delegates' and you can find out more about delegates here.
callback work steps:
1) we have to implement ICallbackEventHandler Interface
2) Register the client script :
String cbReference = Page.ClientScript.GetCallbackEventReference(this, "arg", "ReceiveServerData", "context");
String callbackScript = "function UseCallBack(arg, context)" + "{ " + cbReference + ";}";
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "UseCallBack", callbackScript, true);
1) from UI call Onclient click call javascript function for EX:- builpopup(p1,p2,p3...)
var finalfield= p1,p2,p3;
UseCallBack(finalfield, ""); data from the client passed to server side by using UseCallBack
2) public void RaiseCallbackEvent(string eventArgument) In eventArgument we get the passed data
//do some server side operation and passed to "callbackResult"
3) GetCallbackResult() // using this method data will be passed to client(ReceiveServerData() function) side
callbackResult
4) Get the data at client side:
ReceiveServerData(text) , in text server response , we wil get.
A callback is a function passed as an argument to another function. This technique allows a function to invoke the parameter function argument and even to pass a value back to the caller. A callback function can be designed to run before/after the function has finished and can pass a value.
It is a kind of construct where you call a long running function and ask him to call you back once it has finished with can return a parameter result to the caller.
It's like someone calls you in the middle of your work asking for status and you say "you know what give me 5 min and i will call you back" and at the end you call him to update. If you are a function the caller just added and passed another function that you invoked at the end. This can simpley be written in C# as:
public void VinodSrivastav(Action statusUpdate){
//i am still here working..working
//i have finished, calling you
statusUpdate();
}
//invokes
stackoverflow.VinodSrivastav((cam) => {
Console.Write("Is it finished");
});
The one simple example is the iterator function where the return will be multiple times, one can argue that we have yield for it:
public void IntreationLoop(int min, int max,Action<int> Callback)
{
for(int i = min;i<= max;i++)
Callback(i);
}
//call
IntreationLoop(5,50,(x) => { Console.Write(x); }); //will print 5-50 numbers
In the code above the function return type is void but it has an Action<int> callback which is called and sends each item from the loop to the caller.
The same thing can be done with if..else or try..catch block as:
public void TryCatch(Action tryFor,Action catchIt)
{
try{
tryFor();
}
catch(Exception ex)
{
Console.WriteLine($"[{ex.HResult}] {ex.Message}");
catchIt();
}
}
And call it as:
TryCatch(()=>{
int r = 44;
Console.WriteLine("Throwing Exception");
throw new Exception("something is wrong here");
}, ()=>{
Console.WriteLine("It was a mistake, will not try again");
});
In 2022 we have Func & Action doing the same, please see the demo code below which shows how this can be be used:
void Main()
{
var demo = new CallbackDemo();
demo.DoWork(()=> { Console.WriteLine("I have finished the work"); });
demo.DoWork((r)=> { Console.WriteLine($"I have finished the work here is the result {r}"); });
demo.DoWork(()=> { Console.WriteLine($"This is passed with func"); return 5;});
demo.DoWork((f)=> { Console.WriteLine($"This is passed with func and result is {f}"); return 10;});
}
// Define other methods and classes here
public class CallbackDemo
{
public void DoWork(Action actionNoParameter)
{
int a = 5;
int b = 10;
//i will do th maths and call you back
int result = a + b;
//callback
actionNoParameter(); //execute
Console.WriteLine($"[The Actual Result is {result}]");
}
public void DoWork(Action<int> actionWithParameter)
{
int a = 5;
int b = 10;
//i will do th maths and call you back
int result = a + b;
//callback
actionWithParameter(result); //execute
Console.WriteLine($"[The Actual Result is {result}]");
}
public void DoWork(Func<int> funcWithReturn)
{
int a = 5;
int b = 10;
//i will do th maths and call you back
int result = a + b;
//callback
int c = funcWithReturn(); //execute
result += c;
Console.WriteLine($"[The Actual Result is {result}]");
}
public void DoWork(Func<int,int> funcWithParameter)
{
int a = 5;
int b = 10;
//i will do th maths and call you back
int result = a + b;
//callback
result += funcWithParameter(result); //execute
Console.WriteLine($"[The Actual Result is {result}]");
}
}
Due to a limitation in the .NET EventLog class, I have some code using PInvoke that logs to the Application log. The code works without a problem.
But now, I'd like to log to a custom event log. So, I tried changing the 2nd parameter of the RegisterEventSource to "companyX" (my custom log). It correctly wrote to "companyX" (instead of the Application log), but it also set the Source field (of the individual log entry) to "companyX," which is not what I want.
So how do I modify the code to:
Use the new, custom event log ("companyX"), but also
Use the correct Source value ("MyApp")
Currently, it either correctly writes to the Application log (with the correct Source value of "MyApp"), or it writes to the custom ("companyX") event log, and uses the incorrect Source value (rather than "MyApp", it sets the Source value to "companyX", the name of the custom log).
EDIT: Note that the "companyX" log has already been created (in WIX installer code).
Here's my code:
private void WriteEntryToLog(string msg, LogEventType entryType)
{
// ApplicationName = "MyApp"
// The code as-is is writing to the Application log. Changing the 2nd param of
// the function below to "companyX" allows me to write to my "companyX" event log,
// but also changes the Source value of each entry append to that log to "companyX" rather than "MyApp"
IntPtr eventSrcHandle = NativeMethods.RegisterEventSource(null, Resources.ApplicationName);
try
{
uint tokenInfoSize = 0;
IntPtr userTokenPtr = WindowsIdentity.GetCurrent().Token;
const UInt16 typeError = 1, typeWarning = 2, typeInformation = 4;
//using this first call, get the length required to hold the token information in the tokenInfoSize parameter
bool bresult = NativeMethods.GetTokenInformation(userTokenPtr, NativeMethods.TOKEN_INFORMATION_CLASS.TokenUser, IntPtr.Zero, tokenInfoSize, out tokenInfoSize);
if (bresult) throw new Win32Exception(Marshal.GetLastWin32Error());
IntPtr userTokenInfo = Marshal.AllocHGlobal((int)tokenInfoSize);
try
{
//get the user token now with the pointer allocated to the right size
bresult = NativeMethods.GetTokenInformation(userTokenPtr, NativeMethods.TOKEN_INFORMATION_CLASS.TokenUser, userTokenInfo, tokenInfoSize, out tokenInfoSize);
if (!bresult) throw new Win32Exception(Marshal.GetLastWin32Error());
UInt16 type = typeError;
switch (entryType)
{
case LogEventType.Error:
type = typeError;
break;
case LogEventType.Warning:
type = typeWarning;
break;
case LogEventType.Information:
type = typeInformation;
break;
default:
type = typeInformation;
break;
}
NativeMethods.TOKEN_USER tokUser = (NativeMethods.TOKEN_USER)Marshal.PtrToStructure(userTokenInfo, typeof(NativeMethods.TOKEN_USER));
string[] message = new string[1];
message[0] = msg;
bresult = NativeMethods.ReportEvent(eventSrcHandle, type, 0, 0, tokUser.User.Sid, 1, 0, message, new byte());
if (!bresult) throw new Win32Exception(Marshal.GetLastWin32Error());
}
finally
{
Marshal.FreeHGlobal(userTokenInfo);
}
}
finally
{
NativeMethods.DeregisterEventSource(eventSrcHandle);
}
}
Oh, and this is not a repeat of the question here:
Custom value for the Event Log source property for ASP.NET errors
since I have to use PInvoke for this. =)
You have to create a source called MyApp and map it to your log "CompanyX".
This article goes into detail for creating an Event Source w/ .Net Framework BCL.
http://msdn.microsoft.com/en-us/library/5zbwd3s3.aspx
This change requires update access to registry.