I don't have the code with me at the moment, but I can describe to you what I did to solve this problem. The issue is that while the p4api.net library will compile just fine when set to target Any CPU, the underlying native C++ library (p4bridge.dll) is targeting either x86 or x64, and there's no way to compile it for both architectures in one DLL. Thus, I had to get clever!
To make this work, I added both versions of p4bridge.dll to the p4api.net project, renaming them p4bridge86.dll and p4bridge64.dll, and marked them to be included as assembly resources. Next, I wrote a static function in the p4api.net library that figured out which architecture the machine is running on, gets the correct p4bridge.dll resource, saves it to disk next to the p4api.net.dll that's currently executing, and finally P/Invokes the Windows LoadLibrary function on the extracted p4bridge.dll.
The final piece of the puzzle is making sure this function you've written runs before any types inside p4api.net are instantiated, as at that point the loader will see types referencing p4bridge.dll and attempt to load it from disk, and if you've never run the extraction function, it won't be there and you'll have an exception thrown. To fix this, I had to get kinda hacky with .NET: I downloaded Einar Egilsson's fantastic little tool InjectModuleInitializer and set up a post build step on the p4api.net project which ran the tool and had it insert instructions to call the static extractor/loader function I wrote before any other code in the module was executed.
With this setup, I had a single p4api.net assembly which was compiled for Any CPU, but could automatically deal with the fact that the required native p4bridge.dll must exist separately for the x86 and x64 architectures.
When I get home later, I'll see about adding source code showing exactly how I wrote the extract and load function, and anything else that might need more clarity. Sorry this answer came over a year after you asked originally, but I too needed to figure out a solution to this problem a couple days ago and since I managed to do it, I thought it would be worth sharing for anyone who might run into this very convoluted problem in the future!
Edit:
Here's the implementation of the class that extracts and loads the correct p4bridge.dll. It only extracts the DLL if it either isn't extracted, or the one it does find fails to load (because perhaps it's the wrong architecture, for some reason). Also, p4bridge.dll is several megabytes in size and there's not much point in performing unnecessary IO every time p4api.net is loaded!
internal static class P4BridgeLoader
{
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
private static void ExtractResource(string resourceName, string outPath)
{
using (System.IO.Stream dllStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
{
try
{
// Copy the assembly to the temporary file
using (System.IO.Stream outFile = System.IO.File.Create(outPath))
{
dllStream.CopyTo(outFile);
}
}
catch
{
}
}
}
/// <summary>
/// Loads the correct version of p4bridge.dll, based on the bit with of the current architecture.
/// Note that this is called by the module initializer, which gets called just after this module
/// is loaded but before any other code inside it is executed.
/// </summary>
internal static void LoadP4BridgeDLL()
{
// Figure out where we are going to put the p4bridge.dll once we've extracted it
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string assemblyPath = Uri.UnescapeDataString(uri.Path);
string assemblyDir = Path.GetDirectoryName(assemblyPath);
string dllPath = Path.Combine(assemblyDir, "p4bridge.dll");
// Extract the correct architecture version of p4bridge.dll from our assembly's resources
string resourceName = Environment.Is64BitProcess ? "Perforce.P4.p4bridge64.dll" : "Perforce.P4.p4bridge86.dll";
// If the dll already exists, then we shouldn't have to try extracting it again unless it fails to load
if (System.IO.File.Exists(dllPath))
{
// Attempt to load the DLL
if (LoadLibrary(dllPath) != IntPtr.Zero)
return;
}
// DLL either wasn't already extracted, or failed to load. Try again!
ExtractResource(resourceName, dllPath);
// Attempt to load the DLL
IntPtr h = LoadLibrary(dllPath);
System.Diagnostics.Debug.Assert(h != IntPtr.Zero, "Unable to load library " + dllPath);
}
}
And here's the command line that should be used to hook in to the .net Module Initializer. Note that the /k:MyKey.snk
argument allows the assembly to be strong signed after it's been modified.
InjectModuleInitializer.exe /k:MyKey.snk /m:Perforce.P4.P4BridgeLoader::LoadP4BridgeDLL p4api.net.dll