Wednesday, November 15, 2017

NPM global packages

To list global NPM packages:

npm list -g --depth=0

 To update the globally installed NPM packages:

sudo npm -g update

Wednesday, January 25, 2017

Python Debugging Notes

A few notes for me...

  • To print the properties of an object: 
print “Properties are:”, obj.__dict__

Sunday, July 17, 2016

Accessing a VS2015 Express website on a Parallels VM from a Mac

I’ve got a Mac which is running a Windows 10 Parallels VM that I use for Microsoft Visual Studio 2015 development. I’m using the Express Edition of VS2015. If I code up a web application (maybe a web service or an ASP.NET Web API) and run it in the IDE, I can hit it from the browser on that machine at http://localhost:57292/api/test.

How can I consume this Windows 10 web service from my Mac?

First of all I need to know the IP address of my Win 10 machine. Fire up a “cmd" prompt and run “ipconfig”. In my case the "IPv4 Address” is 10.211.55.4

To avoid having to remember and type this address, let’s add it to the “hosts” file on the Mac. Do this from the Terminal on the Mac using “sudo vi /private/etc/hosts” and add in a new line such as:

10.211.55.4     win10

Sadly, if I fire up Safari on my Mac and try to browse to http://win10:57292/api/test or (http://10.211.55.4:57292/api/test), it won’t find the page. There are two reasons for this:

  1. By default, IIS Express only allows access to your Visual Studio websites via localhost, and
  2. The Windows 10 firewall will block incoming connections to this website.

Fortunately, both of these can be overcome thanks to the handy tips on this webpage. Read it for the details, but for my quick reference I need to do the following on the Windows 10 machine:

  1. Edit the {project}\.vs\config\applicationhost.config file and search for my website (using the port is easiest). Add the following binding (the localhost line will already be there - add the second line with the IP address): 

    <binding protocol="http" bindingInformation="*:57292:localhost" />

    <binding protocol="http" bindingInformation="*:57292:10.211.55.4" />

    NB.This step needs to be done for each new website.  

  2. Create a hole in the Windows 10 firewall using these two commands from a “Run as Administrator” cmd prompt:  

    >netsh http add urlacl url=http://10.211.55.4:57292/ user=everyone 

    >netsh advfirewall firewall add rule name="IISExpressWeb" dir=in protocol=tcp localport=57292 profile=private remoteip=localsubnet action=allow

Now, firing up Safari on the Mac and browsing to http://win10:57292/api/test should work!

If you are getting a 503 error, it could be because IIS Express hasn’t restarted and picked up the new website location. Check in the Windows System Tray for the IIS Express icon and click on it to see when there IP address is listed under the application:

