简体   繁体   中英

Access violation when calling external DLL function (QPDF library) from C# program

Build environment: Visual Studio 2019, Windows Forms Application, .net 4.7.2

I am attempting to use the QPDF .dll library to read, encrypt, and output a PDF file. See here for the DLL header file listing all exposed functions as declarations.

Notes:

  • QPDF_BOOL is a typedef for 'int'

    qpdf_r3_print_e is an integer enum so I considered it to be 'int' also.

I can successfully initialize the QPDF library, read the file, and output it to a new file by calling the requisite functions, but when I add a call to the qpdf_set_r6_encryption_parameters2() function after initializing and successfully reading the file, it throws an access violation. This is probably because the parameter types are incorrect, but I have perused the QPDF code to the best of my ability to use the correct types.

Here is the DllImport in my C# code: (I followed this advice for all the DllImport lines)

[DllImport("qpdf28.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        static extern void qpdf_set_r6_encryption_parameters2(
            IntPtr qpdf, 
            [MarshalAs(UnmanagedType.LPStr)] string user_password,
            [MarshalAs(UnmanagedType.LPStr)] string owner_password,
            int allow_accessibility,
            int allow_extract,
            int allow_assemble,
            int allow_annotate_and_form,
            int allow_form_filling,
            int allow_modify_other,
            int print,
            int encrypt_metadata

            );

Here is the function call later in the C# code:

qpdf_set_r6_encryption_parameters2(qpdf,
                    txtPassword.Text,
                    txtPassword.Text,
                    0, 0, 0, 0, 0, 0,
                     0,
                     0
                    );

I'm fairly certain the parameter data types are wrong somewhere, but I'm not seeing it. Thanks for any pointers!

UPDATE: Here is the full code which I'm attempting to run, in case this is helpful. Note that the code works perfectly if I disable the Encryption line: it writes a new PDF file containing the same information as the input PDF.

namespace testqpdf
{
    public partial class Form1 : Form
    {
        enum qpdf_r3_print_e
        {
            qpdf_r3p_full = 0,
            qpdf_r3p_low = 1,
            qpdf_r3p_none = 2
        }

        [DllImport("qpdf28.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        static extern IntPtr qpdf_init();

        [DllImport("qpdf28.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        static extern void qpdf_cleanup(ref IntPtr qpdfData);

        [DllImport("qpdf28.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        static extern int qpdf_read(IntPtr qpdfdata, [MarshalAs(UnmanagedType.LPStr)] string fileName, IntPtr password);

        [DllImport("qpdf28.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        static extern void qpdf_set_object_stream_mode(IntPtr qpdf, int mode);

        [DllImport("qpdf28.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        static extern void qpdf_set_qdf_mode(IntPtr qpdf, int value);

        [DllImport("qpdf28.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        static extern int qpdf_init_write(IntPtr qpdf, [MarshalAs(UnmanagedType.LPStr)] string fileName);

        [DllImport("qpdf28.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        static extern int qpdf_write(IntPtr qpdf);

        [DllImport("qpdf28.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        static extern void qpdf_set_r6_encryption_parameters2(
            IntPtr qpdf, 
            [MarshalAs(UnmanagedType.LPStr)] string user_password,
            [MarshalAs(UnmanagedType.LPStr)] string owner_password,
            int allow_accessibility,
            int allow_extract,
            int allow_assemble,
            int allow_annotate_and_form,
            int allow_form_filling,
            int allow_modify_other,
            int print,
            int encrypt_metadata

            );




        public Form1()
        {
            InitializeComponent();
        }

        private void btnGo_Click(object sender, EventArgs e)
        {
            IntPtr qpdf = qpdf_init();

            int result = qpdf_read(qpdf, txtInput.Text, /* password */ IntPtr.Zero);

            Console.WriteLine("Read PDF file " + txtInput.Text + ", result = " + result.ToString());

            if (chkEncrypt.Checked)
            {
                qpdf_set_r6_encryption_parameters2(qpdf,
                    null,
                    null,
                    0, 0, 0, 0, 0, 0,
                     0,
                     0

                    );
            }


            result = qpdf_init_write(qpdf, txtOutput.Text);

            Console.WriteLine("Write PDF file " + txtOutput.Text + ", result = " + result.ToString());

            result = qpdf_write(qpdf);

            qpdf_cleanup(ref qpdf);
        }
    }
}

Try this:

[DllImport("qpdf29.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr qpdf_init();

[DllImport("qpdf29.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
static extern void qpdf_cleanup(ref IntPtr qpdfData);

[DllImport("qpdf29.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
static extern int qpdf_read(IntPtr qpdfdata, [MarshalAs(UnmanagedType.LPStr)] string fileName, IntPtr password);

[DllImport("qpdf29.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
static extern void qpdf_set_qdf_mode(IntPtr qpdf, int value);

[DllImport("qpdf29.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
static extern int qpdf_init_write(IntPtr qpdf, [MarshalAs(UnmanagedType.LPStr)] string fileName);

[DllImport("qpdf29.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
static extern int qpdf_write(IntPtr qpdf);


IntPtr pdfData = qpdf_init();
qpdf_read(pdfData, @"C:\source file.pdf", IntPtr.Zero);
qpdf_init_write(pdfData, @"C:destination file.pdf");
qpdf_set_qdf_mode(pdfData, 1);
qpdf_write(pdfData);
qpdf_cleanup(ref pdfData);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM