Using WinFax.dll from C# .NET (NOT using FaxCom)

Discussion in 'Microsoft Windows 2000 Fax' started by Robert Freas, Sep 26, 2003.

  1. Robert Freas

    Robert Freas Guest

    Hi,

    I have declared a bunch of WinFax.DLL exports as static externs in
    ..NET using the DllImportAttribute(). I am basing my code off the
    Simple.c found in the Platform SDK in the Samples\netds\fax\SampleSend
    directory. All the defined externs/structures/code is at the bottom
    of this message.

    As you can see below, the SendFax() method is based on the
    SimpleSend.c sample in the Platform SDK. Everything works up until
    the FaxSendDocument() API call. GetLastWin32Error returns 87--Invalid
    parameter. The documentation suggests that I am missing a required
    parameter--but, there are only 3:

    jobParam.RecipientNumber = "5551212";
    jobParam.ScheduleAction = (int) FAX_ENUM_JOB_SEND_ATTRIBUTES.JSA_NOW;
    jobParam.CallHandle = new IntPtr(0);

    ....and I've set them all; NOTE: the documentation says that CALLHANDLE
    must be NULL--so I set it to a "null" IntPtr.

    Anyone have any ideas what is going on?

    BTW, using the legacy WinFax.dll APIs are a requirement for me as I
    need to leverage IOCompletionPorts in order to make sending a Fax a
    synchronous operation; therefore, I cannot use the FaxCom COM objects.

    Thanks for any help!

    Rob

    --

    public abstract class Win32
    {
    public static readonly int INFINITE = -1;
    public static readonly int INVALID_HANDLE_VALUE = -1;

    [DllImport("kernel32")]
    public static extern int CreateIoCompletionPort(int FileHandle, int
    ExistingCompletionPort, int CompletionKey, int
    NumberOfConcurrentThreads);

    [DllImport("kernel32")]
    public static extern int GetQueuedCompletionStatus(int
    CompletionPort, ref int

    lpNumberOfBytesTransferred, ref int lpCompletionKey, IntPtr
    lpOverlapped, int dwMilliseconds);

    [DllImport("kernel32")]
    public static extern int CloseHandle(int hObject);
    }

    public abstract class WinFax
    {
    #region Enumerations

    public enum FAX_PORT_OPEN_TYPE
    {
    PORT_OPEN_QUERY = 1,
    PORT_OPEN_MODIFY = 2
    }

    public enum FAX_ENUM_JOB_SEND_ATTRIBUTES
    {
    JSA_NOW = 0, // Send now
    JSA_SPECIFIC_TIME, // Send at specific time
    JSA_DISCOUNT_PERIOD // Send at server configured
    discount period
    }

    [FlagsAttribute()]
    public enum WinFaxEvent
    {
    FEI_DIALING = 0x00000001,
    FEI_SENDING = 0x00000002,
    FEI_RECEIVING = 0x00000003,
    FEI_COMPLETED = 0x00000004,
    FEI_BUSY = 0x00000005,
    FEI_NO_ANSWER = 0x00000006,
    FEI_BAD_ADDRESS = 0x00000007,
    FEI_NO_DIAL_TONE = 0x00000008,
    FEI_DISCONNECTED = 0x00000009,
    FEI_FATAL_ERROR = 0x0000000a,
    FEI_NOT_FAX_CALL = 0x0000000b,
    FEI_CALL_DELAYED = 0x0000000c,
    FEI_CALL_BLACKLISTED = 0x0000000d,
    FEI_RINGING = 0x0000000e,
    FEI_ABORTING = 0x0000000f,
    FEI_ROUTING = 0x00000010,
    FEI_MODEM_POWERED_ON = 0x00000011,
    FEI_MODEM_POWERED_OFF = 0x00000012,
    FEI_IDLE = 0x00000013,
    FEI_FAXSVC_ENDED = 0x00000014,
    FEI_ANSWERED = 0x00000015,
    FEI_JOB_QUEUED = 0x00000016,
    FEI_DELETED = 0x00000017,
    FEI_INITIALIZING = 0x00000018,
    FEI_LINE_UNAVAILABLE = 0x00000019,
    FEI_HANDLED = 0x0000001a,
    FEI_FAXSVC_STARTED = 0x0000001b
    }
    #endregion

    #region Structs

    [StructLayout(LayoutKind.Sequential)]
    public struct SYSTEMTIME
    {
    public ushort wYear;
    public ushort wMonth;
    public ushort wDayOfWeek;
    public ushort wDay;
    public ushort wHour;
    public ushort wMinute;
    public ushort wSecond;
    public ushort wMilliseconds;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct FAX_DEVICE_STATUS
    {
    public int SizeOfStruct; // size

    of this structure
    public string CallerId; // caller id

    string
    public string Csid; // station

    identifier
    public int CurrentPage; //

    current page
    public int DeviceId; //

    permanent line id
    public string DeviceName; // device name
    public string DocumentName; // document name
    public int JobType; // send

    or receive?
    public string PhoneNumber; // sending phone

    number
    public string RoutingString; // routing

    information
    public string SenderName; // sender name
    public string RecipientName; // recipient

    name
    public int Size; // size

    in bytes of the document
    public FILETIME StartTime; // starting
    time of the fax

    send/receive
    public int Status; //

    current status of the device, see FPS_??? masks
    public string StatusString; // status string

    if the Status field is zero. this may be NULL.
    public FILETIME SubmittedTime; // time the

    document was submitted
    public int TotalPages; // total

    number of pages in this job
    public string Tsid; // transmitting

    station identifier
    public string UserName; // user that

    submitted the active job
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct FAX_COVERPAGE_INFO
    {
    public int SizeOfStruct; // Size of
    this structure
    //
    // general
    //
    public string CoverPageName; // coverpage
    document name
    public bool UseServerCoverPage; // coverpage
    exists on the fax

    server
    //
    // Recipient information
    //
    public string RecName; //
    public string RecFaxNumber; //
    public string RecCompany; //
    public string RecStreetAddress; //
    public string RecCity; //
    public string RecState; //
    public string RecZip; //
    public string RecCountry; //
    public string RecTitle; //
    public string RecDepartment; //
    public string RecOfficeLocation; //
    public string RecHomePhone; //
    public string RecOfficePhone; //
    //
    // Sender information
    //
    public string SdrName; //
    public string SdrFaxNumber; //
    public string SdrCompany; //
    public string SdrAddress; //
    public string SdrTitle; //
    public string SdrDepartment; //
    public string SdrOfficeLocation; //
    public string SdrHomePhone; //
    public string SdrOfficePhone; //
    //
    // Misc information
    //
    public string Note; // public

    string Subject; //
    public SYSTEMTIME TimeSent; // Time the fax
    was

    sent
    public int PageCount; // Number of

    pages
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct FAX_EVENT
    {
    public int SizeOfStruct; // Size of
    this structure
    public FILETIME TimeStamp; // Timestamp
    for when the event

    was generated
    public int DeviceId; // Permanent
    line id
    public int EventId; // Current
    event id
    public int JobId; // Fax Job Id,
    0xffffffff

    indicates inactive job
    }

    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
    public struct FAX_JOB_PARAM
    {
    public int SizeOfStruct; // size

    of this structure
    public string RecipientNumber; // recipient fax

    number
    public string RecipientName; // recipient

    name
    public string Tsid; // transmitter's

    id
    public string SenderName; // sender name
    public string SenderCompany; // sender

    company
    public string SenderDept; // sender

    department
    public string BillingCode; // billing code
    public int ScheduleAction; // when

    to schedule the fax, see JSA defines
    public SYSTEMTIME ScheduleTime; // time to
    send the fax when

    JSA_SPECIFIC_TIME is used (must be local time)
    public int DeliveryReportType; //

    delivery report type, see DRT defines
    public string DeliveryReportAddress; // email address

    for delivery report (ndr or dr) thru MAPI / SMTP
    public string DocumentName; // document name

    (optional)
    public IntPtr CallHandle; // optional call

    handle

    //[MarshalAs(UnmanagedType., SizeConst=3)]
    public IntPtr[] Reserved; // reserved

    for ms use only
    }
    #endregion

    #region Externs

    [DllImport("winfax.dll", SetLastError=true)]
    public static extern int FaxConnectFaxServer(string MachineName,
    [Out] out int FaxHandle);

    [DllImport("winfax.dll", SetLastError=true)]
    public static extern bool FaxInitializeEventQueue(int FaxHandle, int
    CompletionPort, int

    CompletionKey, int hWnd, int MessageStart);

    [DllImport("winfax.dll", SetLastError=true)]
    public static extern void FaxFreeBuffer(IntPtr Buffer);

    [DllImport("winfax.dll", SetLastError=true)]
    public static extern bool FaxClose(int FaxHandle);

    [DllImport("winfax.dll", SetLastError=true)]
    public static extern bool FaxCompleteJobParams([In, Out] ref
    FAX_JOB_PARAM JobParams, [In,

    Out] ref FAX_COVERPAGE_INFO CoverpageInfo);

    [DllImport("winfax.dll", SetLastError=true)]
    public static extern bool FaxSendDocument(int FaxHandle, string
    FileName, [In] ref

    FAX_JOB_PARAM JobParams, [In] ref FAX_COVERPAGE_INFO CoverpageInfo,
    [Out] out int FaxJobId);

    [DllImport("winfax.dll", SetLastError=true)]
    public static extern bool FaxSendDocument(int FaxHandle, string
    FileName, [In] ref

    FAX_JOB_PARAM JobParams, [In] ref IntPtr CoverpageInfo, [Out] out int
    FaxJobId);

    [DllImport("winfax.dll", SetLastError=true)]
    public static extern bool FaxOpenPort(int FaxHandle, int DeviceId,
    int Flags, [Out] int

    FaxPortHandle);

    [DllImport("winfax.dll", SetLastError=true)]
    public static extern bool FaxGetDeviceStatus(int FaxPortHandle,
    [Out] out FAX_DEVICE_STATUS

    DeviceStatus);

    #endregion

    public static bool SendFax(string faxDocument)
    {
    bool bTerminate = false;
    int hCompletionPort = 0;
    int completionKey = 0;
    int bytesSent = 0;
    int hFax = 0;
    //IntPtr hFax = new IntPtr(0);
    //IntPtr hPort = new IntPtr(0);
    int hPort = 0;
    int faxJobID = 0;
    FAX_DEVICE_STATUS deviceStatus;
    FAX_EVENT faxEvent = new FAX_EVENT();
    FAX_JOB_PARAM jobParam = new FAX_JOB_PARAM();
    FAX_COVERPAGE_INFO coverPageInfo = new FAX_COVERPAGE_INFO();

    faxEvent.SizeOfStruct = Marshal.SizeOf(typeof(FAX_EVENT));
    IntPtr pFaxEvent = Marshal.AllocHGlobal(faxEvent.SizeOfStruct);
    Marshal.StructureToPtr(faxEvent, pFaxEvent, true);

    jobParam.SizeOfStruct = Marshal.SizeOf(typeof(FAX_JOB_PARAM));
    IntPtr pJobParam = Marshal.AllocHGlobal(jobParam.SizeOfStruct);
    Marshal.StructureToPtr(jobParam, pJobParam, true);

    coverPageInfo.SizeOfStruct =
    Marshal.SizeOf(typeof(FAX_COVERPAGE_INFO));
    IntPtr pCoverPageInfo =
    Marshal.AllocHGlobal(coverPageInfo.SizeOfStruct);
    Marshal.StructureToPtr(coverPageInfo, pCoverPageInfo, true);

    // connect to fax service
    if(FaxConnectFaxServer(null, out hFax) == 0)
    {
    Console.WriteLine("GetLastWin32Error: " +

    Marshal.GetLastWin32Error().ToString());

    //_tprintf( TEXT("FaxConnectFaxServer failed, ec =
    %d\n"),GetLastError() );
    return false;
    }

    // create completion port to poll against while waiting for fax
    completion
    hCompletionPort =
    Win32.CreateIoCompletionPort(Win32.INVALID_HANDLE_VALUE, 0, 0, 0);

    if(hCompletionPort == 0)
    {
    Console.WriteLine("GetLastWin32Error: " +

    Marshal.GetLastWin32Error().ToString());

    //_tprintf( TEXT("CreateIoCompletionPort failed, ec = %d\n"),
    GetLastError()

    );
    FaxClose(hFax);
    return false;
    }

    if (!FaxInitializeEventQueue(
    hFax,
    hCompletionPort,
    0,
    0,
    0))
    {
    Console.WriteLine("GetLastWin32Error: " +

    Marshal.GetLastWin32Error().ToString());

    //_tprintf( TEXT("FaxInitializeEventQueue failed, ec = %d\n"),

    GetLastError() );
    FaxClose(hFax);
    return false;
    }

    FaxCompleteJobParams(ref jobParam, ref coverPageInfo);

    jobParam.RecipientNumber = "5551212";
    jobParam.ScheduleAction = (int)
    FAX_ENUM_JOB_SEND_ATTRIBUTES.JSA_NOW;
    jobParam.CallHandle = new IntPtr(0);

    IntPtr coverPageNull = new IntPtr(0);
    if(!FaxSendDocument(hFax, faxDocument, ref jobParam, ref
    coverPageNull, out

    faxJobID))
    {
    Console.WriteLine("GetLastWin32Error: " +

    Marshal.GetLastWin32Error().ToString());

    //jobParam = (FAX_JOB_PARAM) Marshal.PtrToStructure(pJobParam,

    typeof(FAX_JOB_PARAM));
    //coverPageInfo = (FAX_COVERPAGE_INFO)

    Marshal.PtrToStructure(pCoverPageInfo, typeof(FAX_COVERPAGE_INFO));

    //_tprintf( TEXT("FaxSendDocument failed, ec = %d \n"),
    GetLastError() );

    FaxClose(hFax);
    Win32.CloseHandle(hCompletionPort);
    FaxFreeBuffer(pJobParam);
    FaxFreeBuffer(pCoverPageInfo);
    return false;
    }

    //_tprintf(TEXT("Queued document %s for transmition to %s, JobID =
    %d\n"), Document,

    Number, JobId);

    FaxFreeBuffer(pJobParam);
    FaxFreeBuffer(pCoverPageInfo);

    Marshal.StructureToPtr(faxEvent, pFaxEvent, true);

    while (!bTerminate &&
    (Win32.GetQueuedCompletionStatus(
    hCompletionPort,
    ref bytesSent,
    ref completionKey,
    pFaxEvent,
    Win32.INFINITE) != 0))
    {

    faxEvent = (FAX_EVENT) Marshal.PtrToStructure(pFaxEvent,
    typeof(FAX_EVENT));

    //_tprintf( TEXT("Received event 0x%x\n"),FaxEvent->EventId);

    switch ((WinFaxEvent) faxEvent.EventId)
    {
    case WinFaxEvent.FEI_IDLE:
    case WinFaxEvent.FEI_COMPLETED:
    case WinFaxEvent.FEI_MODEM_POWERED_ON:
    case WinFaxEvent.FEI_MODEM_POWERED_OFF:
    case WinFaxEvent.FEI_FAXSVC_ENDED:
    bTerminate = true;
    break;

    case WinFaxEvent.FEI_JOB_QUEUED:
    //_tprintf( TEXT("JobId 0x%x queued\n"),FaxEvent->JobId );
    break;

    case WinFaxEvent.FEI_DIALING:
    case WinFaxEvent.FEI_SENDING:
    case WinFaxEvent.FEI_RECEIVING:
    case WinFaxEvent.FEI_BUSY:
    case WinFaxEvent.FEI_NO_ANSWER:
    case WinFaxEvent.FEI_BAD_ADDRESS:
    case WinFaxEvent.FEI_NO_DIAL_TONE:
    case WinFaxEvent.FEI_DISCONNECTED:
    case WinFaxEvent.FEI_FATAL_ERROR:
    if (FaxOpenPort(hFax, faxEvent.DeviceId, (int)

    FAX_PORT_OPEN_TYPE.PORT_OPEN_QUERY, hPort) )
    {
    if (FaxGetDeviceStatus(hPort, out deviceStatus) )
    {
    IntPtr pDeviceStatus = new IntPtr();
    deviceStatus.SizeOfStruct =

    Marshal.SizeOf(typeof(FAX_DEVICE_STATUS));
    Marshal.StructureToPtr(deviceStatus,

    pDeviceStatus, true);

    //PrintDeviceStatus(deviceStatus);
    FaxFreeBuffer(pDeviceStatus);
    }
    FaxClose(hPort);
    }
    break;
    }
    }

    FaxClose(hFax);
    Win32.CloseHandle(hCompletionPort);
    return true;
    }

    }
     
    Robert Freas, Sep 26, 2003
    #1
    1. Advertisements

  2. Robert Freas

    saeidziaei

    Joined:
    Jan 23, 2006
    Messages:
    1
    Likes Received:
    0
    Please give out some info about your work. What did you do to manage sending fax from C#?
     
    saeidziaei, Jan 23, 2006
    #2
    1. Advertisements

  3. Robert Freas

    cpgcon

    Joined:
    Dec 6, 2006
    Messages:
    1
    Likes Received:
    0
    Hi,

    I am using the WinFax.Dll for Faxing; If you have the solution please update me.
    I want to send TIFF file through Fax. I am using Faxcomlib.dll but it is not able to send the TIFF file and giving error "Invalid data". I decided to go by your way but the program is not working. Please update me.

    Thanks in advance.
     
    cpgcon, Dec 6, 2006
    #3
  4. Robert Freas

    rednael

    Joined:
    Aug 31, 2008
    Messages:
    1
    Likes Received:
    0
    Using a native DLL (or C++ DLL) in your .Net applications

    Please check out this article:
    http://blog.rednael.com/2008/08/29/MarshallingUsingNativeDLLsInNET.aspx

    It's an in depth article about importing native DLLs into .NET code. It has some C# examples. The article shows which types are interoperable, how to import a DLL, how to pass strings and how to de-reference/unreference pointers.

    It answers most of your questions
     
    rednael, Aug 31, 2008
    #4
    1. Advertisements

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ward Germonpé

    VB, faxcom.dll

    Ward Germonpé, Sep 28, 2003, in forum: Microsoft Windows 2000 Fax
    Replies:
    4
    Views:
    4,115
    Robert Freas
    Nov 26, 2003
  2. =?ISO-8859-1?Q?Mathias_W=FChrmann?=

    Call to FaxConnectFaxServer: Cannot find entrypoint in winfax.dll!

    =?ISO-8859-1?Q?Mathias_W=FChrmann?=, Aug 22, 2004, in forum: Microsoft Windows 2000 Fax
    Replies:
    2
    Views:
    1,430
    =?ISO-8859-1?Q?Mathias_W=FChrmann?=
    Aug 30, 2004
  3. news.microsoft.com

    IRQ_NOT LESS OR EQUAL using Winfax on modem test?

    news.microsoft.com, Oct 7, 2005, in forum: Microsoft Windows 2000 Fax
    Replies:
    1
    Views:
    532
    JR K Yoshikawa
    Oct 11, 2005
  4. terminator393

    Using FaxCom.dll

    terminator393, Apr 7, 2006, in forum: Microsoft Windows 2000 Fax
    Replies:
    0
    Views:
    2,297
    terminator393
    Apr 7, 2006
  5. cdonajkowski

    Faxcom.dll on Win2003

    cdonajkowski, May 31, 2007, in forum: Microsoft Windows 2000 Fax
    Replies:
    0
    Views:
    793
    cdonajkowski
    May 31, 2007
Loading...

Share This Page