To register for an Internet.com membership to receive newsletters and white papers, use the Register button ABOVE.
To participate in the message forums BELOW, click here
VBForums  

VB Wire News
Sell Your Code and Make Money?
Creating your own Tetris game using VB.NET
Article :: Improving Software Economics, Part 4 of 7: Top 10 Principles of Iterative Software Management
Building Composable Apps in .NET 4 with the Managed Extensibility Framework
CLR Inside Out: Formatting and Parsing Time Intervals in the .NET Framework 4



Go Back   VBForums > Visual Basic > Visual Basic .NET

Reply Post New Thread
 
Thread Tools Search this Thread Display Modes
Old Dec 2nd, 2006, 01:23 AM   #1
agent
Fanatic Member
 
Join Date: Jun 99
Location: California, USA
Posts: 659
agent is on a distinguished road (10+)
Resolved [RESOLVED] [2005] PInvoke on a function declared with __declspec

I'm getting this exception when I try to get the address of a function in a dll written in vc++ 6.0. The dll is a compiled winamp plugin and I can't change the plugin source.

Code:
System.Runtime.InteropServices.MarshalDirectiveException was unhandled
  Message="Method's type signature is not PInvoke compatible."
  Source="Winamp Plugin Host"
  StackTrace:
       at Winamp_Plugin_Host.OutputPlugin.GetProcAddress(Int32 hModule, String& lpProcName)
       at Winamp_Plugin_Host.OutputPlugin..ctor(String FromFile) in C:\Documents and Settings\Jack Schitt\Desktop\design\programming\Winamp Plugin Host\PluginClasses.vb:line 76
Is there any way in vb.net 2005 to call a function declared as:

Code:
__declspec( dllexport ) Out_Module * winampGetOutModule()
...hopefully using LoadLibraryEX, GetProcAddress, and FreeLibrary...
agent is offline   Reply With Quote
Old Dec 2nd, 2006, 02:03 AM   #2
penagate
Super Moderator
 
Join Date: Jan 05
Location: Sunny Adelaide
Posts: 12,532
penagate has much to be proud of (1500+)penagate has much to be proud of (1500+)penagate has much to be proud of (1500+)penagate has much to be proud of (1500+)penagate has much to be proud of (1500+)penagate has much to be proud of (1500+)penagate has much to be proud of (1500+)penagate has much to be proud of (1500+)penagate has much to be proud of (1500+)penagate has much to be proud of (1500+)penagate has much to be proud of (1500+)
Re: [2005] PInvoke on a function declared with __declspec

VB Code:
  1. <DllImport("dll_name", CallingConvention:=CallingConvention.Cdecl)> _
  2. Private Function WinampGetOutModule() As [...]
  3. End Function
penagate is offline   Reply With Quote
Old Dec 2nd, 2006, 03:09 AM   #3
agent
Fanatic Member
 
Join Date: Jun 99
Location: California, USA
Posts: 659
agent is on a distinguished road (10+)
Re: [2005] PInvoke on a function declared with __declspec

Quote:
Originally Posted by penagate
VB Code:
  1. <DllImport("dll_name", CallingConvention:=CallingConvention.Cdecl)> _
  2. Private Function WinampGetOutModule() As [...]
  3. End Function
I was using the LoadLibrary, GetProcAddress, and FreeLibrary functions before as they allow me to dynamically specify the dll. (The dll to load varies and there are multiple dlls to load).

Can this be done with either DllImport or Declare?
agent is offline   Reply With Quote
Old Dec 2nd, 2006, 03:11 AM   #4
penagate
Super Moderator
 
Join Date: Jan 05
Location: Sunny Adelaide
Posts: 12,532
penagate has much to be proud of (1500+)penagate has much to be proud of (1500+)penagate has much to be proud of (1500+)penagate has much to be proud of (1500+)penagate has much to be proud of (1500+)penagate has much to be proud of (1500+)penagate has much to be proud of (1500+)penagate has much to be proud of (1500+)penagate has much to be proud of (1500+)penagate has much to be proud of (1500+)penagate has much to be proud of (1500+)
Re: [2005] PInvoke on a function declared with __declspec

Dynamic DLLImport