IIS express from system tray

 If it isn’t there, stop VS2015, exit IIS Express if still running (using the ‘Exit' option above), and restart your VS2015 application.

Thursday, July 3, 2014

Accessing a VS2013 Express website on a Parallels VM from a Mac

NB. Updated for Windows 10/VS2015 here.

I’ve got a Mac which is running a Windows 7 Parallels VM that I use for Microsoft Visual Studio 2013 development. I’m using the Express Edition of VS2013. If I code up a web application (maybe a web service or an ASP.NET Web API) and run it in the IDE, I can hit it from the browser on that machine at http://localhost:57017/api/test.

How can I consume this Windows 7 web service from my Mac?

First of all I need to know the IP address of my Win 7 machine. Fire up a “cmd" prompt and run “ipconfig”. In my case the "IPv4 Address” is 10.211.55.3

To avoid having to remember and type this address, let’s add it to the “hosts” file on the Mac. Do this from the Terminal on the Mac using “sudo vi /private/etc/hosts” and add in a new line such as:

10.211.55.3     win7

Sadly, if I fire up Safari on my Mac and try to browse to http://win7:57017/api/test or (http://10.211.55.3:57017/api/test), it won’t find the page. There are two reasons for this:

  1. By default, IIS Express only allows access to your Visual Studio websites via localhost, and
  2. The Windows 7 firewall will block incoming connections to this website.

Fortunately, both of these can be overcome thanks to the handy tips on this webpage. Read it for the details, but for my quick reference I need to do the following on the Windows 7 machine:

  1. Edit the C:\Users\{UserName}\Documents\ IISExpress\config\applicationhost.config file and search for my website, adding the following binding (the localhost line will already be there - add the second line with the IP address):

    <binding protocol="http" bindingInformation="*:57017:localhost" />

    <binding protocol="http" bindingInformation="*:57017:10.211.55.3" />

    NB.This step needs to be done for each new website.  

  2. Create a hole in the Windows 7 firewall using these two commands from a “Run as Administrator” cmd prompt: 

    >netsh http add urlacl url=http://10.211.55.3:57017/ user=everyone

    >netsh advfirewall firewall add rule name="IISExpressWeb" dir=in protocol=tcp localport=57017 profile=private remoteip=localsubnet action=allow

Now, firing up Safari on the Mac and browsing to http://win7:57017/api/test should work!

Wednesday, January 29, 2014

Reduce PDF File Size - More options for Mac

On my Mac, I needed to reduce the size of some scanned PDF documents - without changing the scanner settings and rescanning them. I tried to Export from Preview as a PDF using the “Reduce File Size” filter, but it made the files too blurry.

Googling revealed a nice solution, which allows you to add your own custom “Reduce File Size” filters to Preview’s Export window. Once you’ve done this once, you can use them whenever you need to:

New Reduce File Size Filters

I am going to repost how to do this here, so I don’t lose it. The original can be found at: http://hints.macworld.com/article.php?story=20120629091437274

I was never satisfied with results of "Reduce File Size" Quartz filter when trying to make some PDFs smaller before sending them by e-mail. It made them too small, and the graphics were fuzzy. 

I eventually found where these filters are: 

/System/Library/Filters 

I was delighted to find out they're XML files easily editable with TextEdit (or any other text editor). I also found why this particular filter makes quite unusable PDFs, as these parameters were just too low: 

Compression Quality 0.0
ImageSizeMax 512 

So I copied this file to my Desktop, and then made two more copies of it, and called them Reduce File Size Good, Better and Best. Then I changed the parameters of each file to 0.25, 0.5 and 0.75 for Compression Quality, and used these three values for ImageSizeMax: 

842 (that's A4 at 72dpi)
1684 (A4 at 144dpi)
3508 (A4 at 300dpi) 

Finally, I changed the default string for the Name key at the end of each file to reflect the three settings, so they display the names I have given them in the menu. 

Then I copied them to a /Library/Filters folder I created (for some reason, ~/Library/Filters doesn't work in Lion) and now when I open a picture or PDF in Preview, I have the option of four different qualities for reduced file sizes. 

As an example, I have a JPEG of scanned A4 invoice at 300dpi and it's 1.6MB. When exporting to PDF in reduced size, the file is only 27 KB and it's quite unusable - very fuzzy and hard to read. The Good one is much easier to read, slightly fuzzy and still only 80 KB. Better is 420 KB and clear, and the Best is 600 KB and almost as good as the original even on a laser printer.

A few notes:

  • As well as copying and renaming the *.qfilter files, you also need to change the “Name” parameter in the XML document, from “Reduce File Size” to “Reduce File Size Good” (or whatever).
  • You’ll need to use “sudo…” to create the /Library/Fileters folder and to move the files in there.

 

Friday, February 17, 2012

Implementing a VB6 COM interface in VB.Net - it's not all roses!

Not long after my revelation last week, that VB.Net could implement my VB6 COM interface that had a "optional string" parameter, I ran into a brick wall: VB.Net cannot implement a COM interface where a "Public Property" that passes variables by-reference has been exposed. ie. it can't implement this VB6 code:


Public Property Let MyProperty(sValue As String)
...
End Property


Try it and you get the following error:

Implementing property must have matching 'ReadOnly' or 'WriteOnly' specifiers.

This is a known bug and the only solution is to modify your COM interface (in your original VB6 dll) so that the arguments are passed by-value:


Public Property Let MyProperty(ByVal sValue As String)
...
End Property


Which, under the covers, changes the COM interface from:


[id(0x68030000), propput]
HRESULT MyProperty([in, out] BSTR* );


to


[id(0x68030000), propput]
HRESULT MyProperty([in] BSTR );


But of course, I don't want to change the COM interface - I want to implement the interface that has already been defined and is already being used by multiple legacy applications.

Or I can use C#, which handles these Public Properties just fine.

So I'm caught in a bind - only C# can handle the Public Properties, and only VB.Net can handle the Optional String Parameters. I'm going to have to break my COM interface and force multiple client recompilations... OR use a VB6 COM facade that calls my .Net dll.

A tough choice - yuck, yucky, or yuckier?

Monday, February 13, 2012

HOWTO: Replace a VB6 dll with a C# dll when methods have optional string parameters

My quest to replace my VB6 COM dll with a C# dll continues. In my last post I resolved the problems I was having where early binding to the DLL didn't work, but late binding did.

The problem I need to address this time is handling a VB6 method that has an optional String parameter. Something like:


Public Sub TestMethod(ByVal sArgIn As String, Optional sArgOut As String)


Looking in the TypeLibrary for the DLL (the *.IDL file we get from the OLEVIEW tool), we see this:


HRESULT TestMethod(
[in] BSTR sArgIn,
[in, out, optional] BSTR* sArgOut);


Creating the TLB via the MIDL command works, but it gives the following warning:

.\MyDll13.IDL(30) : warning MIDL2400 : for oleautomation, optional parameters should be VARIANT or VARIANT * : [optional
] [ Parameter 'sArgOut' of Procedure 'TestMethod' ( Interface '_TestClass' ) ]


I'll now go ahead and create my .Net DLL. When I use .Net to implement the interface, it stubs the C# method as:


using System.Runtime.InteropServices;

namespace MyDllNet
{
[ProgId("MyDll.TestClass")]
[ComVisible(true)]
[Guid("D860A2A8-5003-4714-AE59-918FE2B0FC42")]
public class MyProxyClass : MyDll13ModifiedTA.TestClass
{
public string GetVersion()
{...}

public void TestMethod(string sArgIn, [OptionalAttribute]ref string sArgOut)
{...}
}
}


This looks good. After completing the code and compiling it, I run my original VB6 app which uses the TestMethod method from a VB6 app via late binding. It works fine when I pass two parameters, but if I only pass one parameter it falls over with "Run-time error '13' Type mismatch". Interestingly, the VB6 app which uses early binding works with both one or two parameters passed!






C# DLL implements IDL with optional BSTR* argument
VB6 BindingPass One ArgPass Two Args
Early BindingOKOK
Late BindingOKError "Type mismatch"


Plan B. Plan B is to change the optional parameter in the IDL from BSTR* to VARIANT*. According to the MIDL error message, VARIANT* is the right type to use for an optional parameter in COM. Note that I'm not changing the original VB6 COM component, I'm just changing the definition in the Type Library.

Creating the TLB via the MIDL command no longer raises a warning; implementing this new IDL/TLB in Visual Studio yields the following method signature:


public void TestMethod(string sArgIn, [OptionalAttribute]ref object sArgOut) {}


But does it work? No, it's worse! Now it crashes the CLR!!






C# DLL implements IDL with optional VARIANT* argument
VB6 BindingPass One ArgPass Two Args
Early BindingError clr.dll APPCRASHError clr.dll APPCRASH
Late BindingOKOK


OK, this confirms that I don't know what I'm doing! But wait, if I remove all of the code from my "TestMethod" in the .Net DLL then everything works!?! The APPCRASH must be caused by the way I'm handling the object argument in my .Net code. Time to debug into the .Net dll component and see what's going on!

And it turns out that if I try to return anything at all (apart from null) in the optional parameter, I get a System.StackOverflowException in an Unknown Module. Almost time for me to give this one away. Just one last thing to try... VB.Net!

Plan C. VB.Net VB.Net offers more comprehensive COM support, presumably because it is supposed to be a migration path for people who have VB6. So I'll create a new VB.Net class project, and add a reference to the "optional BSTR*" assembly (create in Plan A above), and implement the interface in VB.Net. The VB.Net code looks something like:


Imports System.Runtime.InteropServices

<ProgId("MyDll.TestClass")>
<Guid("D860A2A8-5003-4714-AE59-918FE2B0FC42")>
Public Class MyProxyClass
Implements MyDll13TldAssembly.TestClass

Public Function GetVersion() As String Implements MyDll13TldAssembly._TestClass.GetVersion
...
End Function

Public Sub TestMethod(ByVal sArgIn As String, Optional ByRef sArgOut As String = Nothing) Implements MyDll13TldAssembly._TestClass.TestMethod
...
End Sub
End Class


And guess what? It works! Late-binding, early-binding, the optional supplied, the optional not supplied. All combinations work!. Job done.

To Conclude: If you want to implement a VB6 COM interface, which has an optional String parameter, in .Net, then use VB.Net! (with some provisos)

Tuesday, February 7, 2012

The quest to replace a VB6 dll with a C# dll continues

I have a VB6 dll that is being used, via COM, in multiple VB6 apps, COM add-ins, and Outlook Forms. It is being used via both late binding [Set o = CreateObject("a.b")] and early binding [Set o = New a.b] techniques. The idea is to replace the VB6 dll with a C# dll that does exactly the same thing, without touching any of the other applications.

I started by creating a C# dll that implements the same COM interface. But this only got me halfway there. I had two problems:


  1. It worked for late binding, but did not work for early binding. With early binding, the program would use the old VB6 dll (if present) or display the "ActiveX component can't create object" message.


  2. It did not work for a method that had an optional String parameter eg. Public Sub TestMethod(ByVal sArgIn As String, Optional sArgOut As String)



Note that in the years that have passed since this project was started (and stopped, and restarted), I've switched from VS2008 to VS2010, and from .Net 1.1 to .Net 4.0. Some of these problems might have arisen from this change in tools.

Identifying the late binding/early binding problem

Further investigation into COM revealed that when a VB6 dll is registered, it writes the following important entries into the registry (for a VB6 DLL called "MyDll.dll" with an exposed class called "TestClass" which therefore has a ProgId of "MyDll.TestClass"):


HKEY_CLASSES_ROOT\MyDll.TestClass\CLSID
+-- (Default) {ABB83F02-4012-45E4-ADD6-D2E79F45381D}


The "{ABB83...}" string is called a GUID which is basically a unique identifier. Following this in the registry, we get (amongst other things):


HKEY_CLASSES_ROOT\CLSID\{ABB83F02-4012-45E4-ADD6-D2E79F45381D}
+-- InProcServer32
+-- (Default) C:\code\MyDll.dll
+-- TypeLib
+-- (Default) {EACF9A0F-461E-4A36-A195-43ECDE3C5FBA}
+-- VERSION
+-- (Default) 1.1


Following the TypeLib entry (and using the "VERSION" value of "1.1") we get:


HKEY_CLASSES_ROOT\TypeLib\{EACF9A0F-461E-4A36-A195-43ECDE3C5FBA}
+-- 1.1
+-- 0
+-- win32
+-- (Default) C:\code\MyDll


All very boring, BUT the path to my VB6 dll is held in two different places. From what I can tell, late binding uses the first path shown at ...\CLSID\...\InProcServer32, and early binding uses the second path shown at ...\TypeLib\...\win32.

By adding the ProgId attribute to my public .Net class (like [ProgId("MyDll.TestClass")]) and registering it via regasm, my C# dll gets placed into the ...\CLSID\...\InProcServer32 entry. Well actually, because we only added the ProgId to our .Net dll, a new GUID is generated. But because late bound calls are resolved using the "MyDll.TestClass" ProgId, any late bound call to MyDll.TestClass will now use the .Net dll instead of the old VB6 dll.

But the ...\TypeLib\...\win32 registry entry still points to the old VB6 dll (or doesn't exist at all if the VB6 dll has been unregistered via "regsvr32 /u"). So early bound clients will still use the old VB6 dll, or crash.

Resolving the late binding/early binding problem

Resolving this is actually pretty straight-forward. We modify the "AssemblyInfo.cs" file in our .Net project, and insert the TypeLib GUID in there (or replace it with our TypeLib GUID if an entry is already there):


[assembly: Guid("EACF9A0F-461E-4A36-A195-43ECDE3C5FBA")]


Note that this is the TypeLib GUID not the CLSID GUID. I only knew the TypeLib GUID by inspecting the registry. I could also have found this TypeLib GUID by looking into one of the *.VBP project files for a VB6 project that early binds to this dll, where I would have seen:


Reference=*\G{EACF9A0F-461E-4A36-A195-43ECDE3C5FBA}#1.1#0#MyDll.dll#


Just to be neat and tidy, we can force .Net to use the same CLSID GUID as the VB6 dll by adding the "GUID" attribute to the .Net public class:


[ProgId("MyDll.TestClass")]
[ComVisible(true)]
[Guid("ABB83F02-4012-45E4-ADD6-D2E79F45381D")]
public class MyProxyClass : MyDllTlbAssembly.TestClass
{ ...


Next up? Solving the optional String parameter problem!

Wednesday, July 20, 2011

Dull colours in MS Word 2011 for Mac using *.doc format

I had a problem where I created a nice diagram in JPG format, but when I inserted it in my Word document the colours appeared dull and washed-out. This was using Mac Microsoft Word 2011 and saving the document in Word 97-2004 compatible format (*.doc). I tried many different ways to insert the image (including dragging and dropping it in), but all resulted in the washed-out image.

dull colours.png

Saving the document as a Word document (*.docx) resolves the problem; but unfortunately I need to use *.doc format for backwards compatibility with my corporate clients.

Then I noticed that some of my earlier images in the same document were not washed out. How could this be? Reinserting these older images resulted in nice bright pictures in my *.doc document. So the problem had to be with the new images I was creating. I was using the same method I had always used to create images, but Word did not like my new ones. Something must have changed.

I quick check of the image properties, via the Finder, revealed the answer: The Color Profile

image properties.png

I had created the first images on my laptop which gave them a Color Profile of "Color LCD". The later images had been created on my secondary monitor and got a Color Profile of "DELL 3008WFP".

The Solution

The solution was to preview the image, on my laptop screen, and take a screen shot of it (using Command-Shift-4 and selecting the image). This screenshot had the required "Color LCD" Color Profile. I then dragged that screenshot into MS Word and the colours were perfect! Voila!!



Friday, May 6, 2011

Visual Studio Keyboard shortcuts that I keep forgetting!

I use so many different IDEs that there are a few key combinations that I just don't remember. Here's a quick list for next time I'm hunting:






CommandKeys
I Use
Keys
Others Use
Edit-Intellisense-ResolveAlt-Shift-F10Ctrl-+
Right Click-Go to DefinitionShift-F2F12

Tuesday, April 5, 2011

Getting Novell SSL VPN working on Windows 7

I use the Novell Access Manager SSL VPN to connect to one of my customer's networks. It is a browser-based VPN client which means that you have to login via the browser and then keep the browser window open to maintain the VPN connection.

According to the documentation it will work with both Windows and Mac, and with IE, Firefox and Safari. Well it doesn't for me! Initially the only combination I could get working was IE under Windows XP. With a bit of fiddling I've finally managed to get it working for Windows 7. I write these notes for when I need to set this up again!

Attempting to launch the VPN client from IE on Windows 7 initially gives this error message:

AM.1804 : Connection to service failed.


Consulting the Novell Access Manager SSL VPN manual says that you should watch the <Users> folder. If you are quick enough, you'll see these files appear:


novl-sslvpn-service-install.exe
cacert.pem
openvpnclient.msi
PrivilegeDetector.exe
vplogin.dll


...along with a few log files. You do have to be quick though because they are deleted almost immediately.

The manual instructs you to shutdown your browser, run the novl-sslvpn-service-install.exe EXE manually and then start the browser and all should be working.

Instead, I took a simpler (and probably far less secure) route. I removed the User Account Access Control restrictions. I changed them from "Notify me when programs try to make changes to my computer" to "Never notify me". This can be done via Control Panel-User Accounts-Change User Account Control Settings

User Account Control Settings

Change from Default to "Never Notify" and click OK. After confirming this change you will be prompted to restart your computer. Once it has restarted, the SSL VPN should work! Note that it does take a while to connect and you'll have to confirm to install some insecure driver software, but it works.

Monday, March 21, 2011

Using log4net with shared DLLs


I've got a C# DLL that is used from a number of different places, including .Net EXEs, VB6 EXEs, Work and Outlook COMAddIns and also Outlook forms. It uses log4net for tracing and debugging.

I'd found log4net to be pretty reliable BUT sometimes messages weren't ending up in my log file (usually when I really needed them!). Most recently this happened today when I was trying to trace a problem in my Outlook form. I'd drag the appointment in Outlook which would fire the Item Write event on the form and, although I could loo kin the DB and see that my DLL was working, nothing was showing up in the log4net log file.



How to Investigate the Problem


To find out what was really happening, I used log4net's internal debugging. In the case of an Outlook Form, I switched it on like this:




  1. Started Outlook

  2. Started Visual Studio and opened my DLL project

  3. Switched on log4net internal debugging by modifying my log4net configuration file and changed the <log4net> to read <log4net debug="true">

  4. Used "Tools-Attach to Process" and attached to the Outlook.exe process

  5. Placed a breakpoint in the project on a line that I knew it should encounter

  6. Ran the test again...



The Problem


When I ran the test again with log4net debugging switched on, I could clearly see that log4net was unable to write to my logfile because it was locked. I didn't obviously have it locked (I had it open in TextPad but closing that didn't fix the problem). A quick scout around revealed that log4net with the RollingFileAppender by default will lock the file and keep it locked. Clearly this was the problem in my case where multiple programs all use my DLL which writes to the same logfile.



The Solution


I do want all of the instances of my DLL to write to the same log file, but I don't want them to lock the file and keep each other out. The solution was to add the following to the appender section of my log4net configuration file:




<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />



This instructs log4net to get the lock, write and release the lock every time - so it doesn't keep the file locked. With this in place, all of my DLL instances now write to the logfile, ALL of the time! There is a slight performance overhead to this approach, but then I'd rather than it works slowly, than not working quickly!

Tuesday, July 27, 2010

ORA-06508 error calling package in different schema


I had a PL/SQL package (let's call it PACKAGE_A) in schema SCHEMA_A which called a procedure in PACKAGE_B in SCHEMA_B. When I added a new parameter to the procedure in PACKAGE_B, I got some very strange errors showing up in PACKAGE_A. After trying all combinations of compiling PACKAGE_A and PACKAGE_B and REVOKEing and GRANTing EXECUTE rights to PACKAGE_B, I was consistently coming up with this Oracle error when I ran PACKAGE_A:



ORA-06508: PL/SQL: could not find program unit being called


Note that PACKAGE_A would compile fine, it just wouldn't run. I finally managed to get rid of this error by logging off my PL/SQL session in SCHEMA_A and then logging back in. After that, my PACKAGE_A call worked fine. "When in doubt, reboot!" A pretty old-school solution but it was the answer in this case!



NB. Oracle Version 10g Enterprise Edition 10.2.0.2.0

Monday, February 22, 2010

"The form required to view this message cannot be displayed" error accessing Organizational Forms Library in Outlook 2003


I had a VB6 program running on a server using Outlook 2003 client to create appointments. The appointments used a custom Outlook form stored in the Organizational Forms Library. Suddenly the program started spitting out this error:



"The form required to view this message cannot be display. Contact your administrator."



If I used the Outlook Client (on the server) to try to design the form via Tools-Forms-Design Form-Organizational Forms Library-{shift}+Open then I got the following error message:



"The form you selected cannot be displayed. The form required to view this message cannot be display. Contact your administrator."



The solution was to clear the Outlook Forms cache. This can be done via:





  1. Click on the "Tools" menu

  2. Click on "Options"

  3. Click on the "Other" tab

  4. Click the "Advanced Options" button

  5. Click the "Custom Forms" button

  6. Click the "Manage Forms" button

  7. Click the "Clear Cache" button

  8. Close and OK through all Outlook Property/Option windows




Credit for these steps from http://www.experts-exchange.com/Software/Server_Software/Email_Servers/Exchange/Q_24342937.html

Wednesday, February 17, 2010

Compile All Invalid Oracle objects

If you add a column to a table that invalidates lots of packages, triggers, views etc then you'll need to compile all of these invalidated objects. And each of these objects might in turn invalidate more - so this can take a few cycles.





I use the SQL statement below to generate the COMPILE statements for all invalid objects. I then copy and paste the COMPILE statements into a SQL session and run them (compiling them). Then I run the code below again (and compile again...etc) until no more are found.


SELECT 'ALTER '
||decode(object_type,'PACKAGE BODY','PACKAGE', object_type)
||' '||object_name||' COMPILE'
||decode(object_type,'PACKAGE BODY',' BODY', '')||';'
FROM user_objects
WHERE status = 'INVALID'
AND object_type <> 'SYNONYM'


The output from this (which I paste into a SQL window to run) will be something like:


ALTER TRIGGER CUST_AUI COMPILE;
ALTER PACKAGE CUST_PKG COMPILE;
ALTER PACKAGE CUST_PKG COMPILE BODY;
ALTER VIEW CUST_VW COMPILE;
ALTER PACKAGE CUST_AUDIT_PKG COMPILE BODY;

Monday, October 5, 2009

Adding HTTP Authentication for a user in Subversion

If you've already got your HTTP Authentication setup (instructions for that can be found here) then you can add a new user (eg. xyz) like this:


$htpasswd2 -m /etc/svn-auth-file xyz


Note that for Apache 2, you use the htpasswd2 command, NOT htpasswd.

Monday, May 4, 2009

Solution to the ORABEL-08021 "partnerlink not found" problem!

I was seeing an ORABPEL-08021 error when calling a Oracle BPEL web service via C# in .Net. Specifically, the error returned was:


<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header/>
<env:Body>
<env:Fault xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<faultcode xmlns="">env:Server</faultcode>
<faultstring xmlns="">ORABPEL-08021 Cannot find partner wsdl. parnterLink "MyService" is not found in process "MyService" (revision "1.0") Please check the deployment descriptor of the process to find the correct partnerLink name.
</faultstring>
<faultactor xmlns=""></faultactor>
</env:Fault>
</env:Body>
</env:Envelope>


The problem was that I was using the wrong URI to access the service. I was using:

http://myserver:8888/orabpel/default/MyService/1.0/MyService

and I should have been using:

http://myserver:8888/orabpel/default/MyService/1.0

So, my own silly fault really! Normally I can take the WSDL address (eg. http://myserver:8888/orabpel/default/MyService/1.0/MyService?wsdl) and just drop the "?wsdl" off the end to get the service endpoint. Not with these Oracle BPEL services though. If I had bothered to read the WSDL, I would have seen that the endpoint address is clearly specified. One more thing to note: with an Oracle BPEL service, you can also drop the version number off the end and it will still work, calling the latest version by default. eg:

http://myserver:8888/orabpel/default/MyService

Wednesday, March 25, 2009

Where should I put my .Net DLL for COM Interop?

I have a .Net DLL which I want to use from VB6 via COM interop. Where should I put it when I deploy it? (look here to see how to make a .Net DLL useable via VB6)



The key thing is that in order to use your .Net dll from VB6 you do need to register the .Net DLL. You don't need to to do anything special in the VB6 program - it doesn't matter how you reference the .Net DLL in your VB6 program. The command to register a .Net DLL is "regasm". This lives under "C:\Windows\Microsoft.Net\Framework\v2.0.50727" (or whatever .Net framework version you have).



There are three options for where to put your .Net DLL:



1. Put it in the GAC. If you want to share the same .Net DLL with more than one VB6 program then you can put it in the GAC (Global Assembly Cache). To do this, you can use an MSI file, or manually, you can copy it to c:\windows\assembly, and then register it via "regasm c:\winnt\assembly\mydotnet.dll".



2. Put it in the EXE folder. If you want the .Net DLL to live in the same place as your VB6 EXE then you can copy it to that folder, and then use "regasm c:\vb6\exe\folder\mydotnet.dll". Note that the .Net DLL has to be in the same folder as the VB6 EXE. So if you have VB6 EXE calling a VB6 DLL which calls your .Net dll then it must go in the EXEs folder - it won't find it in VB6 DLLs folder.



3. Put it in any folder via codebase. If you want the .Net DLL to live anywhere else, you can use use "regasm c:\program files\vanwills\mydotnet.dll /codebase". This will register the .Net DLL to the path you provide. This is a bit like the old VB6 regsvr32 command. So using this we can have the .Net DLL sitting in the "c:\vb6\dll\folder" folder.



The only other point to note is that .Net will always check the GAC first before other locations. So if we have a .Net DLL in the GAC, then even if we register the same DLL somewhere else via the "/codebase" option, it will always use the GAC DLL. You can get around this by changing the version number on the DLL - it will always load the version with the highest number first.


Thursday, November 6, 2008

How to switch on log4net internal logging

If you want log4net to show its own internal logging, which is useful to find out where it is looking for your XML configuration file, you can add the following XML to your app.config file:

<configuration>
<appSettings>
<add key="log4net.Internal.Debug" value="true"/>
</appSettings>
</configuration>

Note that if you are using log4net in a DLL, this goes into the app.config file for the EXE that is calling your DLL.

Monday, November 3, 2008

Log4Net using a named config file

Setting up Log4Net with your configuration in the app.config file is pretty straight-forward to do - a quick Google will lead to a number of posts on how to do this.

But if you decide to move your log4net config settings to an external file (convention seems to be "log4net.config") then there are a few misconceptions floating around. There are only two further steps you need to take to achieve this:

1. Copy the <log4net> ... </log4net> section out of your app.config and save it into a new file called log4net.config. You should totally remove it from the app.config file once you feel confident - it is no longer needed.

2. Modify your AssembyInfo.cs file by removing this:

[assembly: log4net.Config.XmlConfigurator
(Watch = true)]


and replacing it with this:

[assembly: log4net.Config.XmlConfigurator
(ConfigFile = "log4net.config", Watch = true)]


Now if you fire up the IDE and run it, your logging should still work. If you don't see any logging, then check that the log4net.config is in the current application path - if you are running from the IDE then that will be where the EXE lives at "../MyProject/bin/Debug/". If you've placed the log4net.config file in your project home folder then you can get it working through the IDE with this:

[assembly: log4net.Config.XmlConfigurator
(ConfigFile = "../../log4net.config", Watch = true)]


Note that this will need to be reviewed come deployment time!

OR, even better, just select the config file in the IDE and, in the Properties window, change the "Copy to Output Directory" value to "Copy always". Now when you build it through the IDE it will follow your compiled file around. Nice!

Note that you do NOT need to add log4net.Config.XmlConfigurator.Configure() or log4net.Config.XmlConfigurator.Configure({file name}) to the code in your project! This does a manual configuration which overrides what is in the AssemblyInfo.cs file. If you get the AssemblyInfo.cs parameters right then that is all you need.