I try to use LoadLibraryEx Function to load a xxx.dll. In ASP.NET CORE Web - MVC application. It can return a right value. But in a ASP.NET Web - Web API application. It return 0x00000000.But GetLastError() return 0. Here is my demo code
CODE IN ASP.NET Web - Web API application
[DllImport("kernel32.dll")]
static extern uint GetLastError();
[DllImport("kernel32.dll", EntryPoint = "LoadLibraryEx", SetLastError = true)]
private static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags);
private static uint LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008;
private static void LoadWin32Library(string libPath)
{
IntPtr moduleHandle = LoadLibraryEx(libPath, IntPtr.Zero, LOAD_WITH_ALTERED_SEARCH_PATH);
uint code = GetLastError();
Console.WriteLine(code);
Console.WriteLine(moduleHandle);
if (moduleHandle == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
}
// GET api/values
public IEnumerable<string> Get()
{
String lpFileName = "C:\\Program Files\\dotnet\\shared\\Microsoft.NETCore.App\\2.1.11\\System.dll";
LoadWin32Library(lpFileName);
return new string[] { "value1", "value2" };
}
CODE IN ASP.NET CORE Web - MVC
[DllImport("kernel32.dll")]
static extern uint GetLastError();
[DllImport("kernel32.dll", EntryPoint = "LoadLibraryEx", SetLastError = true)]
private static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags);
private static uint LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008;
private static void LoadWin32Library(string libPath)
{
IntPtr moduleHandle = LoadLibraryEx(libPath, IntPtr.Zero, LOAD_WITH_ALTERED_SEARCH_PATH);
uint code = GetLastError();
Console.WriteLine(code);
Console.WriteLine(moduleHandle);
if (moduleHandle == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
}
public string Index()
{
String lpFileName = "C:\\Program Files\\dotnet\\shared\\Microsoft.NETCore.App\\2.1.11\\System.dll";
LoadWin32Library(lpFileName);
return "This is my default action...";
}
In fact. These two pieces of code are basically the same.But the results are completely different.So. If anybody can help me?
This isn't really an "answer" but it's too involved to be a comment.
You should never need to call LoadLibrary from managed code
There are three ways DLLs can get loaded into managed code:
Your program has a referenced to a managed assembly (in the References section under the project in Solution Explorer)
You call Assembly.Load (or one of the variants) from your code, loading in a managed assembly
You use P/Invoke to load an unmanaged DLL and execute a function within it (like how you are loading kernel32.dll and calling GetLastError or LoadLibraryEx in your code)
And, for completeness (and on the advice of #SeanSkelly), adding a fourth option that does involve LoadLibary(Ex), but with severe restrictions. This is definitely not a recommended option.
Use LoadLibary(Ex), but with the caveat that you have to do much of the work of (and mimic the actions of) the P/Invoke marshaler. You also can't use this with a managed DLL because GetProcAddress will always fail on a managed assembly.
I have a guess as to why you are getting success in one case and a failure in the other. In one case, you are loading in the same System.dll that the framework has already loaded, so it just returns a handle to the loaded DLL. In the other, you are loading a different version of System.dll. The unmanaged loader doesn't understand versioning and strong names the way Assembly.Load does, so it says "hey, I already have a System.dll and it doesn't match up, so I'm failing your request". But, this is just a guess.
But, it doesn't really matter, you don't need to do this.
Related
We are writing a code to do on-demand scan of a file from C# using Windows Defender APIs.
[DllImport(#"C:\Program Files\Windows Defender\MpClient.dll")]
public static extern int WDStatus(out bool pfEnabled);
[DllImport(#"C:\Program Files\Windows Defender\MpClient.dll")]
public static extern int MpManagerOpen(uint dwReserved, out IntPtr phMpHandle);
[DllImport(#"C:\Program Files\Windows Defender\MpClient.dll")]
public static extern int MpScanStart(IntPtr hMpHandle, uint ScanType, uint dwScanOptions, IntPtr pScanResources, IntPtr pCallbackInfo, out IntPtr phScanHandle);
[DllImport(#"C:\Program Files\Windows Defender\MpClient.dll")]
public static extern int MpHandleClose(IntPtr hMpHandle);
private void DoDefenderScan_Click(object sender, EventArgs e)
{
try
{
bool pfEnabled;
int result = WDStatus(out pfEnabled); //Returns the defender status - It's working properly.
ErrorHandler.ThrowOnFailure(result, VSConstants.S_OK);
IntPtr phMpHandle;
uint dwReserved = 0;
IntPtr phScanHandle;
MpManagerOpen(dwReserved, out phMpHandle); //Opens Defender and returns the handle in phMpHandle.
tagMPRESOURCE_INFO mpResourceInfo = new tagMPRESOURCE_INFO();
mpResourceInfo.Path = "eicar.com";
mpResourceInfo.Scheme = "file";
mpResourceInfo.Class = IntPtr.Zero;
tagMPRESOURCE_INFO[] pResourceList = new tagMPRESOURCE_INFO[1];
pResourceList.SetValue(mpResourceInfo, 0);
tagMPSCAN_RESOURCES scanResource = new tagMPSCAN_RESOURCES();
scanResource.dwResourceCount = 1;
scanResource.pResourceList = pResourceList;
IntPtr resourcePointer = StructToPtr(scanResource);
result = MpScanStart(phMpHandle, 3, 0, resourcePointer, IntPtr.Zero, out phScanHandle); **//Getting Access violation exception here**.
MpHandleClose(phMpHandle);
MpHandleClose(phScanHandle);
Marshal.FreeHGlobal(resourcePointer);
}
catch (Exception)
{ }
}
And the structure is defined here.
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct tagMPSCAN_RESOURCES
{
public uint dwResourceCount;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 1)]
public tagMPRESOURCE_INFO[] pResourceList;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct tagMPRESOURCE_INFO
{
[MarshalAs(UnmanagedType.LPWStr)]
public String Scheme;
[MarshalAs(UnmanagedType.LPWStr)]
public String Path;
public IntPtr Class;
}
public class MPRESOURCE_CLASS
{
public uint Value;
}
private static IntPtr StructToPtr(object obj)
{
var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(obj));
Marshal.StructureToPtr(obj, ptr, false);
return ptr;
}
The code is written based on the documentation available at
https://msdn.microsoft.com/en-us/library/vs/alm/dn920144(v=vs.85).aspx
We are getting this exception
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
at
result = MpScanStart(phMpHandle, 3, 0, resourcePointer, IntPtr.Zero, out phScanHandle); **//Getting Access violation exception here**.
What could be the problem? Is the format of struct is correct?
P.S - No information about MPRESOURCE_CLASS is available in msdn.
I'm not sure, whether this line of code is correct.
mpResourceInfo.Class = IntPtr.Zero;
Update:
Quick scan is working fine with this code:
result = MpScanStart(phMpHandle, 1, 0, IntPtr.Zero, IntPtr.Zero, out phScanHandle);
Defender logs in the event viewer [ Applications and Services Logs-Microsoft-Windows-Windows Defender/Operational ] as
Windows Defender scan has started.
Scan ID:{CDC2AC0D-7648-4313-851C-4D8B7B5EB5CD}
Scan Type:AntiSpyware
Scan Parameters:Quick Scan
I couldn't identify the problem here. So I ended up with Antimalware Scan Interface (AMSI) available starting from Windows 10.
I have written a sample C# code here.
One thing I found is AMSI requires Windows defender/any antivirus to be turned on to verify the file passed to API. But triggering a scan through MpClient.dllwill trigger a defender scan even if defender is turned off.
Also ensure your project targets x64 platform.
public enum AMSI_RESULT
{
AMSI_RESULT_CLEAN = 0,
AMSI_RESULT_NOT_DETECTED = 1,
AMSI_RESULT_DETECTED = 32768
}
[DllImport("Amsi.dll", EntryPoint = "AmsiInitialize", CallingConvention = CallingConvention.StdCall)]
public static extern int AmsiInitialize([MarshalAs(UnmanagedType.LPWStr)]string appName, out IntPtr amsiContext);
[DllImport("Amsi.dll", EntryPoint = "AmsiUninitialize", CallingConvention = CallingConvention.StdCall)]
public static extern void AmsiUninitialize(IntPtr amsiContext);
[DllImport("Amsi.dll", EntryPoint = "AmsiOpenSession", CallingConvention = CallingConvention.StdCall)]
public static extern int AmsiOpenSession(IntPtr amsiContext, out IntPtr session);
[DllImport("Amsi.dll", EntryPoint = "AmsiCloseSession", CallingConvention = CallingConvention.StdCall)]
public static extern void AmsiCloseSession(IntPtr amsiContext, IntPtr session);
[DllImport("Amsi.dll", EntryPoint = "AmsiScanString", CallingConvention = CallingConvention.StdCall)]
public static extern int AmsiScanString(IntPtr amsiContext, [InAttribute()] [MarshalAsAttribute(UnmanagedType.LPWStr)]string #string, [InAttribute()] [MarshalAsAttribute(UnmanagedType.LPWStr)]string contentName, IntPtr session, out AMSI_RESULT result);
[DllImport("Amsi.dll", EntryPoint = "AmsiScanBuffer", CallingConvention = CallingConvention.StdCall)]
public static extern int AmsiScanBuffer(IntPtr amsiContext, [In] [MarshalAs(UnmanagedType.LPArray)] byte[] buffer, uint length, [In()] [MarshalAs(UnmanagedType.LPWStr)] string contentName, IntPtr session, out AMSI_RESULT result);
//This method apparently exists on MSDN but not in AMSI.dll (version 4.9.10586.0)
[DllImport("Amsi.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern bool AmsiResultIsMalware(AMSI_RESULT result);
private void CallAntimalwareScanInterface()
{
IntPtr amsiContext;
IntPtr session;
AMSI_RESULT result = 0;
int returnValue;
returnValue = AmsiInitialize("VirusScanAPI", out amsiContext); //appName is the name of the application consuming the Amsi.dll. Here my project name is VirusScanAPI.
returnValue = AmsiOpenSession(amsiContext, out session);
returnValue = AmsiScanString(amsiContext, #"X5O!P%#AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*", "EICAR", session, out result); //I've used EICAR test string.
AmsiCloseSession(amsiContext, session);
AmsiUninitialize(amsiContext);
}
I've been searching about problem and I've read this as one of the possible causes:
"You often see differences between debug and release builds because
debug builds contain extra metadata to assist in debugging."
here: https://social.msdn.microsoft.com/Forums/vstudio/en-US/4f48c152-68cd-45ec-a11e-baa7de7f79c3/attempted-to-read-or-write-protected-memory?forum=csharpgeneral
Also you should check this answer to "Is it possible to catch an access violation exception in .NET?" and the further details that are explained in the article Handling Corrupted State Exceptions in MSDN magazine
...
So, according to that answers and articles I'd try:
1st Double check signatures and COM interop thunks for all unmanaged code to verify that they're correct.
2nd Set Visual Studio Debugger to bypass this exception:
Tools menu ->Options -> Debugging -> General -> Uncheck this option "Suppress JIT optimization on module load"
3rd Try-Catch the exception
(note: if you are using .Net 4 then in App.config, within the tag modify runtime to include legacyCorruptedStateExceptionsPolicy enabled="true"like:
<runtime>
<legacyCorruptedStateExceptionsPolicy enabled="true"/>
</runtime>
)
In addition, here, I've found that some .net framework versions (latest comment point to 4.6.1 in one of the answer's comments) has a bug related with this exception and the solution, in the past, has been upgrading the framework.
Also, in the one of that answers I've read:
Hi There are two possible reasons.
1.We have un-managed code and we are calling it from managed code. that is preventing to run this code. try running these commands and
restart your pc
cmd: netsh winsock reset
open cmd.exe and run command "netsh winsock reset catalog"
2.Anti-virus is considering un-managed code as harmful and restricting to run this code disable anti-virus and then check
I'd like to know if some of these approaches helps you to solve your issue.
I really hope this helps.
KR,
Juan
You may use Antimalware Scan Interface to check file for malware.
The Antimalware Scan Interface (AMSI) is a generic interface standard that allows applications and services to integrate with any antimalware product present on a machine. It provides enhanced malware protection for users and their data, applications, and workloads.
It's available starting from Windows 10.
Windows Defender comes with CLI tool 'MpCmdRun' - it's not a full-sized antivirus app, but an API interface to the actual Windows Defender that's always (?) running in background.
Saving to a temporary file via Path.GetTempFileName() and then running a scan like this
MpCmdRun.exe -Scan -ScanType 3 -File "c:\path\to\temp\file" -DisableRemediation
works fine even in an ASP.NET (Core) app, that runs under app-pool identity
I've actually written a small (40 lines of code) C# helper that does everything for you (saves temp file, runs a scan, cleans up)
https://github.com/jitbit/WinDefender/blob/main/WinDefender.cs
I am finding myself out of my depth when trying to programatically add a Windows 8 'Metro' application to the Loopback exceptions list using the code provided by Microsoft below:
// Call this API to enumerate all of the AppContainers on the system
[DllImport("FirewallAPI.dll")]
internal static extern uint NetworkIsolationEnumAppContainers(out uint pdwCntPublicACs, out IntPtr ppACs);
// Call this API to free the memory returned by the Enumeration API
[DllImport("FirewallAPI.dll")]
internal static extern void NetworkIsolationFreeAppContainers(IntPtr pACs);
// Call this API to load the current list of Loopback-enabled AppContainers
[DllImport("FirewallAPI.dll")]
internal static extern uint NetworkIsolationGetAppContainerConfig(out uint pdwCntACs, out IntPtr appContainerSids);
// Call this API to set the Loopback-exemption list
[DllImport("FirewallAPI.dll")]
internal static extern uint NetworkIsolationSetAppContainerConfig(uint pdwCntACs, SID_AND_ATTRIBUTES[] appContainerSids);
// Use this API to convert a string SID into an actual SID
[DllImport("advapi32.dll", SetLastError=true)]
internal static extern bool ConvertStringSidToSid(string strSid, out IntPtr pSid);
// Use this API to convert a string reference (e.g. "#{blah.pri?ms-resource://whatever}") into a plain string
[DllImport("shlwapi.dll", CharSet=CharSet.Unicode, ExactSpelling=true)]
internal static extern int SHLoadIndirectString(string pszSource, StringBuilder pszOutBuf, int cchOutBuf, IntPtr ppvReserved);
For those unaware of the Windows 8 application security, 'Metro' apps are not allowed to communicate with localhost unless added to the exceptions list. The above code facilitates this (apparently), but I cannot work out for example how to add Internet Explorer to the exceptions list.
Can anybody provide any examples on how to use this code? I'm really lost!
Example adding Edge to exceptions:
// We need construct PSID from this string sid
const string EDGE_SID = "S-1-15-2-3624051433-2125758914-1423191267-1740899205-1073925389-3782572162-737981194";
IntPtr pSid = IntPtr.Zero;
ConvertStringSidToSid(EDGE_SID, out pSid); // Pinvoked
List<SID_AND_ATTRIBUTES> list = PI_NetworkIsolationGetAppContainerConfig(); // For simplicity, this is borrowed from complex example below.
SID_AND_ATTRIBUTES item = new SID_AND_ATTRIBUTES(); // This Struct can be found in complex example too
item.Sid = sid;
list.Add(item);
uint r = NetworkIsolationSetAppContainerConfig((uint)list.Count, list.ToArray());
Here is complex example of usage.
I am facing a problem. I have written and win32 DLL in delphi 2009. Now I want to dynamically load that DLL from C# desktop application but LoadLibray function returns 0. Here is CSharp code, please can any body helps me why DLL is not loading?
public partial class Form1 : Form
{
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad, IntPtr hFile, uint dwFlag);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("Kernel32.dll")]
private extern static Boolean CloseHandle(IntPtr handle);
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
IntPtr ptr = IntPtr.Zero;
ptr = LoadLibrary("MyDLL.dll", IntPtr.Zero, 0);
if (ptr == IntPtr.Zero)
{
MessageBox.Show("DLL not laded");
}
}
}
}
You have the wrong signature for LoadLibrary. It should be:
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr LoadLibrary(string dllname);
You had two spurious parameters and weren't capturing the error code.
Always check for errors when calling Win32 functions. In this case
IntPtr lib = LoadLibrary(dllname);
if (lib == IntPtr.Zero)
throw new Win32Exception();
Common failure modes include:
Mis-matched bitness.
DLL not found on DLL search path.
DLL's dependencies not resolved.
I can't tell you why that DLL is not loading as there is not enough information in the question.
Hint: Have you checked that your application is running in 32-bit or 64-bit appropriately for the DLL?
However, I can tell you how to get more information about the problem.
First, add the following to the attributes:
[DllImport("Kernel32.dll", SetLastError=true)]
^-----------------^
Then add this to your if-statement that handles the problem:
if (ptr == IntPtr.Zero)
throw new Win32Exception();
This should give you a more specific exception message indicating what the problem might be.
I have few images embedded in my executable in resource section.
I followed these steps to create my executable:
Generated .resx file for all the images (.jpg) in a directory using some utility. The images are named image1.jpg, image2.jpg and so on.
created .resources file from .resx file using: resgen myResource.resx
Embedded the generated .resource file using /res flag as: csc file.cs /res:myResource.resources
4 I am accessing these images as:
ResourceManager resources = new ResourceManager("myResource", Assembly.GetExecutingAssembly());
Image foo = (System.Drawing.Image)(resources.GetObject("image1"));
This all is working fine as expected. Now I want to change embedded images to some new images. This is what I am currently doing:
class foo
{
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr BeginUpdateResource(string pFileName, bool bDeleteExistingResources);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool UpdateResource(IntPtr hUpdate, string lpType, string lpName, string wLanguage, Byte[] lpData, uint cbData);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);
public static void Main(string[] args)
{
IntPtr handle = BeginUpdateResource(args[0], false);
if (handle.ToInt32() == 0)
throw new Exception("File Not Found: " + fileName + " last err: " + Marshal.GetLastWin32Error());
byte[] imgData = File.ReadAllBytes("SetupImage1.jpg");
int fileSize = imgData.Length;
Console.WriteLine("Updaing resources");
if (UpdateResource(handle, "Image", "image1", "image1", imgData, (uint)fileSize))
{
EndUpdateResource(handle, false);
Console.WriteLine("Update successfully");
}
else
{
Console.WriteLine("Failed to update resource. err: {0}", Marshal.GetLastWin32Error());
}
}
}
The above code is adding a new resource for the specified image (inside IMAGE title with some random number, as seen in Resource hacker), but I want to modify the existing resource data for image1.
I am sure that I am calling UpdateResource with some invalid arguments.
Could any one help pointing that out?
I am using .NET version 2
Thank you,
Vikram
I think you are making a confusion between .NET resources, and Win32 resources. The resources you add embedding with the /res argument to csc.exe are .NET resources that you can successfully read using you ResourceManager snippet code.
Win32 resources are another beast, that is not much "compatible" with the managed .NET world in general, athough you can indeed add them to a .NET exe using the /win32Res argument - note the subtle difference :-)
Now, if you want to modify embedded .NET resources, I don't think there are classes to do it in the framework itself, however you can use the Mono.Cecil library instead. There is an example that demonstrates this here: C# – How to edit resource of an assembly?
And if you want to modify embedded Win32 resources, you code needs some fixes, here is a slightly modified version of it, the most important difference lies in the declaration of UpdateResource:
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr BeginUpdateResource(string pFileName, bool bDeleteExistingResources);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool UpdateResource(IntPtr hUpdate, string lpType, string lpName, short wLanguage, byte[] lpData, int cbData);
[DllImport("kernel32.dll")]
static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);
public static void Main(string[] args)
{
IntPtr handle = BeginUpdateResource(args[0], false);
if (handle == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error()); // this will automatically throw an error with the appropriate human readable message
try
{
byte[] imgData = File.ReadAllBytes("SetupImage1.jpg");
if (!UpdateResource(handle, "Image", "image1", (short)CultureInfo.CurrentUICulture.LCID, imgData, imgData.Length))
throw new Win32Exception(Marshal.GetLastWin32Error());
}
finally
{
EndUpdateResource(handle, false);
}
}
This is impossible. You cant modify compiled file that you are running.
I believe you can add new images in run time but can't update a resource that is essentially just held in memory.
If you add a resource in run time, it exists but I don't think it is compiled and therefore I don't think it is accessible to you.
Is there a reason you aren't using content instead?
I try to use a VB6 DLL in a C# Program. But I allways get a AccessViolationException. Maybe you can tell me what Im doing wrong.
I created a Test-VB6-DLL like in this tutorial:
http://oreilly.com/pub/a/windows/2005/04/26/create_dll.html
Then I tried to use this DLL dynamically like in this Post:
http://blogs.msdn.com/b/jonathanswift/archive/2006/10/03/dynamically-calling-an-unmanaged-dll-from-.net-_2800_c_23002900_.aspx?PageIndex=3#comments
But also if I try it by using [DLLImport]. I allways run into the AccessViolationException.
Maybe someone can give me a hint.
regards
viktor
P.S.: What I was able to do is to create a reference to an existing DLL. But this approach has the disadvantage, that I have to update all the references if the DLL is updated. And this will happen (more or less) open because to dlls are part of a softwareproject that is under developmen. Maybe there is a possibility to update the references without to need to recompile the C# program?
#MarkJ: No - binary compatibility brought no success.
Here are the sources:
The VB6-Dll:
Option Explicit
Public Function Increment(var As Integer) As Integer
If Not IsNumeric(var) Then Err.Raise 5
Increment = var + 1
End Function
And here the C# code that tries to use the VB6 Dll:
class Program
{
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr LoadLibrary(String DllName);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, byte[] procedureName);
static void Main(string[] args)
{
IntPtr pDll = LoadLibrary(#"P:\dev\Path\to\TestProjekt.dll");
string x = "Increment";
Encoding e = Encoding.GetEncoding("ISO-8859-1");
byte[] b = e.GetBytes(x);
IntPtr pAddressOfFunctionToCall = GetProcAddress(pDll, b);
Increment inc = Increment)Marshal.
GetDelegateForFunctionPointer(pAddressOfFunctionToCall,
typeof(Increment));
int a = inc(5); // <---- Here the AccessViolationException is thrown
return;
}
}
In the meantime I have read any doc I could find but still I don't habe any idea why this ist not working grgrgrgrgr
regards
viktor
Your byte[] b has no terminating null, so isn't a valid unmanaged LPCSTR. I don't understand why you are fiddling about trying to encode the method name by hand, instead of declaring GetProcAddress like this and having the Framework interop code take care of the marshalling for you:
public static extern IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string procedureName);
You must check the return value (pAddressOfFunctionToCall). When it isIntPtr.Zero as I believe you are getting, because your lpProcName argument to GetProcAddress is wrong, then attempting to call through its Delegate wrapper will always give an AccessViolationException.
Also, don't omit to call FreeLibrary on the module handle when you are done.