Hope you can convert C# to VB.
penagate is offline   Reply With Quote
Old Dec 2nd, 2006, 03:29 AM   #5
agent
Fanatic Member
 
Join Date: Jun 99
Location: California, USA
Posts: 659
agent is on a distinguished road (10+)
Re: [2005] PInvoke on a function declared with __declspec

Quote:
Originally Posted by penagate
Dynamic DLLImport

Hope you can convert C# to VB.

It looks a little complicated for what I'm trying to do and seems to apply to .Net 1.x.

I'm including the unfinished class I'm working on. If you have winamp, create a new instance of the class and provide the full path to any dll file in the plugins folder of winamp who's filename begins with "OUT".

The test in this case would be to run the About method of the class and see if you get an 'About This Plugin...' type window. I haven't been able to test any of the delegates in the OutModule structure as the problem I'm having occures before this is returned.

You can get winamp free at winamp.com. The sdk is available free at http://www.winamp.com/nsdn/winamp/sdk/index.php

VB Code:
  1. Public Class OutputPlugin
  2.     Implements IDisposable
  3.     Private Declare Function LoadLibraryEx Lib "kernel32.dll" Alias "LoadLibraryExA" (ByVal lpLibFileName As String, ByVal hFile As Int32, ByVal dwFlags As Int32) As Int32
  4.     Private Declare Function FreeLibrary Lib "kernel32.dll" (ByVal hLibModule As Integer) As Integer
  5.     Private Declare Function GetProcAddress Lib "kernel32.dll" (ByVal hModule As Integer, ByVal lpProcName As String) As ptrwinampGetOutModule
  6.     Private Const LOAD_WITH_ALTERED_SEARCH_PATH As Int32 = &H8
  7.     'Main delegate. The declare above for GetProcAddress returns this type
  8.     Private Delegate Function ptrwinampGetOutModule() As OutModule
  9.     Private _Lib As Integer 'holds HMODULE for dll file
  10.     Private _OutModule As OutModule 'holds the plugin info
  11.     Sub New(ByVal FromFile As String)
  12.         MyBase.New()
  13.         'load the library. FreeLibrary is called in Dispose
  14.         _Lib = LoadLibraryEx(FromFile, 0, LOAD_WITH_ALTERED_SEARCH_PATH)
  15.         'Get the address for function winampGetOutModule...
  16.         Dim tmp As ptrwinampGetOutModule = GetProcAddress(_Lib, "winampGetOutModule")
  17.         '...and call it
  18.         _OutModule = tmp.Invoke
  19.     End Sub
  20. #Region " IDisposable Support "
  21.     Private disposedValue As Boolean = False        ' To detect redundant calls
  22.     ' IDisposable
  23.     Protected Overridable Sub Dispose(ByVal disposing As Boolean)
  24.         If Not Me.disposedValue Then
  25.             If disposing Then
  26.                 ' TODO: free unmanaged resources when explicitly called
  27.             End If
  28.             ' TODO: free shared unmanaged resources
  29.             FreeLibrary(_Lib)
  30.         End If
  31.         Me.disposedValue = True
  32.     End Sub
  33.     ' This code added by Visual Basic to correctly implement the disposable pattern.
  34.     Public Sub Dispose() Implements IDisposable.Dispose
  35.         ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
  36.         Dispose(True)
  37.         GC.SuppressFinalize(Me)
  38.     End Sub
  39. #End Region
  40. #Region "OutModule Structure"
  41.     '"Slightly" modified def of the structure. See OUT.H in the sdk for the original version
  42.     <StructLayout(LayoutKind.Sequential)> _
  43.     Public Structure OutModule
  44.         Public version As Integer               '// module version (OUT_VER)
  45.         Public description As String            '// description of module, with version string
  46.         Public id As Integer                    '// module id. each input module gets its own. non-nullsoft modules should
  47.         '// be >= 65536.
  48.         Public hMainWindow As Integer           '// winamp's main window (filled in by winamp)
  49.         Public hDllInstance As Integer         '// DLL instance handle (filled in by winamp)
  50.         Public Delegate Sub ptrConfig(ByVal hwndParent As Integer)
  51.         <MarshalAs(UnmanagedType.FunctionPtr)> _
  52.         Public Config As ptrConfig '(HWND hwndParent); '// configuration dialog
  53.         Public Delegate Sub ptrAbout(ByVal hwndParent As Integer)
  54.         <MarshalAs(UnmanagedType.FunctionPtr)> _
  55.         Public About As ptrAbout '(HWND hwndParent);  '// about dialog
  56.         Public Delegate Sub ptrInit()
  57.         <MarshalAs(UnmanagedType.FunctionPtr)> _
  58.         Public Init As ptrInit '();    '// called when loaded
  59.         Public Delegate Sub ptrQuit()
  60.         <MarshalAs(UnmanagedType.FunctionPtr)> _
  61.         Public Quit As ptrQuit '();    '// called when unloaded
  62.         Public Delegate Function ptrOpen(ByVal SampleRate As Integer, ByVal NumChannels As Integer, ByVal BitsPerSamp As Integer, ByVal BufferLenMS As Integer, ByVal PreBufferMS As Integer) As Integer
  63.         <MarshalAs(UnmanagedType.FunctionPtr)> _
  64.         Public Open As ptrOpen '(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms);
  65.         '// returns >=0 on success, <0 on failure
  66.         '// NOTENOTENOTE: bufferlenms and prebufferms are ignored in most if not all output plug-ins.
  67.         '//    ... so don't expect the max latency returned to be what you asked for.
  68.         '// returns max latency in ms (0 for diskwriters, etc)
  69.         '// bufferlenms and prebufferms must be in ms. 0 to use defaults.
  70.         '// prebufferms must be <= bufferlenms
  71.         Public Delegate Sub ptrClose()
  72.         <MarshalAs(UnmanagedType.FunctionPtr)> _
  73.         Public Close As ptrClose '();   '// close the ol' output device.
  74.         Public Delegate Function ptrWrite(ByRef buf As Byte(), ByVal len As Integer) As Integer
  75.         <MarshalAs(UnmanagedType.FunctionPtr)> _
  76.         Public Write As ptrWrite '(char *buf, int len); 
  77.         '// 0 on success. Len == bytes to write (<= 8192 always). buf is straight audio data.
  78.         '// 1 returns not able to write (yet). Non-blocking, always.
  79.         Public Delegate Function ptrCanWrite() As Integer
  80.         <MarshalAs(UnmanagedType.FunctionPtr)> _
  81.         Public CanWrite As ptrCanWrite '(); '// returns number of bytes possible to write at a given time.
  82.         '// Never will decrease unless you call Write (or Close, heh)
  83.         Public Delegate Function ptrIsPlaying() As Integer
  84.         <MarshalAs(UnmanagedType.FunctionPtr)> _
  85.         Public IsPlaying As ptrIsPlaying '(); '// non0 if output is still going or if data in buffers waiting to be
  86.         '// written (i.e. closing while IsPlaying() returns 1 would truncate the song
  87.         Public Delegate Function ptrPause(ByVal Pause As Integer) As Integer
  88.         <MarshalAs(UnmanagedType.FunctionPtr)> _
  89.         Public Pause As ptrPause '(int pause); '// returns previous pause state
  90.         Public Delegate Sub ptrSetVolume(ByVal volume As Integer)
  91.         <MarshalAs(UnmanagedType.FunctionPtr)> _
  92.         Public SetVolume As ptrSetVolume '(int volume); '// volume is 0-255
  93.         Public Delegate Sub ptrSetPan(ByVal pan As Integer)
  94.         <MarshalAs(UnmanagedType.FunctionPtr)> _
  95.         Public SetPan As ptrSetPan '(int pan); '// pan is -128 to 128
  96.         Public Delegate Sub ptrFlush(ByVal t As Integer)
  97.         <MarshalAs(UnmanagedType.FunctionPtr)> _
  98.         Public Flush As ptrFlush '(int t);  '// flushes buffers and restarts output at time t (in ms)
  99.         '// (used for seeking)
  100.         Public Delegate Function ptrGetOutputTime() As Integer
  101.         <MarshalAs(UnmanagedType.FunctionPtr)> _
  102.         Public GetOutputTime As ptrGetOutputTime '(); '// returns played time in MS
  103.         Public Delegate Function ptrGetWrittenTime() As Integer
  104.         <MarshalAs(UnmanagedType.FunctionPtr)> _
  105.         Public GetWrittenTime As ptrGetWrittenTime '(); '// returns time written in MS (used for synching up vis stuff)
  106.     End Structure
  107. #End Region
  108. #Region "Methods"
  109.     'these call the pointers to the various functions of the plugin.
  110.     'Note: this section is not yet complete
  111.     'Plugin loads settings, etc.
  112.     Public Sub Init()
  113.         _OutModule.Init()
  114.     End Sub
  115.     'Plugin saves settings, closes devices
  116.     Public Sub Quit()
  117.         _OutModule.Quit()
  118.     End Sub
  119.     'Show the about window
  120.     Public Sub About(ByVal Owner As Form)
  121.         _OutModule.About(Owner.Handle)
  122.     End Sub
  123.     'Show the config window
  124.     Public Sub Config(ByVal Owner As Form)
  125.         _OutModule.Config(Owner.Handle)
  126.     End Sub
  127. #End Region
  128. End Class
