We have been using an SAP "COM License Bridge" to access their license server and query the hardware key of a system programatically (to reuse with out own licensing). This worked fine on SAP Business one Versions 2007A, 2007B and 8.8, but in 8.81 they seem to have updated their CORBA interface without updating the COM wrapper because we now get memory exceptions when attempting to call the GetHardwareKey function.
So I downloaded IIOP.NET and started trying to write my own interface. I never liked that COM wrapper anyway. But I encountered my old nemesis of .NET remoting -- the inability to invoke a remote method without having a common interface defined in both the server and the client. I tried using the IDL to CLS compiler included with IIOP.NET, but I continue to get errors about the interface beign incompatible (SAP did not provide an IDL file). I don't know how IIOP and CORBA determine whether an interface is compatible. But I even tried debugging into IIOP.NET code and forcing it to execute the method despite the incompatibility, but received an empty string back instead of the hardware key I wanted.
My next step is to try to implement a fake license server and examine the requests coming in from the production client in the hopes of identifying what they should look like, but I'm not counting on much success considering the difficulty I've had in peering into the innards of .NET remoting already.
My real problem is how to get or generate the SAP Business One hardware key, but questions stemming from that include:
- How do I reflect on or query information about a CORBA interface? I can use the list method of the NamingContext class to retrieve a list of available objects, but I don't see if there is a way to query available methods on an object.
- Can I dynamically invoke .NET remoting methods without having an interface? I see there's something called DII for dynamically invoking CORBA, but I don't see how to use it from IIOP.NET.
- Can I invoke .NET remoting methods with just a delegate or incomplete interface? I tried using the dynamic keyword, but it was unable to invoke a method on my MarshalByRef remote object... I think it said the method didn't exist on my MarshalByRef instance or something. I have only tried this via IIOP.NET, though (I wonder if it works for normal .NET remoting).
- How do I create or inspect Message instances in the .NET remoting framework?
- Can I send or retrieve remoting messages directly, bypassing the underlying proxies?
Edit: I managed to make IIOP.NET / CORBA believe that I had a compatible interface by applying the RepositoryID attribute:
[Ch.Elca.Iiop.Idl.InterfaceType(Ch.Elca.Iiop.Idl.IdlTypeInterface.ConcreteInterface)]
[Ch.Elca.Iiop.Idl.RepositoryID("IDL:LicenseInfo:1.0")]
public interface ILicenseInfo : Ch.Elca.Iiop.Idl.IIdlEntity
{
void GetHardwareKey(out string hwKey);
}
But I am still getting an empty string result.
Edit 2: After some more experimentation and debugging, I have found that the response messages do contain the data I'm looking for, but are not being parsed into the client values properly, probably because of my bad interface definition. Hoping that debugging into the response processing further will help me figure out how to correct my interface. Strangely the first thing it's parsing from the response is a null boxed value, which doesn't seem right for an "out string" parameter.
Edit 3: I have found that I need to apply string attributes to the parameters like this to prevent them from being treated as boxed values:
void GetHardwareKey([StringValue(), WideChar(true)] out string hwKey);
But despite the WideChar attribute, I am getting en error about the CodeSet not supporting WChar or something. I'm getting really close to figuring this out.
Edit 4: I am stumped at how to set the codeset for WChar. If I do not set it, I receive an error: "WChar Codeset either not specified or not supported." because the server has returned a unicode string without overriding the default character set. I can't find any way to override that from the client. I tried calling:
omg.org.CORBA.OrbServices.GetSingleton().OverrideDefaultCharSets(
CharSet.UTF8, WCharSet.UTF16);
But that does not seem to have any effect on the client end. The example code shows calling that on the server end. But I didn't write the server, so I can't control that. Is my only option to rewrite the IIOP.NET code for my own purposes forcing a default WChar CodeSet to go into effect?
After 3 days of debugging into IIOP to track down its behavior and inspect the data coming back in the response, I have settled on this solution.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using omg.org.CosNaming;
using Ch.Elca.Iiop;
using Ch.Elca.Iiop.Services;
using System.Runtime.Remoting.Channels;
using Ch.Elca.Iiop.Idl;
[RepositoryID("IDL:LicenseInfo:1.0")]
public interface ILicenseInfo
{
Int32 GetHardwareKey([IdlSequence(0)] out byte[] hwKey);
Int32 GetInstallationNumberList([IdlSequence(0)] out byte[] instNum);
}
class Program
{
static void Main(string[] args)
{
IiopClientChannel channel = new IiopClientChannel();
ChannelServices.RegisterChannel(channel, false);
CorbaInit init = CorbaInit.GetInit();
NamingContext context = init.GetNameService("MYLICSRV", 30000);
NameComponent[] names = new NameComponent[] { new NameComponent("B1LicenseInfo") };
ILicenseInfo li = (ILicenseInfo)context.resolve(names);
byte[] hwKey;
byte[] instNum;
li.GetHardwareKey(out hwKey);
li.GetInstallationNumberList(out instNum);
Encoding encoding = new System.Text.UnicodeEncoding(false, false, true);
Console.WriteLine(encoding.GetString(hwKey));
Console.WriteLine(encoding.GetString(instNum));
}
}
I temporarily was also using this in an attempt to make IIOP give me back the right strings. If it had occurred to me that I could simply accept the reply as a byte array and perform the decoding myself, I wouldn't have wasted half the time trying to work out how to get IIOP to understand how I wanted my string back:
class MyOrbInitializer : omg.org.PortableInterceptor.ORBInitializer
{
public void post_init(omg.org.PortableInterceptor.ORBInitInfo info)
{
// Nothing to do
}
public void pre_init(omg.org.PortableInterceptor.ORBInitInfo info)
{
omg.org.IOP.Codec codec = info.codec_factory.create_codec(
new omg.org.IOP.Encoding(omg.org.IOP.ENCODING_CDR_ENCAPS.ConstVal, 1, 2));
Program.m_codec = codec;
}
}
class Program
{
public static omg.org.IOP.Codec m_codec;
static void Main(string[] args)
{
IOrbServices orb = OrbServices.GetSingleton();
orb.OverrideDefaultCharSets(CharSet.UTF8, WCharSet.UTF16);
orb.RegisterPortableInterceptorInitalizer(new MyOrbInitializer());
orb.CompleteInterceptorRegistration();
...
MarshalByRefObject objRef = context.resolve(names);
string origObjData = orb.object_to_string(objRef);
Ch.Elca.Iiop.CorbaObjRef.Ior iorObj = new Ch.Elca.Iiop.CorbaObjRef.Ior(origObjData);
CodeSetComponentData cscd = new CodeSetComponentData(
(int)Ch.Elca.Iiop.Services.CharSet.UTF8,
new int[] { (int)Ch.Elca.Iiop.Services.CharSet.UTF8 },
(int)Ch.Elca.Iiop.Services.WCharSet.UTF16,
new int[] { (int)Ch.Elca.Iiop.Services.WCharSet.UTF16 });
omg.org.IOP.TaggedComponent codesetcomp = new omg.org.IOP.TaggedComponent(
omg.org.IOP.TAG_CODE_SETS.ConstVal, m_codec.encode_value(cscd));
iorObj.Profiles[0].TaggedComponents.AddComponent(codesetcomp);
string newObjData = iorObj.ToString();
MarshalByRefObject newObj = (MarshalByRefObject)orb.string_to_object(newObjData);
ILicenseInfo li = (ILicenseInfo)newObj;
...
}
After that much code ran, I had an object that would define the WChar CodeSet so it would parse the return strings properly, avoiding the "WChar CodeSet either not specified or not supported" error. But after all that, the Unicode byte ordering was backwards too! And the only way to fix that, as far as I could tell, was to re-parse the string into bytes and then back into a Unicode string. But that's when it occurred to me, why even ask for the result as a string!? I could just take the bytes directly and avoid so much of this complication. I wish I had thought of that earlier.
SAP BO 882 //LicenseInterface.idl
typedef sequence<octet> LicenseFileData;
interface LicenseInfo
{
boolean IsUserLicensed(in wstring wstrUser, in wstring wstrModule, in wstring wstrInstallNo);
long GetHardwareKey(out wstring pbstrHK);
long GetInstallationNumberList(out wstring wbstrInstNum);
long GetSystemNumber(out wstring wbstrSysNum, in wstring wstrInstallNo);
long GetLicenseInfo(in wstring wstrModule, out long lNum, out long lAvailable, out long lStart, out long lEnd, in wstring wstrInstallNo);
long GetLoggedInUsers(out wstring wbstrLogUsers);
long StartLogging();
long StopLogging();
long GetLicenseNum(in wstring wstrKey, in wstring wstrInstallNo);
long GetLogFileName(out wstring wstrLogFileName);
boolean GetIsLogging();
long LoadLicenseFile (in LicenseFileData arg_licenseFileData);
boolean IsLicenseFileExist();
long ResetAllLicenses();
long GetVersion(out wstring sVersion);
//long DeleteLicenseFile (in wstring wstrInstallNo);
};
SBOLicense.idl
typedef sequence<octet> usBuffer;
enum LicenseClientUTFType {LIC_UTF16 , LIC_UTF32};
exception NotAuthenticated {};
exception UserNotConnected {};
interface LicenseServer
{
long SBOConnect (in usBuffer User, in usBuffer Company, in usBuffer PCName, out usBuffer SessionE, in long lDate, in usBuffer sInstallNo) raises(NotAuthenticated);
long AddOnGetLicense (in usBuffer Identifier, in usBuffer User, in usBuffer Company, in usBuffer PCName, out long plSessionID, out usBuffer SessionE, in long lDate, in usBuffer sInstallNo) raises(NotAuthenticated);
long PollSession (in usBuffer User, in usBuffer SIDs, out usBuffer RetE) raises(NotAuthenticated);
long SessionsInfo (in usBuffer User, in usBuffer SessionsInfo, out usBuffer SessionsInfoE, in long lDate) raises(NotAuthenticated);
long SessionVerify (in usBuffer User, in long lSessionID, out usBuffer pSessionIdE) raises(NotAuthenticated);
long CloseSession (in usBuffer User, in long lSessionId) raises(NotAuthenticated);
long LockServer (in usBuffer User, in long lSessionID) raises(NotAuthenticated);
long UnLockServer (in usBuffer User, in long lSessionID) raises(NotAuthenticated);
long GetUserLicenseInfo (in usBuffer User, out usBuffer pModules, out boolean pbIsConnected) raises(NotAuthenticated);
long GetAllModulesStatus (out usBuffer pModulesInfo) raises(NotAuthenticated);
long LoadLicenseFile (in usBuffer NewLicenseFile) raises(NotAuthenticated);
long GetHardwareKey (out usBuffer pHK) raises(NotAuthenticated);
long CreateIdentifier (in usBuffer Addon, out usBuffer pIdentifier, in usBuffer sInstallNo) raises(NotAuthenticated);
long GetAllUsersLicenseInfo(out usBuffer pUsersLicInfo) raises(NotAuthenticated);
long SetAllUsersLicenseInfo(in usBuffer User, in usBuffer UsersLicInfo, out usBuffer pConnectedUser) raises(NotAuthenticated,UserNotConnected);
long IsDevExist (in usBuffer sInstallNo);
long GetInstallationNumberList(out usBuffer pInstNum);
long GetSystemNumber (out usBuffer pSysNum, in usBuffer sInstallNo);
long GetFutureExpired(in long lFutureDate, out usBuffer pModules, in usBuffer sInstallNo);
long GetUserSessionsInfo(in usBuffer UserName,out usBuffer pRsltSessionsInfo);
long GetBIGSLicense (in usBuffer User, in usBuffer Company, in usBuffer PCName, in long lNum, out usBuffer pSessionsE, in long lDate, in usBuffer sInstallNo) raises(NotAuthenticated);
boolean IsLicenseFileExist();
long GetVersion(out usBuffer sVersion);
long ClearUserLicenses (in usBuffer User) raises(NotAuthenticated);
long UpdateUserLicenses (in usBuffer User, out usBuffer ModulesE, in long lDate, in long lSessionID, in usBuffer sCmpLocalization, in usBuffer sCmpVersion) raises(NotAuthenticated);
long RequestNamedLicenses (in usBuffer User, out usBuffer ModulesE, in long lDate, in long lSessionID, in usBuffer sCmpLocalization, in usBuffer sCmpVersion) raises(NotAuthenticated);
long IsLicenseConcurrent () raises(NotAuthenticated);
long GetLicenseFileGenInfo(in usBuffer sInstallNo, out usBuffer sLicGenInfo);
//long DeleteLicenseFile (in usBuffer sInstallNo) raises(NotAuthenticated);
long HandShake(in long algorithm, in usBuffer publicKey, out usBuffer sessionKey) raises(NotAuthenticated);
long GetCompanyDBCredentials(in long dbType, in usBuffer server, in usBuffer company, in usBuffer user, in usBuffer password, out usBuffer dbUser, out usBuffer dbPassword, out boolean useTrusted) raises(NotAuthenticated);
long GetDBCredentials(in long dbType, in usBuffer server, in usBuffer siteUser, in usBuffer password, out usBuffer dbUser, out usBuffer dbPassword, out boolean useTrusted) raises(NotAuthenticated);
long GetCompanyReadOnlyDBCredentials(in long dbType, in usBuffer server, in usBuffer company, in usBuffer user, in usBuffer password, out usBuffer dbUser, out usBuffer dbPassword) raises(NotAuthenticated);
long GetReadOnlyDBCredentials(in long dbType, in usBuffer server, in usBuffer siteUser, in usBuffer password, out usBuffer dbUser, out usBuffer dbPassword) raises(NotAuthenticated);
long GetListOfCompanies(in long dbType, in usBuffer server, in boolean refresh, out usBuffer listOfCompanies);
long GetCompanyEncryptionConfig(in long dbType, in usBuffer server, in usBuffer company, in usBuffer user, in usBuffer password, out long algorithm, out usBuffer keyId, out usBuffer key) raises(NotAuthenticated);
long GetEncryptionConfig(in usBuffer siteUser, in usBuffer password, out long algorithm, out usBuffer keyId, out usBuffer key) raises(NotAuthenticated);
long SetDBCredentials(in long dbType, in usBuffer server, in usBuffer siteUser, in usBuffer password, in usBuffer dbUser, in usBuffer dbPassword, in boolean useTrusted) raises(NotAuthenticated);
long RemoveDBCredentials(in long dbType, in usBuffer server, in usBuffer siteUser, in usBuffer password) raises(NotAuthenticated);
long GetServerVersion(in long dbType, in usBuffer server, out usBuffer version, in usBuffer commonDBName);
long SetReadOnlyDBCredentials(in long dbType, in usBuffer server, in usBuffer siteUser, in usBuffer password, in usBuffer dbUser, in usBuffer dbPassword) raises(NotAuthenticated);
long SetEncryptionAlghorithm(in usBuffer siteUser, in usBuffer password, in long algorithm) raises(NotAuthenticated);
long GenerateEncryptionKey(in usBuffer siteUser, in usBuffer password) raises(NotAuthenticated);
long GetServicesUserCredentials(in usBuffer siteUser, in usBuffer password, out usBuffer servicesUser, out usBuffer servicesPassword) raises(NotAuthenticated);
long ExportSecuritySettings(in usBuffer siteUser, in usBuffer password, out usBuffer xmlSettings) raises(NotAuthenticated);
long ImportSecuritySettings(in usBuffer siteUser, in usBuffer password, in usBuffer xmlSettings) raises(NotAuthenticated);
long GetListOfConfiguredServers(out usBuffer listOfServers);
long GetSiteUserName(out usBuffer siteUser);
long AuthenticateSiteUser(in usBuffer siteUser, in usBuffer password, out boolean result) raises(NotAuthenticated);
long AuthenticateServicesUser(in usBuffer siteUser, in usBuffer password, out boolean result) raises(NotAuthenticated);
long ChangeSiteUserPassword(in usBuffer siteUser, in usBuffer oldPassword, in usBuffer password) raises(NotAuthenticated);
long ChangeSiteUserPasswordByDB(in long dbType, in usBuffer server, in usBuffer dbUser, in usBuffer dbPassword, in usBuffer password) raises(NotAuthenticated);
long GetCompanyStaticKey(in long dbType, in usBuffer server, in usBuffer company, in usBuffer user, in usBuffer password, out usBuffer key) raises(NotAuthenticated);
long GetStaticKey(in usBuffer siteUser, in usBuffer password, out usBuffer key) raises(NotAuthenticated);
long GetEncryptionAlgorithm(out long algorithm);
long IsNTTrusted(in long dbType, in usBuffer server, out boolean isNTTrusted);
long IsDKeyUsed(out boolean result);
long ExportDKeys(in usBuffer siteUser, in usBuffer password, out usBuffer xmlDKeys) raises(NotAuthenticated);
long ImportDKeys(in usBuffer siteUser, in usBuffer password, in usBuffer xmlDKeys) raises(NotAuthenticated);
long GenerateDKey(in usBuffer siteUser, in usBuffer password, out usBuffer xmlDKeys) raises(NotAuthenticated);
long EnableDKey(in usBuffer siteUser, in usBuffer password, out usBuffer xmlDKeys) raises(NotAuthenticated);
long GetCompanyKeyAndKeyState(in long dbType, in usBuffer server, in usBuffer company, in usBuffer user, in usBuffer password, in usBuffer compKeyId, out long keyState, out usBuffer compKey)raises(NotAuthenticated);
long GetKeyAndKeyState(in usBuffer siteUser, in usBuffer password, in usBuffer compKeyId, out long keyState, out usBuffer compKey)raises(NotAuthenticated);
};
interface LicenseServerFactory
{
LicenseServer GetLicenseServer(in LicenseClientUTFType ClientUTFType);
};
来源:https://stackoverflow.com/questions/6031381/how-to-access-corba-interface-without-idl-or-late-bound-invoke-remoting-methods