agent is offline   Reply With Quote
Old Dec 2nd, 2006, 06:19 PM   #6
agent
Fanatic Member
 
Join Date: Jun 99
Location: California, USA
Posts: 659
agent is on a distinguished road (10+)
Re: [2005] PInvoke on a function declared with __declspec

Not for the faint at heart...

I took my previous code and added a dynamic binder as suggested by penagate. Everything, including the dynamic binding works un until the point where it calls the function in the dll. Then I get the same exception (signature not PInvoke compatible).

This is the entire contents of the plugin file... (The exception occurs on the bolded line near the bottom)
The second code section is the function template I'm using. This file should have its build action set to none. Additionally, add it as a resource via the resource manager. The resource should be named 'Template'

WinampPluginClasses.vb
VB Code:
  1. Imports System.Runtime.InteropServices
  2. Imports System.CodeDom
  3. Public Class OutputPlugin
  4.     'function name = winampGetOutModule
  5.     'Main delegate. The declare above for GetProcAddress returns this type
  6.     Private Delegate Function ptrwinampGetOutModule() As OutModule
  7.     Private _OutModule As OutModule 'holds the plugin info
  8.     Sub New(ByVal FromFile As String)
  9.         MyBase.New()
  10.         _OutModule = DynamicBinding(Of OutModule).CallFunction(FromFile, "winampGetOutModule")
  11.     End Sub
  12. #Region "Methods"
  13.     'these call the pointers to the various functions of the plugin.
  14.     'Note: this section is not yet complete
  15.     'Plugin loads settings, etc.
  16.     Public Sub Init()
  17.         _OutModule.Init()
  18.     End Sub
  19.     'Plugin saves settings, closes devices
  20.     Public Sub Quit()
  21.         _OutModule.Quit()
  22.     End Sub
  23.     'Show the about window
  24.     Public Sub About(ByVal Owner As Form)
  25.         _OutModule.About(Owner.Handle)
  26.     End Sub
  27.     'Show the config window
  28.     Public Sub Config(ByVal Owner As Form)
  29.         _OutModule.Config(Owner.Handle)
  30.     End Sub
  31. #End Region
  32. End Class
  33. #Region "OutModule Structure"
  34. '"Slightly" modified def of the structure. See OUT.H in the sdk for the original version
  35. <StructLayout(LayoutKind.Sequential)> _
  36. Public Structure OutModule
  37.     Public version As Integer               '// module version (OUT_VER)
  38.     Public description As String            '// description of module, with version string
  39.     Public id As Integer                    '// module id. each input module gets its own. non-nullsoft modules should
  40.     '// be >= 65536.
  41.     Public hMainWindow As Integer           '// winamp's main window (filled in by winamp)
  42.     Public hDllInstance As Integer         '// DLL instance handle (filled in by winamp)
  43.     Public Delegate Sub ptrConfig(ByVal hwndParent As Integer)
  44.     <MarshalAs(UnmanagedType.FunctionPtr)> _
  45.     Public Config As ptrConfig '(HWND hwndParent); '// configuration dialog
  46.     Public Delegate Sub ptrAbout(ByVal hwndParent As Integer)
  47.     <MarshalAs(UnmanagedType.FunctionPtr)> _
  48.     Public About As ptrAbout '(HWND hwndParent);  '// about dialog
  49.     Public Delegate Sub ptrInit()
  50.     <MarshalAs(UnmanagedType.FunctionPtr)> _
  51.     Public Init As ptrInit '();    '// called when loaded
  52.     Public Delegate Sub ptrQuit()
  53.     <MarshalAs(UnmanagedType.FunctionPtr)> _
  54.     Public Quit As ptrQuit '();    '// called when unloaded
  55.     Public Delegate Function ptrOpen(ByVal SampleRate As Integer, ByVal NumChannels As Integer, ByVal BitsPerSamp As Integer, ByVal BufferLenMS As Integer, ByVal PreBufferMS As Integer) As Integer
  56.     <MarshalAs(UnmanagedType.FunctionPtr)> _
  57.     Public Open As ptrOpen '(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms);
  58.     '// returns >=0 on success, <0 on failure
  59.     '// NOTENOTENOTE: bufferlenms and prebufferms are ignored in most if not all output plug-ins.
  60.     '//    ... so don't expect the max latency returned to be what you asked for.
  61.     '// returns max latency in ms (0 for diskwriters, etc)
  62.     '// bufferlenms and prebufferms must be in ms. 0 to use defaults.
  63.     '// prebufferms must be <= bufferlenms
  64.     Public Delegate Sub ptrClose()
  65.     <MarshalAs(UnmanagedType.FunctionPtr)> _
  66.     Public Close As ptrClose '();   '// close the ol' output device.
  67.     Public Delegate Function ptrWrite(ByRef buf As Byte(), ByVal len As Integer) As Integer
  68.     <MarshalAs(UnmanagedType.FunctionPtr)> _
  69.     Public Write As ptrWrite '(char *buf, int len); 
  70.     '// 0 on success. Len == bytes to write (<= 8192 always). buf is straight audio data.
  71.     '// 1 returns not able to write (yet). Non-blocking, always.
  72.     Public Delegate Function ptrCanWrite() As Integer
  73.     <MarshalAs(UnmanagedType.FunctionPtr)> _
  74.     Public CanWrite As ptrCanWrite '(); '// returns number of bytes possible to write at a given time.
  75.     '// Never will decrease unless you call Write (or Close, heh)
  76.     Public Delegate Function ptrIsPlaying() As Integer
  77.     <MarshalAs(UnmanagedType.FunctionPtr)> _
  78.     Public IsPlaying As ptrIsPlaying '(); '// non0 if output is still going or if data in buffers waiting to be
  79.     '// written (i.e. closing while IsPlaying() returns 1 would truncate the song
  80.     Public Delegate Function ptrPause(ByVal Pause As Integer) As Integer
  81.     <MarshalAs(UnmanagedType.FunctionPtr)> _
  82.     Public Pause As ptrPause '(int pause); '// returns previous pause state
  83.     Public Delegate Sub ptrSetVolume(ByVal volume As Integer)
  84.     <MarshalAs(UnmanagedType.FunctionPtr)> _
  85.     Public SetVolume As ptrSetVolume '(int volume); '// volume is 0-255
  86.     Public Delegate Sub ptrSetPan(ByVal pan As Integer)
  87.     <MarshalAs(UnmanagedType.FunctionPtr)> _
  88.     Public SetPan As ptrSetPan '(int pan); '// pan is -128 to 128
  89.     Public Delegate Sub ptrFlush(ByVal t As Integer)
  90.     <MarshalAs(UnmanagedType.FunctionPtr)> _
  91.     Public Flush As ptrFlush '(int t);  '// flushes buffers and restarts output at time t (in ms)
  92.     '// (used for seeking)
  93.     Public Delegate Function ptrGetOutputTime() As Integer
  94.     <MarshalAs(UnmanagedType.FunctionPtr)> _
  95.     Public GetOutputTime As ptrGetOutputTime '(); '// returns played time in MS
  96.     Public Delegate Function ptrGetWrittenTime() As Integer
  97.     <MarshalAs(UnmanagedType.FunctionPtr)> _
  98.     Public GetWrittenTime As ptrGetWrittenTime '(); '// returns time written in MS (used for synching up vis stuff)
  99. End Structure
  100. #End Region
  101. Friend Class DynamicBinding(Of ReturnStructure As Structure)
  102.     'replacements in template
  103.     Private Const DLLName As String = "DLLName"
  104.     Private Const [Structure] As String = "Integer"
  105.     Private Const FunctionName As String = "FunctionName"
  106.     'name of module
  107.     Private Const ClassName As String = "CallDll"
  108.     Public Shared Function CallFunction(ByVal DLL As String, ByVal Funct As String) As ReturnStructure
  109.         'Code is loaded from a resource. see Template.VB
  110.         Dim TemplateCode As String = My.Resources.Template
  111.         'Replace parts of the code with the constants above
  112.         TemplateCode = Replace(TemplateCode, DLLName, DLL)
  113.         TemplateCode = Replace(TemplateCode, FunctionName, Funct)
  114.         TemplateCode = Replace(TemplateCode, [Structure], GetType(ReturnStructure).FullName)
  115.         'Compile the code
  116.         Dim CompileUnit As New CodeSnippetCompileUnit(TemplateCode)
  117.         Dim TemplateCodeArray As String() = {TemplateCode}
  118.         Dim Params As New Compiler.CompilerParameters()
  119.         With Params
  120.             .GenerateExecutable = False
  121.             .GenerateInMemory = True
  122.             .IncludeDebugInformation = False
  123.             .ReferencedAssemblies.Add(Application.ExecutablePath)
  124.         End With
  125.         Dim CodeProvider As New Microsoft.VisualBasic.VBCodeProvider()
  126.         'this is the line that compiles it
  127.         Dim CompilerResaults As Compiler.CompilerResults = CodeProvider.CompileAssemblyFromSource(Params, TemplateCodeArray)
  128.         'if there are errors, let me see what they are
  129.         If CompilerResaults.Errors.Count > 0 Then
  130.             Dim ce As Object = CompilerResaults.Errors
  131.             Dim item As Object
  132.             For Each item In ce
  133.                 'cheap and simple way of debugging compiler errors:
  134.                 'hover the mouse over 'item' in the code window while stopped
  135.                 'it will tell you what error occured.
  136.                 Stop
  137.             Next
  138.         End If
  139.         'now it should be compiled, use relfection to call the code
  140.         Dim Assembly As System.Reflection.Assembly = CompilerResaults.CompiledAssembly
  141.         Dim [class] As System.Type = Assembly.GetType(ClassName)
  142.         Dim method As Reflection.MethodInfo = [class].GetMethod(Funct, Reflection.BindingFlags.Static Or Reflection.BindingFlags.Public Or Reflection.BindingFlags.FlattenHierarchy)
  143.         [b]Return DirectCast(method.Invoke(Nothing, Nothing), ReturnStructure)[/b]
  144.     End Function
  145. End Class

Template.vb
VB Code:
  1. Public Class CallDll
  2.     <System.Runtime.InteropServices.DllImport("DLLName", CallingConvention:=System.Runtime.InteropServices.CallingConvention.StdCall)> _
  3.     Public Shared Function FunctionName() As Integer
  4.     End Function
  5. End Class
agent is offline   Reply With Quote
Old Dec 2nd, 2006, 11:01 PM   #7
agent
Fanatic Member
 
Join Date: Jun 99
Location: California, USA
Posts: 659
agent is on a distinguished road (10+)
Re: [2005] PInvoke on a function declared with __declspec

Looks like I got it working. I'll post the working code after optimizing it a bit. I knew dynamically compiling code was a little overkill. I'm switching it back to LoadLibrary, GetProcAddress, and FreeLibrary.

The problem was that (apparently) you can't PInvoke something if the return value isn't something standard (i.e. a number or a boolean.)

Now, I simply take the number returned and use that as the first param of Marshal.PtrToStructure

Now the test works properly and it looks like I don't need to compile code from my program.

(If you found this post by doing a search for compiling code or executing scripts from your app, the above source code does do that, btw)
agent is offline   Reply With Quote
Reply

Go Back   VBForums > Visual Basic > Visual Basic .NET


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -5. The time now is 02:29 AM.




To view more projects, click here

Acceptable Use Policy


The Network for Technology Professionals

Search:

About Internet.com

Legal Notices, Licensing, Permissions, Privacy Policy.
Advertise | Newsletters | E-mail Offers

Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.